From 0862ecd269d835524f085c85e60830c8de1bd90c Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Wed, 8 Jan 2025 13:21:35 +0800 Subject: [PATCH] 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. --- bbp_ng/OP_UV_rail_uv.py | 4 +- bbp_ng/PROP_ptrprop_resolver.py | 212 ++++++++++++++++++++++++++++++-- bbp_ng/UTIL_ioport_shared.py | 9 +- 3 files changed, 207 insertions(+), 18 deletions(-) diff --git a/bbp_ng/OP_UV_rail_uv.py b/bbp_ng/OP_UV_rail_uv.py index b5eac56..794db0e 100644 --- a/bbp_ng/OP_UV_rail_uv.py +++ b/bbp_ng/OP_UV_rail_uv.py @@ -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 diff --git a/bbp_ng/PROP_ptrprop_resolver.py b/bbp_ng/PROP_ptrprop_resolver.py index de99f3f..f99fa37 100644 --- a/bbp_ng/PROP_ptrprop_resolver.py +++ b/bbp_ng/PROP_ptrprop_resolver.py @@ -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) diff --git a/bbp_ng/UTIL_ioport_shared.py b/bbp_ng/UTIL_ioport_shared.py index c1a7284..418a47d 100644 --- a/bbp_ng/UTIL_ioport_shared.py +++ b/bbp_ng/UTIL_ioport_shared.py @@ -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: