fix: fix previous commit remained issues.

- vt encodings in list showcase now works.
- modify some usage of message_box to Operator.report to make it more like blender suggested.
This commit is contained in:
yyc12345 2025-01-08 20:20:10 +08:00
parent 0862ecd269
commit 77315ffbea
8 changed files with 127 additions and 121 deletions

View File

@ -1,5 +1,5 @@
import bpy
from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_icons_manager, UTIL_ioport_shared
from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ioport_shared
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)"""
@ -12,18 +12,14 @@ 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(
('This function not supported yet.', ),
'No Implement',
UTIL_icons_manager.BlenderPresetIcons.Error.value
)
self.report({'INFO'}, "BM File Exporting Finished.")
self.report({'ERROR'}, 'This function not supported yet.')
# 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())
self.draw_export_params(context, layout.box())
def register() -> None:
bpy.utils.register_class(BBP_OT_export_bmfile)

View File

@ -2,7 +2,7 @@ import bpy, mathutils
from bpy_extras.wm_utils.progress_report import ProgressReport
import tempfile, os, typing
from . import PROP_preferences, UTIL_ioport_shared
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_icons_manager, UTIL_naming_convension
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_naming_convension
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_virtools_light
from .PyBMap import bmap_wrapper as bmap
@ -20,30 +20,28 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
def execute(self, context):
# check selecting first
objls: tuple[bpy.types.Object] | None = self.general_get_export_objects()
objls: tuple[bpy.types.Object] | None = self.general_get_export_objects(context)
if objls is None:
UTIL_functions.message_box(
('No selected target!', ),
'Lost Parameters',
UTIL_icons_manager.BlenderPresetIcons.Error.value
)
self.report({'ERROR'}, 'No selected target!')
return {'CANCELLED'}
# check texture save option to prevent real stupid user.
# check texture save option to avoid real stupid user.
texture_save_opt = self.general_get_texture_save_opt()
if texture_save_opt == UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_USEGLOBAL:
UTIL_functions.message_box(
('You can not specify "Use Global" as global texture save option!', ),
'Wrong Parameters',
UTIL_icons_manager.BlenderPresetIcons.Error.value
)
self.report({'ERROR'}, 'You can not specify "Use Global" as global texture save option!')
return {'CANCELLED'}
# check whether encoding list is empty to avoid real stupid user.
encodings = self.general_get_vt_encodings(context)
if len(encodings) == 0:
self.report({'ERROR'}, 'You must specify at least one encoding for file saving (e.g. cp1252, gb2312)!')
return {'CANCELLED'}
# start exporting
with UTIL_ioport_shared.ExportEditModeBackup() as editmode_guard:
_export_virtools(
self.general_get_filename(),
self.general_get_vt_encodings(),
encodings,
texture_save_opt,
self.general_get_use_compress(),
self.general_get_compress_level(),
@ -57,8 +55,8 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
def draw(self, context):
layout = self.layout
self.draw_export_params(layout)
self.draw_virtools_params(layout, False)
self.draw_export_params(context, layout)
self.draw_virtools_params(context, layout, False)
self.draw_ballance_params(layout, False)
_TObj3dPair = tuple[bpy.types.Object, bmap.BM3dObject]

View File

@ -1,5 +1,5 @@
import bpy
from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_icons_manager, UTIL_ioport_shared
from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ioport_shared
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)"""
@ -12,12 +12,8 @@ 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(
('This function not supported yet.', ),
'No Implement',
UTIL_icons_manager.BlenderPresetIcons.Error.value
)
self.report({'INFO'}, "BM File Importing Finished.")
self.report({'ERROR'}, 'This function not supported yet.')
# self.report({'INFO'}, "BM File Importing Finished.")
return {'FINISHED'}
def draw(self, context):

View File

@ -19,9 +19,15 @@ class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtool
and bmap.is_bmap_available())
def execute(self, context):
# check whether encoding list is empty to avoid real stupid user.
encodings = self.general_get_vt_encodings(context)
if len(encodings) == 0:
self.report({'ERROR'}, 'You must specify at least one encoding for file loading (e.g. cp1252, gb2312)!')
return {'CANCELLED'}
_import_virtools(
self.general_get_filename(),
self.general_get_vt_encodings(),
encodings,
self.general_get_conflict_resolver()
)
self.report({'INFO'}, "Virtools File Importing Finished.")
@ -30,7 +36,7 @@ class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtool
def draw(self, context):
layout = self.layout
self.draw_import_params(layout)
self.draw_virtools_params(layout, True)
self.draw_virtools_params(context, layout, True)
self.draw_ballance_params(layout, True)
def _import_virtools(file_name_: str, encodings_: tuple[str], resolver: UTIL_ioport_shared.ConflictResolver) -> None:

