feat: use list to display virtools encodings settings, instead of raw string.

- use list to show bmap encoding settings, instead of user input raw string. it will give a more obvisous interface.
	* add bmap encoding setting properties in ptrprop_resolver.
	* update ptrprop_resolver for more clear usage.
- following features has not been implemented yet.
	* default value for bmap encoding list.
	* the bridge function in ioport_shared module (filter empty item in result)
	* validate encoding list result when importing and exporting virtools file.
This commit is contained in:
yyc12345 2025-01-08 13:21:35 +08:00
parent f4d3e48be2
commit 0862ecd269
3 changed files with 207 additions and 18 deletions

View File

@ -19,7 +19,7 @@ class BBP_OT_rail_uv(bpy.types.Operator):
def execute(self, context):
# check material
mtl: bpy.types.Material = PROP_ptrprop_resolver.get_rail_uv_material()
mtl: bpy.types.Material = PROP_ptrprop_resolver.PtrPropResolver.get_rail_uv_material()
if mtl is None:
UTIL_functions.message_box(
("No specific material", ),
@ -34,7 +34,7 @@ class BBP_OT_rail_uv(bpy.types.Operator):
def draw(self, context):
layout: bpy.types.UILayout = self.layout
PROP_ptrprop_resolver.draw_rail_uv_material(layout)
PROP_ptrprop_resolver.PtrPropResolver.draw_rail_uv_material(layout)
#region Real Worker Functions

View File

@ -1,10 +1,24 @@
import bpy
from bpy.types import Context, Event
from . import UTIL_functions
## Intent
# Operator is not allowed to register Pointer Properties.
# The solution is register pointer properties in Scene and reference it when drawing operator window.
# This module contains all pointer properties used by other operators.
#region Blender Type Defines
class BBP_PG_bmap_encoding(bpy.types.PropertyGroup):
encoding: bpy.props.StringProperty(
name = "Encoding",
default = ""
) # type: ignore
class BBP_UL_bmap_encoding(bpy.types.UIList):
def draw_item(self, context, layout: bpy.types.UILayout, data, item: BBP_PG_bmap_encoding, icon, active_data, active_propname):
layout.prop(item, 'encoding', emboss = False, text = '', icon = 'FONT_DATA')
class BBP_PG_ptrprop_resolver(bpy.types.PropertyGroup):
rail_uv_material: bpy.props.PointerProperty(
name = "Material",
@ -24,28 +38,202 @@ class BBP_PG_ptrprop_resolver(bpy.types.PropertyGroup):
description = "The object exported"
) # type: ignore
ioport_encodings: bpy.props.CollectionProperty(
type = BBP_PG_bmap_encoding
) # type: ignore
active_ioport_encodings: bpy.props.IntProperty() # type: ignore
#endregion
def get_ptrprop_resolver() -> BBP_PG_ptrprop_resolver:
return bpy.context.scene.bbp_ptrprop_resolver
def get_rail_uv_material() -> bpy.types.Material:
return get_ptrprop_resolver().rail_uv_material
def draw_rail_uv_material(layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(), 'rail_uv_material')
def get_ioport_encodings() -> UTIL_functions.CollectionVisitor[BBP_PG_bmap_encoding]:
return UTIL_functions.CollectionVisitor(get_ptrprop_resolver().ioport_encodings)
def get_active_ioport_encoding() -> int:
return get_ptrprop_resolver().active_ioport_encodings
def set_active_ioport_encoding(val: int) -> None:
get_ptrprop_resolver().active_ioport_encodings = val
def get_export_collection() -> bpy.types.Collection:
return get_ptrprop_resolver().export_collection
def draw_export_collection(layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(), 'export_collection')
#region Blender Operator Defines for Encodings
def get_export_object() -> bpy.types.Object:
return get_ptrprop_resolver().export_object
def draw_export_object(layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(), 'export_object')
class BBP_OT_add_ioport_encodings(bpy.types.Operator):
"""Add item at the tail of encodings list used by BMap for Virtools file read and write."""
bl_idname = "bbp.add_ioport_encodings"
bl_label = "Add in Encodings List"
bl_options = {'UNDO'}
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
return True
def execute(self, context):
encodings = get_ioport_encodings()
encodings.add()
return {'FINISHED'}
class BBP_OT_rm_ioport_encodings(bpy.types.Operator):
"""Remove selected item in encodings list used by BMap for Virtools file read and write."""
bl_idname = "bbp.rm_ioport_encodings"
bl_label = "Remove from Encodings List"
bl_options = {'UNDO'}
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
return index >= 0 and index < len(encodings)
def execute(self, context):
encodings = get_ioport_encodings()
encodings.remove(get_active_ioport_encoding())
return {'FINISHED'}
class BBP_OT_up_ioport_encodings(bpy.types.Operator):
"""Move selected item up in encodings list used by BMap for Virtools file read and write."""
bl_idname = "bbp.up_ioport_encodings"
bl_label = "Move Up in Encodings List"
bl_options = {'UNDO'}
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
return index >= 1 and index < len(encodings)
def execute(self, context):
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
encodings.move(index, index - 1)
set_active_ioport_encoding(index - 1)
return {'FINISHED'}
class BBP_OT_down_ioport_encodings(bpy.types.Operator):
"""Move selected item down in encodings list used by BMap for Virtools file read and write."""
bl_idname = "bbp.down_ioport_encodings"
bl_label = "Move Down in Encodings List"
bl_options = {'UNDO'}
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
return index >= 0 and index < len(encodings) - 1
def execute(self, context):
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
encodings.move(index, index + 1)
set_active_ioport_encoding(index + 1)
return {'FINISHED'}
class BBP_OT_clear_ioport_encodings(bpy.types.Operator):
"""Clear the encodings list used by BMap for Virtools file read and write."""
bl_idname = "bbp.clear_ioport_encodings"
bl_label = "Clear Encodings List"
bl_options = {'UNDO'}
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
return True
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_confirm(self, event)
def execute(self, context):
encodings = get_ioport_encodings()
encodings.clear()
set_active_ioport_encoding(0)
return {'FINISHED'}
#endregion
class PtrPropResolver():
"""
All outside code should use this class static methods to fetch property data or draw property.
All function inside in this module should not be called directly.
"""
@staticmethod
def get_rail_uv_material() -> bpy.types.Material:
return get_ptrprop_resolver().rail_uv_material
@staticmethod
def draw_rail_uv_material(layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(), 'rail_uv_material')
@staticmethod
def get_export_collection() -> bpy.types.Collection:
return get_ptrprop_resolver().export_collection
@staticmethod
def draw_export_collection(layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(), 'export_collection')
@staticmethod
def get_export_object() -> bpy.types.Object:
return get_ptrprop_resolver().export_object
@staticmethod
def draw_export_object(layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(), 'export_object')
@staticmethod
def get_ioport_encodings() -> tuple[str, ...]:
encodings = get_ioport_encodings()
return tuple(i.encoding for i in encodings)
@staticmethod
def set_ioport_encodings(user_encodings: tuple[str, ...]) -> None:
encodings = get_ioport_encodings()
# clear and apply user encoding one by one
encodings.clear()
for user_encoding in user_encodings:
item = encodings.add()
item.encoding = user_encoding
@staticmethod
def draw_ioport_encodings(layout: bpy.types.UILayout) -> None:
target = get_ptrprop_resolver()
row = layout.row()
# draw main list
row.template_list(
"BBP_UL_bmap_encoding", "",
target, "ioport_encodings",
target, "active_ioport_encodings",
rows = 6, maxrows = 6,
sort_reverse = False, sort_lock = True # disable sort feature because the order od this encoding list is crucial
)
# draw sidebar
col = row.column(align=True)
col.operator(BBP_OT_add_ioport_encodings.bl_idname, icon='ADD', text='')
col.operator(BBP_OT_rm_ioport_encodings.bl_idname, icon='REMOVE', text='')
col.separator()
col.operator(BBP_OT_up_ioport_encodings.bl_idname, icon='TRIA_UP', text='')
col.operator(BBP_OT_down_ioport_encodings.bl_idname, icon='TRIA_DOWN', text='')
col.separator()
col.operator(BBP_OT_clear_ioport_encodings.bl_idname, icon='TRASH', text='')
def register() -> None:
bpy.utils.register_class(BBP_PG_bmap_encoding)
bpy.utils.register_class(BBP_UL_bmap_encoding)
bpy.utils.register_class(BBP_PG_ptrprop_resolver)
bpy.utils.register_class(BBP_OT_add_ioport_encodings)
bpy.utils.register_class(BBP_OT_rm_ioport_encodings)
bpy.utils.register_class(BBP_OT_up_ioport_encodings)
bpy.utils.register_class(BBP_OT_down_ioport_encodings)
bpy.utils.register_class(BBP_OT_clear_ioport_encodings)
bpy.types.Scene.bbp_ptrprop_resolver = bpy.props.PointerProperty(type = BBP_PG_ptrprop_resolver)
def unregister() -> None:
del bpy.types.Scene.bbp_ptrprop_resolver
bpy.utils.unregister_class(BBP_OT_clear_ioport_encodings)
bpy.utils.unregister_class(BBP_OT_down_ioport_encodings)
bpy.utils.unregister_class(BBP_OT_up_ioport_encodings)
bpy.utils.unregister_class(BBP_OT_rm_ioport_encodings)
bpy.utils.unregister_class(BBP_OT_add_ioport_encodings)
bpy.utils.unregister_class(BBP_PG_ptrprop_resolver)
bpy.utils.unregister_class(BBP_UL_bmap_encoding)
bpy.utils.unregister_class(BBP_PG_bmap_encoding)

View File

@ -256,21 +256,21 @@ class ExportParams():
# draw picker
if self.export_mode == 'COLLECTION':
PROP_ptrprop_resolver.draw_export_collection(body)
PROP_ptrprop_resolver.PtrPropResolver.draw_export_collection(body)
elif self.export_mode == 'OBJECT':
PROP_ptrprop_resolver.draw_export_object(body)
PROP_ptrprop_resolver.PtrPropResolver.draw_export_object(body)
def general_get_export_objects(self) -> tuple[bpy.types.Object] | None:
"""
Return resolved exported objects or None if no selection.
"""
if self.export_mode == 'COLLECTION':
col: bpy.types.Collection = PROP_ptrprop_resolver.get_export_collection()
col: bpy.types.Collection = PROP_ptrprop_resolver.PtrPropResolver.get_export_collection()
if col is None: return None
else:
return tuple(col.all_objects)
else:
obj: bpy.types.Object = PROP_ptrprop_resolver.get_export_object()
obj: bpy.types.Object = PROP_ptrprop_resolver.PtrPropResolver.get_export_object()
if obj is None: return None
else: return (obj, )
@ -314,6 +314,7 @@ class VirtoolsParams():
# draw encodings
body.label(text = 'Encodings')
body.prop(self, 'vt_encodings', text = '')
PROP_ptrprop_resolver.PtrPropResolver.draw_ioport_encodings(body)
# following field are only valid in exporter
if not is_importer: