BallanceBlenderHelper/bbp_ng/PROP_ptrprop_resolver.py
yyc12345 4ffe29654b feat: add translation context for operators and their properties.
- add translation context for operator, menu, panel and etc. and their associated properties.
- improve some name and description but not finished.
- move reset BME material function inside BMEMaterialsHelper.
- rename variable of collection visitor in BME adder operator for clear meaning.
- replace some message box to report in ballance elements reset operator, BME materials reset operator and rail UV operator
2025-01-11 21:36:11 +08:00

261 lines
11 KiB
Python

import bpy
from bpy.types import Context, Event
from . import UTIL_functions, UTIL_virtools_types
## 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 = "",
translation_context = 'BBP_PG_bmap_encoding/property'
) # 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",
description = "The material used for rail",
type = bpy.types.Material,
translation_context = 'BBP_PG_ptrprop_resolver/property'
) # type: ignore
export_collection: bpy.props.PointerProperty(
name = "Collection",
description = "The collection exported. Nested collections allowed.",
type = bpy.types.Collection,
translation_context = 'BBP_PG_ptrprop_resolver/property'
) # type: ignore
export_object: bpy.props.PointerProperty(
name = "Object",
description = "The object exported",
type = bpy.types.Object,
translation_context = 'BBP_PG_ptrprop_resolver/property'
) # type: ignore
# TR: These encoding related items should not have explicit name and description
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(scene: bpy.types.Scene) -> BBP_PG_ptrprop_resolver:
return scene.bbp_ptrprop_resolver
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
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'}
bl_translation_context = 'BBP_OT_add_ioport_encodings'
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
return True
def execute(self, context):
encodings = get_ioport_encodings(context.scene)
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'}
bl_translation_context = 'BBP_OT_rm_ioport_encodings'
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
encodings = get_ioport_encodings(context.scene)
index = get_active_ioport_encoding(context.scene)
return index >= 0 and index < len(encodings)
def execute(self, context):
# 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):
"""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'}
bl_translation_context = 'BBP_OT_up_ioport_encodings'
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
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(context.scene)
index = get_active_ioport_encoding(context.scene)
encodings.move(index, index - 1)
set_active_ioport_encoding(context.scene, 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'}
bl_translation_context = 'BBP_OT_down_ioport_encodings'
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
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(context.scene)
index = get_active_ioport_encoding(context.scene)
encodings.move(index, index + 1)
set_active_ioport_encoding(context.scene, 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'}
bl_translation_context = 'BBP_OT_clear_ioport_encodings'
@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(context.scene)
encodings.clear()
set_active_ioport_encoding(context.scene, 0)
return {'FINISHED'}
#endregion
class PropsVisitor():
"""
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!
"""
__mAssocScene: bpy.types.Scene
def __init__(self, assoc_scene: bpy.types.Scene):
self.__mAssocScene = assoc_scene
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')
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)
def draw_ioport_encodings(self, layout: bpy.types.UILayout) -> None:
target = get_ptrprop_resolver(self.__mAssocScene)
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='')
@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)
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)
# 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)