View File

@ -19,13 +19,10 @@ class BBP_OT_rail_uv(bpy.types.Operator):
def execute(self, context):
# check material
mtl: bpy.types.Material = PROP_ptrprop_resolver.PtrPropResolver.get_rail_uv_material()
ptrprops = PROP_ptrprop_resolver.PropsVisitor(context.scene)
mtl: bpy.types.Material = ptrprops.get_rail_uv_material()
if mtl is None:
UTIL_functions.message_box(
("No specific material", ),
"Lost Parameter",
UTIL_icons_manager.BlenderPresetIcons.Error.value
)
self.report({'ERROR'}, "Specified material is empty.")
return {'CANCELLED'}
# apply rail uv
@ -34,7 +31,8 @@ class BBP_OT_rail_uv(bpy.types.Operator):
def draw(self, context):
layout: bpy.types.UILayout = self.layout
PROP_ptrprop_resolver.PtrPropResolver.draw_rail_uv_material(layout)
ptrprops = PROP_ptrprop_resolver.PropsVisitor(context.scene)
ptrprops.draw_rail_uv_material(layout)
#region Real Worker Functions

View File

@ -1,6 +1,6 @@
import bpy
from bpy.types import Context, Event
from . import UTIL_functions
from . import UTIL_functions, UTIL_virtools_types
## Intent
# Operator is not allowed to register Pointer Properties.
@ -45,15 +45,15 @@ class BBP_PG_ptrprop_resolver(bpy.types.PropertyGroup):
#endregion
def get_ptrprop_resolver() -> BBP_PG_ptrprop_resolver:
return bpy.context.scene.bbp_ptrprop_resolver
def get_ptrprop_resolver(scene: bpy.types.Scene) -> BBP_PG_ptrprop_resolver:
return scene.bbp_ptrprop_resolver
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_ioport_encodings(scene: bpy.types.Scene) -> UTIL_functions.CollectionVisitor[BBP_PG_bmap_encoding]:
return UTIL_functions.CollectionVisitor(get_ptrprop_resolver(scene).ioport_encodings)
def get_active_ioport_encoding(scene: bpy.types.Scene) -> int:
return get_ptrprop_resolver(scene).active_ioport_encodings
def set_active_ioport_encoding(scene: bpy.types.Scene, val: int) -> None:
get_ptrprop_resolver(scene).active_ioport_encodings = val
#region Blender Operator Defines for Encodings
@ -68,7 +68,7 @@ class BBP_OT_add_ioport_encodings(bpy.types.Operator):
return True
def execute(self, context):
encodings = get_ioport_encodings()
encodings = get_ioport_encodings(context.scene)
encodings.add()
return {'FINISHED'}
@ -80,13 +80,19 @@ class BBP_OT_rm_ioport_encodings(bpy.types.Operator):
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
encodings = get_ioport_encodings(context.scene)
index = get_active_ioport_encoding(context.scene)
return index >= 0 and index < len(encodings)
def execute(self, context):
encodings = get_ioport_encodings()
encodings.remove(get_active_ioport_encoding())
# delete selected item
encodings = get_ioport_encodings(context.scene)
index = get_active_ioport_encoding(context.scene)
encodings.remove(index)
# try to correct selected item
if index >= len(encodings): index = len(encodings) - 1
if index < 0: index = 0
set_active_ioport_encoding(context.scene, index)
return {'FINISHED'}
class BBP_OT_up_ioport_encodings(bpy.types.Operator):
@ -97,15 +103,15 @@ class BBP_OT_up_ioport_encodings(bpy.types.Operator):
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
encodings = get_ioport_encodings(context.scene)
index = get_active_ioport_encoding(context.scene)
return index >= 1 and index < len(encodings)
def execute(self, context):
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
encodings = get_ioport_encodings(context.scene)
index = get_active_ioport_encoding(context.scene)
encodings.move(index, index - 1)
set_active_ioport_encoding(index - 1)
set_active_ioport_encoding(context.scene, index - 1)
return {'FINISHED'}
class BBP_OT_down_ioport_encodings(bpy.types.Operator):
@ -116,15 +122,15 @@ class BBP_OT_down_ioport_encodings(bpy.types.Operator):
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
encodings = get_ioport_encodings(context.scene)
index = get_active_ioport_encoding(context.scene)
return index >= 0 and index < len(encodings) - 1
def execute(self, context):
encodings = get_ioport_encodings()
index = get_active_ioport_encoding()
encodings = get_ioport_encodings(context.scene)
index = get_active_ioport_encoding(context.scene)
encodings.move(index, index + 1)
set_active_ioport_encoding(index + 1)
set_active_ioport_encoding(context.scene, index + 1)
return {'FINISHED'}
class BBP_OT_clear_ioport_encodings(bpy.types.Operator):
@ -142,55 +148,46 @@ class BBP_OT_clear_ioport_encodings(bpy.types.Operator):
return wm.invoke_confirm(self, event)
def execute(self, context):
encodings = get_ioport_encodings()
encodings = get_ioport_encodings(context.scene)
encodings.clear()
set_active_ioport_encoding(0)
set_active_ioport_encoding(context.scene, 0)
return {'FINISHED'}
#endregion
class PtrPropResolver():
class PropsVisitor():
"""
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.
When outside code want to fetch or draw properties defined in ptrprop_resolver,
they should create the instance of this class with given associated scene instance first.
Then use this class provided member function to draw or fetch these properties.
The function located 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')
__mAssocScene: bpy.types.Scene
@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')
def __init__(self, assoc_scene: bpy.types.Scene):
self.__mAssocScene = assoc_scene
@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')
def get_rail_uv_material(self) -> bpy.types.Material:
return get_ptrprop_resolver(self.__mAssocScene).rail_uv_material
def draw_rail_uv_material(self, layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(self.__mAssocScene), 'rail_uv_material')
@staticmethod
def get_ioport_encodings() -> tuple[str, ...]:
encodings = get_ioport_encodings()
def get_export_collection(self) -> bpy.types.Collection:
return get_ptrprop_resolver(self.__mAssocScene).export_collection
def draw_export_collection(self, layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(self.__mAssocScene), 'export_collection')
def get_export_object(self) -> bpy.types.Object:
return get_ptrprop_resolver(self.__mAssocScene).export_object
def draw_export_object(self, layout: bpy.types.UILayout) -> None:
layout.prop(get_ptrprop_resolver(self.__mAssocScene), 'export_object')
def get_ioport_encodings(self) -> tuple[str, ...]:
encodings = get_ioport_encodings(self.__mAssocScene)
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()
def draw_ioport_encodings(self, layout: bpy.types.UILayout) -> None:
target = get_ptrprop_resolver(self.__mAssocScene)
row = layout.row()
# draw main list
@ -212,11 +209,24 @@ class PtrPropResolver():
col.separator()
col.operator(BBP_OT_clear_ioport_encodings.bl_idname, icon='TRASH', text='')
@bpy.app.handlers.persistent
def _ioport_encodings_initializer(file_path: str):
# if we can fetch property, and it is empty after loading file
# we fill it with default value
encodings = get_ioport_encodings(bpy.context.scene)
if len(encodings) == 0:
for default_enc in UTIL_virtools_types.g_PyBMapDefaultEncodings:
item = encodings.add()
item.encoding = default_enc
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)
# register ioport encodings default value
bpy.app.handlers.load_post.append(_ioport_encodings_initializer)
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)
@ -234,6 +244,9 @@ def unregister() -> None:
bpy.utils.unregister_class(BBP_OT_rm_ioport_encodings)
bpy.utils.unregister_class(BBP_OT_add_ioport_encodings)
# unregister ioport encodings default value
bpy.app.handlers.load_post.remove(_ioport_encodings_initializer)
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

@ -242,7 +242,7 @@ class ExportParams():
),
) # type: ignore
def draw_export_params(self, layout: bpy.types.UILayout) -> None:
def draw_export_params(self, context: bpy.types.Context, layout: bpy.types.UILayout) -> None:
header: bpy.types.UILayout
body: bpy.types.UILayout
header, body = layout.panel("BBP_PT_ioport_shared_export_params", default_closed=False)
@ -255,22 +255,24 @@ class ExportParams():
horizon_body.prop(self, "export_mode", expand = True)
# draw picker
ptrprops = PROP_ptrprop_resolver.PropsVisitor(context.scene)
if self.export_mode == 'COLLECTION':
PROP_ptrprop_resolver.PtrPropResolver.draw_export_collection(body)
ptrprops.draw_export_collection(body)
elif self.export_mode == 'OBJECT':
PROP_ptrprop_resolver.PtrPropResolver.draw_export_object(body)
ptrprops.draw_export_object(body)
def general_get_export_objects(self) -> tuple[bpy.types.Object] | None:
def general_get_export_objects(self, context: bpy.types.Context) -> tuple[bpy.types.Object] | None:
"""
Return resolved exported objects or None if no selection.
"""
ptrprops = PROP_ptrprop_resolver.PropsVisitor(context.scene)
if self.export_mode == 'COLLECTION':
col: bpy.types.Collection = PROP_ptrprop_resolver.PtrPropResolver.get_export_collection()
col: bpy.types.Collection = ptrprops.get_export_collection()
if col is None: return None
else:
return tuple(col.all_objects)
else:
obj: bpy.types.Object = PROP_ptrprop_resolver.PtrPropResolver.get_export_object()
obj: bpy.types.Object = ptrprops.get_export_object()
if obj is None: return None
else: return (obj, )
@ -278,12 +280,6 @@ class ExportParams():
_g_EnumHelper_CK_TEXTURE_SAVEOPTIONS: UTIL_virtools_types.EnumPropHelper = UTIL_virtools_types.EnumPropHelper(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS)
class VirtoolsParams():
vt_encodings: bpy.props.StringProperty(
name = "Encodings",
description = "The encoding list used by Virtools engine to resolve object name. Use `;` to split multiple encodings",
default = UTIL_virtools_types.g_PyBMapDefaultEncoding
) # type: ignore
texture_save_opt: bpy.props.EnumProperty(
name = "Global Texture Save Options",
description = "Decide how texture saved if texture is specified as Use Global as its Save Options.",
@ -304,7 +300,7 @@ class VirtoolsParams():
default = 5,
) # type: ignore
def draw_virtools_params(self, layout: bpy.types.UILayout, is_importer: bool) -> None:
def draw_virtools_params(self, context: bpy.types.Context, layout: bpy.types.UILayout, is_importer: bool) -> None:
header: bpy.types.UILayout
body: bpy.types.UILayout
header, body = layout.panel("BBP_PT_ioport_shared_virtools_params", default_closed=False)
@ -313,8 +309,8 @@ class VirtoolsParams():
# draw encodings
body.label(text = 'Encodings')
body.prop(self, 'vt_encodings', text = '')
PROP_ptrprop_resolver.PtrPropResolver.draw_ioport_encodings(body)
ptrprops = PROP_ptrprop_resolver.PropsVisitor(context.scene)
ptrprops.draw_ioport_encodings(body)
# following field are only valid in exporter
if not is_importer:
@ -329,10 +325,10 @@ class VirtoolsParams():
body.prop(self, 'compress_level')
def general_get_vt_encodings(self) -> tuple[str]:
# get encoding, split it by `;` and strip blank chars.
encodings: str = self.vt_encodings
return tuple(map(lambda x: x.strip(), encodings.split(';')))
def general_get_vt_encodings(self, context: bpy.types.Context) -> tuple[str, ...]:
# get from ptrprop resolver then filter empty item
ptrprops = PROP_ptrprop_resolver.PropsVisitor(context.scene)
return tuple(filter(lambda encoding: len(encoding) != 0, ptrprops.get_ioport_encodings()))
def general_get_texture_save_opt(self) -> UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS:
return _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.get_selection(self.texture_save_opt)

View File

@ -270,6 +270,9 @@ def virtools_name_regulator(name: str | None) -> str:
# Since LibCmo 0.2, the encoding name of LibCmo become universal encoding which is platfoorm independent.
# So no need set it according to different platform.
# Use universal encoding name (like Python).
g_PyBMapDefaultEncoding: str = 'cp1252;gb2312'
g_PyBMapDefaultEncodings: tuple[str, ...] = (
'cp1252',
'gb2312'
)
#endregion