From 680f367a42f88e78067954154e09d294e3c66cef Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Mon, 1 Jan 2024 13:07:10 +0800 Subject: [PATCH] fix issues - disable bmx import/export temporaryly - optimize the ui display of importing/exporting. (use box to organize props) - place button horizontally, not vertically in virtools material. - disallow apply in legacy align if no axis selected. - add applied step counter in legacy alignment. - add feedback for reseting bme material/component. (add a message box to show success) --- bbp_ng/OP_EXPORT_bmfile.py | 12 ++- bbp_ng/OP_EXPORT_virtools.py | 18 ++-- bbp_ng/OP_IMPORT_bmfile.py | 12 ++- bbp_ng/OP_IMPORT_virtools.py | 4 +- bbp_ng/OP_OBJECT_legacy_align.py | 28 ++++-- bbp_ng/OP_OBJECT_virtools_group.py | 3 +- bbp_ng/PROP_ballance_element.py | 8 +- bbp_ng/PROP_bme_material.py | 8 +- bbp_ng/PROP_virtools_material.py | 5 +- bbp_ng/UTIL_ioport_shared.py | 131 +++++++++++++++++++++-------- bbp_ng/UTIL_naming_convension.py | 3 +- bbp_ng/__init__.py | 4 +- 12 files changed, 172 insertions(+), 64 deletions(-) diff --git a/bbp_ng/OP_EXPORT_bmfile.py b/bbp_ng/OP_EXPORT_bmfile.py index 4536cf6..e3d1f03 100644 --- a/bbp_ng/OP_EXPORT_bmfile.py +++ b/bbp_ng/OP_EXPORT_bmfile.py @@ -1,7 +1,7 @@ import bpy -from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh +from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_icons_manager, UTIL_ioport_shared -class BBP_OT_export_bmfile(bpy.types.Operator, UTIL_file_browser.ExportBmxFile): +class BBP_OT_export_bmfile(bpy.types.Operator, UTIL_file_browser.ExportBmxFile, UTIL_ioport_shared.ExportParams): """Save a Ballance Map File (BM File Spec 1.4)""" bl_idname = "bbp.export_bmfile" bl_label = "Export BM (Ballance Map) File" @@ -12,12 +12,18 @@ class BBP_OT_export_bmfile(bpy.types.Operator, UTIL_file_browser.ExportBmxFile): return PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder() def execute(self, context): - UTIL_functions.message_box((self.general_get_filename(), ), 'Export BM File Path', 'INFO') + UTIL_functions.message_box( + ('This function not supported yet.', ), + 'No Implement', + UTIL_icons_manager.BlenderPresetIcons.Error.value + ) self.report({'INFO'}, "BM File Exporting Finished.") return {'FINISHED'} def draw(self, context): layout = self.layout + layout.label(text = 'Export Target') + self.draw_export_params(layout.box()) def register() -> None: bpy.utils.register_class(BBP_OT_export_bmfile) diff --git a/bbp_ng/OP_EXPORT_virtools.py b/bbp_ng/OP_EXPORT_virtools.py index 8e97a47..f181e06 100644 --- a/bbp_ng/OP_EXPORT_virtools.py +++ b/bbp_ng/OP_EXPORT_virtools.py @@ -68,15 +68,21 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool def draw(self, context): layout = self.layout layout.label(text = 'Export Target') - self.draw_export_params(layout) + self.draw_export_params(layout.box()) + layout.separator() layout.label(text = 'Virtools Params') - self.draw_virtools_params(layout) - layout.label(text = 'Global Texture Save Option') - layout.prop(self, 'texture_save_opt', text = '') - layout.prop(self, 'use_compress') + box = layout.box() + self.draw_virtools_params(box) + + box.separator() + box.label(text = 'Global Texture Save Option') + box.prop(self, 'texture_save_opt', text = '') + + box.separator() + box.prop(self, 'use_compress') if self.use_compress: - layout.prop(self, 'compress_level') + box.prop(self, 'compress_level') _TObj3dPair = tuple[bpy.types.Object, bmap.BM3dObject] _TMeshPair = tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh] diff --git a/bbp_ng/OP_IMPORT_bmfile.py b/bbp_ng/OP_IMPORT_bmfile.py index b5e2bad..b658fc9 100644 --- a/bbp_ng/OP_IMPORT_bmfile.py +++ b/bbp_ng/OP_IMPORT_bmfile.py @@ -1,7 +1,7 @@ import bpy -from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh +from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_icons_manager, UTIL_ioport_shared -class BBP_OT_import_bmfile(bpy.types.Operator, UTIL_file_browser.ImportBmxFile): +class BBP_OT_import_bmfile(bpy.types.Operator, UTIL_file_browser.ImportBmxFile, UTIL_ioport_shared.ImportParams): """Load a Ballance Map File (BM File Spec 1.4)""" bl_idname = "bbp.import_bmfile" bl_label = "Import BM (Ballance Map) File" @@ -12,12 +12,18 @@ class BBP_OT_import_bmfile(bpy.types.Operator, UTIL_file_browser.ImportBmxFile): return PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder() def execute(self, context): - UTIL_functions.message_box((self.general_get_filename(), ), 'Import BM File Path', 'INFO') + UTIL_functions.message_box( + ('This function not supported yet.', ), + 'No Implement', + UTIL_icons_manager.BlenderPresetIcons.Error.value + ) self.report({'INFO'}, "BM File Importing Finished.") return {'FINISHED'} def draw(self, context): layout = self.layout + layout.label(text = 'Conflict Options') + self.draw_import_params(layout.box()) def register() -> None: bpy.utils.register_class(BBP_OT_import_bmfile) diff --git a/bbp_ng/OP_IMPORT_virtools.py b/bbp_ng/OP_IMPORT_virtools.py index 400cfe2..e502701 100644 --- a/bbp_ng/OP_IMPORT_virtools.py +++ b/bbp_ng/OP_IMPORT_virtools.py @@ -29,10 +29,10 @@ class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtool def draw(self, context): layout = self.layout layout.label(text = 'Conflict Options') - self.draw_import_params(layout) + self.draw_import_params(layout.box()) layout.separator() layout.label(text = 'Virtools Params') - self.draw_virtools_params(layout) + self.draw_virtools_params(layout.box()) def _import_virtools(file_name_: str, encodings_: tuple[str]) -> None: # create temp folder diff --git a/bbp_ng/OP_OBJECT_legacy_align.py b/bbp_ng/OP_OBJECT_legacy_align.py index 7ab99b0..c1eb28b 100644 --- a/bbp_ng/OP_OBJECT_legacy_align.py +++ b/bbp_ng/OP_OBJECT_legacy_align.py @@ -82,8 +82,21 @@ class BBP_OT_legacy_align(bpy.types.Operator): if self.apply_flag == True: return self.apply_flag = True - # add a new entry in history - self.align_history.add() + # check whether add new entry + # if no selected axis, this alignment is invalid + entry: BBP_PG_legacy_align_history = self.align_history[-1] + if entry.align_x == True or entry.align_y == True or entry.align_z == True: + # valid one + # add a new entry in history + self.align_history.add() + else: + # invalid one + # reset all data to default + entry.align_x = False + entry.align_y = False + entry.align_z = False + entry.current_align_mode = _g_EnumHelper_AlignMode.to_selection(AlignMode.AxisCenter) + entry.target_align_mode = _g_EnumHelper_AlignMode.to_selection(AlignMode.AxisCenter) # reset hinder self.recursive_hinder = False @@ -142,7 +155,7 @@ class BBP_OT_legacy_align(bpy.types.Operator): col = layout.column() # show axis - col.label(text="Align Axis") + col.label(text="Align Axis (Multi-selection)") row = col.row() row.prop(entry, "align_x", toggle = 1) row.prop(entry, "align_y", toggle = 1) @@ -152,12 +165,17 @@ class BBP_OT_legacy_align(bpy.types.Operator): col.separator() col.label(text = 'Current Object (Active Object)') col.prop(entry, "current_align_mode", expand = True) - col.label(text = 'Target Objects (Other Objects)') + col.label(text = 'Target Objects (Selected Objects)') col.prop(entry, "target_align_mode", expand = True) # show apply button col.separator() - col.prop(self, 'apply_flag', text = 'Apply', icon = 'CHECKMARK', toggle = 1) + conditional_disable_area = col.column() + # only allow Apply when there is a selected axis + conditional_disable_area.enabled = entry.align_x == True or entry.align_y == True or entry.align_z == True + # show apply and counter + conditional_disable_area.prop(self, 'apply_flag', text = 'Apply', icon = 'CHECKMARK', toggle = 1) + conditional_disable_area.label(text = f'Total {len(self.align_history) - 1} applied alignments') #region Core Functions diff --git a/bbp_ng/OP_OBJECT_virtools_group.py b/bbp_ng/OP_OBJECT_virtools_group.py index 2b450d7..ce4e56a 100644 --- a/bbp_ng/OP_OBJECT_virtools_group.py +++ b/bbp_ng/OP_OBJECT_virtools_group.py @@ -54,7 +54,8 @@ class BBP_OT_select_object_by_virtools_group(bpy.types.Operator, PROP_virtools_g def draw(self, context): layout = self.layout layout.label(text='Selection Mode') - layout.prop(self, 'selection_mode', expand = True) + sublayout = layout.column() # make selection expand vertically, not horizontal. + sublayout.prop(self, 'selection_mode', expand = True) layout.separator() layout.label(text='Group Parameters') diff --git a/bbp_ng/PROP_ballance_element.py b/bbp_ng/PROP_ballance_element.py index 0f5ffe8..a320df9 100644 --- a/bbp_ng/PROP_ballance_element.py +++ b/bbp_ng/PROP_ballance_element.py @@ -1,7 +1,7 @@ import bpy import os, typing, enum, array from . import PROP_virtools_mesh -from . import UTIL_functions, UTIL_file_io, UTIL_blender_mesh, UTIL_virtools_types +from . import UTIL_functions, UTIL_file_io, UTIL_blender_mesh, UTIL_virtools_types, UTIL_icons_manager #region Raw Elements Operations @@ -349,6 +349,12 @@ class BBP_OT_reset_ballance_elements(bpy.types.Operator): def execute(self, context): reset_ballance_elements(context.scene) + # show a window to let user know, not silence + UTIL_functions.message_box( + ('Reset OK.', ), + "Reset Result", + UTIL_icons_manager.BlenderPresetIcons.Info.value + ) return {'FINISHED'} class BBP_PT_ballance_elements(bpy.types.Panel): diff --git a/bbp_ng/PROP_bme_material.py b/bbp_ng/PROP_bme_material.py index 9ca7cb6..4bc2c46 100644 --- a/bbp_ng/PROP_bme_material.py +++ b/bbp_ng/PROP_bme_material.py @@ -1,7 +1,7 @@ import bpy import typing, enum, copy from . import PROP_virtools_material, PROP_virtools_texture -from . import UTIL_ballance_texture, UTIL_functions +from . import UTIL_ballance_texture, UTIL_functions, UTIL_icons_manager #region BME Material Presets @@ -239,6 +239,12 @@ class BBP_OT_reset_bme_materials(bpy.types.Operator): def execute(self, context): reset_bme_materials(context.scene) + # show a window to let user know, not silence + UTIL_functions.message_box( + ('Reset OK.', ), + "Reset Result", + UTIL_icons_manager.BlenderPresetIcons.Info.value + ) return {'FINISHED'} class BBP_PT_bme_materials(bpy.types.Panel): diff --git a/bbp_ng/PROP_virtools_material.py b/bbp_ng/PROP_virtools_material.py index 79a599f..3c5a426 100644 --- a/bbp_ng/PROP_virtools_material.py +++ b/bbp_ng/PROP_virtools_material.py @@ -656,8 +656,9 @@ class BBP_PT_virtools_material(bpy.types.Panel): props: BBP_PG_virtools_material = get_virtools_material(context.material) # draw operator - layout.operator(BBP_OT_preset_virtools_material.bl_idname, icon="PRESET") - layout.operator(BBP_OT_apply_virtools_material.bl_idname, icon="NODETREE") + row = layout.row() + row.operator(BBP_OT_preset_virtools_material.bl_idname, text = 'Preset', icon = "PRESET") + row.operator(BBP_OT_apply_virtools_material.bl_idname, text = 'Apply', icon = "NODETREE") # draw data layout.label(text="Color Parameters") diff --git a/bbp_ng/UTIL_ioport_shared.py b/bbp_ng/UTIL_ioport_shared.py index d3d9c44..7f8a81c 100644 --- a/bbp_ng/UTIL_ioport_shared.py +++ b/bbp_ng/UTIL_ioport_shared.py @@ -1,6 +1,6 @@ import bpy import enum -from . import UTIL_virtools_types +from . import UTIL_virtools_types, UTIL_functions from . import PROP_ptrprop_resolver ## Intent @@ -9,65 +9,90 @@ from . import PROP_ptrprop_resolver # and call general getter to get user selected data. # Also provide draw function thus caller do not need draw the params themselves. +class ConflictStrategy(enum.IntEnum): + Rename = enum.auto() + Current = enum.auto() + Replace = enum.auto() +_g_ConflictStrategyDesc: dict[ConflictStrategy, tuple[str, str]] = { + ConflictStrategy.Rename: ('Rename', 'Rename the new one'), + ConflictStrategy.Current: ('Use Current', 'Use current one'), + ConflictStrategy.Replace: ('Replace', 'Replace the old one with new one'), +} +_g_EnumHelper_ConflictStrategy: UTIL_functions.EnumPropHelper = UTIL_functions.EnumPropHelper( + ConflictStrategy, + lambda x: str(x.value), + lambda x: ConflictStrategy(int(x)), + lambda x: _g_ConflictStrategyDesc[x][0], + lambda x: _g_ConflictStrategyDesc[x][1], + lambda _: '' +) + class ImportParams(): texture_conflict_strategy: bpy.props.EnumProperty( - name = "Texture name conflict", - items = ( - ('NEW', "New Instance", "Create a new instance"), - ('CURRENT', "Use Current", "Use current one"), - ), + name = "Texture Name Conflict", + items = _g_EnumHelper_ConflictStrategy.generate_items(), description = "Define how to process texture name conflict", - default = 'CURRENT', - ) + default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Current), + ) material_conflict_strategy: bpy.props.EnumProperty( - name = "Material name conflict", - items = ( - ('RENAME', "Rename", "Rename the new one"), - ('CURRENT', "Use Current", "Use current one"), - ), + name = "Material Name Conflict", + items = _g_EnumHelper_ConflictStrategy.generate_items(), description = "Define how to process material name conflict", - default = 'RENAME', - ) + default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename), + ) mesh_conflict_strategy: bpy.props.EnumProperty( - name = "Mesh name conflict", - items = ( - ('RENAME', "Rename", "Rename the new one"), - ('CURRENT', "Use Current", "Use current one"), - ), + name = "Mesh Name Conflict", + items = _g_EnumHelper_ConflictStrategy.generate_items(), description = "Define how to process mesh name conflict", - default = 'RENAME', - ) + default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename), + ) object_conflict_strategy: bpy.props.EnumProperty( - name = "Object name conflict", - items = ( - ('RENAME', "Rename", "Rename the new one"), - ('CURRENT', "Use Current", "Use current one"), - ), + name = "Object Name Conflict", + items = _g_EnumHelper_ConflictStrategy.generate_items(), description = "Define how to process object name conflict", - default = 'RENAME', - ) + default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename), + ) def draw_import_params(self, layout: bpy.types.UILayout) -> None: - layout.prop(self, 'object_conflict_strategy') - layout.prop(self, 'mesh_conflict_strategy') - layout.prop(self, 'material_conflict_strategy') - layout.prop(self, 'texture_conflict_strategy') + layout.label(text = 'Object Name Conflict') + layout.prop(self, 'object_conflict_strategy', text = '') + layout.label(text = 'Mesh Name Conflict') + layout.prop(self, 'mesh_conflict_strategy', text = '') + layout.label(text = 'Material Name Conflict') + layout.prop(self, 'material_conflict_strategy', text = '') + layout.label(text = 'Texture Name Conflict') + layout.prop(self, 'texture_conflict_strategy', text = '') + + def general_get_texture_conflict_strategy(self) -> ConflictStrategy: + return _g_EnumHelper_ConflictStrategy.get_selection(self.texture_conflict_strategy) + + def general_get_material_conflict_strategy(self) -> ConflictStrategy: + return _g_EnumHelper_ConflictStrategy.get_selection(self.material_conflict_strategy) + + def general_get_mesh_conflict_strategy(self) -> ConflictStrategy: + return _g_EnumHelper_ConflictStrategy.get_selection(self.mesh_conflict_strategy) + + def general_get_object_conflict_strategy(self) -> ConflictStrategy: + return _g_EnumHelper_ConflictStrategy.get_selection(self.object_conflict_strategy) class ExportParams(): export_mode: bpy.props.EnumProperty( name = "Export Mode", items = ( - ('COLLECTION', "Collection", "Export a collection"), - ('OBJECT', "Object", "Export an object"), + ('COLLECTION', "Collection", "Export a collection", 'OUTLINER_COLLECTION', 0), + ('OBJECT', "Object", "Export an object", 'OBJECT_DATA', 1), ), ) def draw_export_params(self, layout: bpy.types.UILayout) -> None: + # make prop expand horizontaly, not vertical. + sublayout = layout.row() # draw switch - layout.prop(self, "export_mode", expand = True) + sublayout.prop(self, "export_mode", expand = True) + # draw picker if self.export_mode == 'COLLECTION': PROP_ptrprop_resolver.draw_export_collection(layout) @@ -96,7 +121,8 @@ class VirtoolsParams(): ) def draw_virtools_params(self, layout: bpy.types.UILayout) -> None: - layout.prop(self, 'vt_encodings') + layout.label(text = 'Encodings') + layout.prop(self, 'vt_encodings', text = '') def general_get_vt_encodings(self) -> tuple[str]: # get encoding, split it by `;` and strip blank chars. @@ -108,6 +134,13 @@ class ExportEditModeBackup(): The class which save Edit Mode when exporting and restore it after exporting. Because edit mode is not allowed when exporting. Support `with` statement. + + ``` + with ExportEditModeBackup(): + # do some exporting work + blabla() + # restore automatically when exiting "with" + ``` """ mInEditMode: bool @@ -127,4 +160,28 @@ class ExportEditModeBackup(): bpy.ops.object.editmode_toggle() self.mInEditMode = False +class ConflictResolver(): + """ + This class frequently used when importing objects. + This class accept 4 conflict strategies for object, mesh, material and texture, + and provide 4 general creation functions to handle these strategies. + Each general creation functions will return an instance and a bool indicating whether this instance need be initialized. + + This class also provide 3 static common creation functions without considering conflict. + They just a redirect calling to `bpy.data.xxx.new()`. + No static texture (Image) creation function because texture is not created from `bpy.data.images`. + """ + + @staticmethod + def create_object(name: str, data: bpy.types.Mesh) -> bpy.types.Object: + return bpy.data.objects.new(name, data) + + @staticmethod + def create_mesh(name: str) -> bpy.types.Mesh: + return bpy.data.meshes.new(name) + + @staticmethod + def create_material(name: str) -> bpy.types.Material: + return bpy.data.materials.new(name) + diff --git a/bbp_ng/UTIL_naming_convension.py b/bbp_ng/UTIL_naming_convension.py index b52c9d8..e1609a1 100644 --- a/bbp_ng/UTIL_naming_convension.py +++ b/bbp_ng/UTIL_naming_convension.py @@ -373,7 +373,8 @@ class VirtoolsGroupConvention(): case BallanceObjectType.COMPONENT: # group into component type - gp.add_group(info.mComponentType) + # use typing.cast() to force linter accept it because None is impossible + gp.add_group(typing.cast(str, info.mComponentType)) # group to sector if info.mSector == 9: diff --git a/bbp_ng/__init__.py b/bbp_ng/__init__.py index 09482a2..83aa185 100644 --- a/bbp_ng/__init__.py +++ b/bbp_ng/__init__.py @@ -103,12 +103,12 @@ MenuDrawer_t = typing.Callable[[typing.Any, typing.Any], None] def menu_drawer_import(self, context) -> None: layout: bpy.types.UILayout = self.layout - layout.operator(OP_IMPORT_bmfile.BBP_OT_import_bmfile.bl_idname, text = "Ballance Map (.bmx)") + #layout.operator(OP_IMPORT_bmfile.BBP_OT_import_bmfile.bl_idname, text = "Ballance Map (.bmx)") layout.operator(OP_IMPORT_virtools.BBP_OT_import_virtools.bl_idname, text = "Virtools File (.nmo/.cmo/.vmo) (experimental)") def menu_drawer_export(self, context) -> None: layout: bpy.types.UILayout = self.layout - layout.operator(OP_EXPORT_bmfile.BBP_OT_export_bmfile.bl_idname, text = "Ballance Map (.bmx)") + #layout.operator(OP_EXPORT_bmfile.BBP_OT_export_bmfile.bl_idname, text = "Ballance Map (.bmx)") layout.operator(OP_EXPORT_virtools.BBP_OT_export_virtools.bl_idname, text = "Virtools File (.nmo/.cmo/.vmo) (experimental)") def menu_drawer_view3d(self, context) -> None: