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
This commit is contained in:
yyc12345 2025-01-11 21:36:11 +08:00
parent 1d7ac76d0e
commit 4ffe29654b
27 changed files with 444 additions and 206 deletions

View File

@ -1,7 +1,7 @@
import bpy, mathutils
import typing
from . import PROP_preferences
from . import UTIL_functions, UTIL_bme
from . import UTIL_functions, UTIL_translation, UTIL_bme
#region BME Adder
@ -9,29 +9,33 @@ _g_EnumHelper_BmeStructType: UTIL_bme.EnumPropHelper = UTIL_bme.EnumPropHelper()
class BBP_PG_bme_adder_cfgs(bpy.types.PropertyGroup):
prop_int: bpy.props.IntProperty(
name = 'Single Int', description = 'Single Int',
name = 'Integral Value', description = 'The field representing a single integral value.',
min = 0, max = 64,
soft_min = 0, soft_max = 32,
step = 1,
default = 1,
translation_context = 'BBP_PG_bme_adder_cfgs/property'
) # type: ignore
prop_float: bpy.props.FloatProperty(
name = 'Single Float', description = 'Single Float',
name = 'Float Point Value', description = 'The field representing a single float point value.',
min = 0.0, max = 1024.0,
soft_min = 0.0, soft_max = 512.0,
step = 50, # Step is in UI, in [1, 100] (WARNING: actual value is /100). So we choose 50, mean 0.5
default = 5.0,
translation_context = 'BBP_PG_bme_adder_cfgs/property'
) # type: ignore
prop_bool: bpy.props.BoolProperty(
name = 'Single Bool', description = 'Single Bool',
default = True
name = 'Boolean Value', description = 'The field representing a single boolean value.',
default = True,
translation_context = 'BBP_PG_bme_adder_cfgs/property'
) # type: ignore
class BBP_OT_add_bme_struct(bpy.types.Operator):
"""Add BME Struct"""
"""Add BME structure"""
bl_idname = "bbp.add_bme_struct"
bl_label = "Add BME Struct"
bl_label = "Add BME Structure"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_bme_struct'
## There is a compromise due to the shitty Blender design.
#
@ -51,8 +55,9 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
## Compromise used "outdated" flag.
outdated_flag: bpy.props.BoolProperty(
name = "Outdated Type",
description = "Internal flag.",
# TR: Internal property should not have name and desc otherwise they will be written in translation.
# name = "Outdated Type",
# description = "Internal flag.",
options = {'HIDDEN', 'SKIP_SAVE'},
default = False
) # type: ignore
@ -96,29 +101,29 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
# init data collection
adder_cfgs_visitor: UTIL_functions.CollectionVisitor[BBP_PG_bme_adder_cfgs]
adder_cfgs_visitor = UTIL_functions.CollectionVisitor(self.bme_struct_cfgs)
op_cfgs_visitor: UTIL_functions.CollectionVisitor[BBP_PG_bme_adder_cfgs]
op_cfgs_visitor = UTIL_functions.CollectionVisitor(self.bme_struct_cfgs)
# clear first
adder_cfgs_visitor.clear()
op_cfgs_visitor.clear()
# create enough entries specified by gotten cfgs
for _ in range(max(counter_int, counter_float, counter_bool)):
adder_cfgs_visitor.add()
op_cfgs_visitor.add()
# assign default value
for (cfg, cfg_index) in self.bme_struct_cfg_index_cache:
# show prop differently by cfg type
match(cfg.get_type()):
case UTIL_bme.PrototypeShowcaseCfgsTypes.Integer:
adder_cfgs_visitor[cfg_index].prop_int = cfg.get_default()
op_cfgs_visitor[cfg_index].prop_int = cfg.get_default()
case UTIL_bme.PrototypeShowcaseCfgsTypes.Float:
adder_cfgs_visitor[cfg_index].prop_float = cfg.get_default()
op_cfgs_visitor[cfg_index].prop_float = cfg.get_default()
case UTIL_bme.PrototypeShowcaseCfgsTypes.Boolean:
adder_cfgs_visitor[cfg_index].prop_bool = cfg.get_default()
op_cfgs_visitor[cfg_index].prop_bool = cfg.get_default()
case UTIL_bme.PrototypeShowcaseCfgsTypes.Face:
# face is just 6 bool
default_values: tuple[bool, ...] = cfg.get_default()
for i in range(6):
adder_cfgs_visitor[cfg_index + i].prop_bool = default_values[i]
op_cfgs_visitor[cfg_index + i].prop_bool = default_values[i]
# reset outdated flag
self.outdated_flag = False
@ -132,15 +137,17 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
bme_struct_type: bpy.props.EnumProperty(
name = "Type",
description = "BME struct type",
description = "The type of BME structure.",
items = _g_EnumHelper_BmeStructType.generate_items(),
update = bme_struct_type_updated
update = bme_struct_type_updated,
translation_context = 'BBP_OT_add_bme_struct/property'
) # type: ignore
bme_struct_cfgs : bpy.props.CollectionProperty(
name = "Cfgs",
description = "Cfg collection.",
name = "Configurations",
description = "The collection holding BME structure configurations.",
type = BBP_PG_bme_adder_cfgs,
translation_context = 'BBP_OT_add_bme_struct/property'
) # type: ignore
## Extra transform for good "what you see is what you gotten".
@ -151,7 +158,8 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
size = 3,
subtype = 'TRANSLATION',
step = 50, # same step as the float entry of BBP_PG_bme_adder_cfgs
default = (0.0, 0.0, 0.0)
default = (0.0, 0.0, 0.0),
translation_context = 'BBP_OT_add_bme_struct/property'
) # type: ignore
extra_rotation: bpy.props.FloatVectorProperty(
name = "Extra Rotation",
@ -159,7 +167,8 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
size = 3,
subtype = 'EULER',
step = 100, # We choosen 100, mean 1. Sync with property window.
default = (0.0, 0.0, 0.0)
default = (0.0, 0.0, 0.0),
translation_context = 'BBP_OT_add_bme_struct/property'
) # type: ignore
@classmethod
@ -185,22 +194,22 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
self.__internal_update_bme_struct_type()
# create cfg visitor
adder_cfgs_visitor: UTIL_functions.CollectionVisitor[BBP_PG_bme_adder_cfgs]
adder_cfgs_visitor = UTIL_functions.CollectionVisitor(self.bme_struct_cfgs)
op_cfgs_visitor: UTIL_functions.CollectionVisitor[BBP_PG_bme_adder_cfgs]
op_cfgs_visitor = UTIL_functions.CollectionVisitor(self.bme_struct_cfgs)
# collect cfgs data
cfgs: dict[str, typing.Any] = {}
for (cfg, cfg_index) in self.bme_struct_cfg_index_cache:
match(cfg.get_type()):
case UTIL_bme.PrototypeShowcaseCfgsTypes.Integer:
cfgs[cfg.get_field()] = adder_cfgs_visitor[cfg_index].prop_int
cfgs[cfg.get_field()] = op_cfgs_visitor[cfg_index].prop_int
case UTIL_bme.PrototypeShowcaseCfgsTypes.Float:
cfgs[cfg.get_field()] = adder_cfgs_visitor[cfg_index].prop_float
cfgs[cfg.get_field()] = op_cfgs_visitor[cfg_index].prop_float
case UTIL_bme.PrototypeShowcaseCfgsTypes.Boolean:
cfgs[cfg.get_field()] = adder_cfgs_visitor[cfg_index].prop_bool
cfgs[cfg.get_field()] = op_cfgs_visitor[cfg_index].prop_bool
case UTIL_bme.PrototypeShowcaseCfgsTypes.Face:
# face is just 6 bool tuple
cfgs[cfg.get_field()] = tuple(
adder_cfgs_visitor[cfg_index + i].prop_bool for i in range(6)
op_cfgs_visitor[cfg_index + i].prop_bool for i in range(6)
)
# call general creator
@ -231,8 +240,8 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
layout.prop(self, 'bme_struct_type')
# create cfg visitor
adder_cfgs_visitor: UTIL_functions.CollectionVisitor[BBP_PG_bme_adder_cfgs]
adder_cfgs_visitor = UTIL_functions.CollectionVisitor(self.bme_struct_cfgs)
op_cfgs_visitor: UTIL_functions.CollectionVisitor[BBP_PG_bme_adder_cfgs]
op_cfgs_visitor = UTIL_functions.CollectionVisitor(self.bme_struct_cfgs)
# visit cfgs cache list to show cfg
layout.label(text = "Prototype Configurations:")
for (cfg, cfg_index) in self.bme_struct_cfg_index_cache:
@ -246,29 +255,29 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
# show prop differently by cfg type
match(cfg.get_type()):
case UTIL_bme.PrototypeShowcaseCfgsTypes.Integer:
box_layout.prop(adder_cfgs_visitor[cfg_index], 'prop_int', text = '')
box_layout.prop(op_cfgs_visitor[cfg_index], 'prop_int', text = '')
case UTIL_bme.PrototypeShowcaseCfgsTypes.Float:
box_layout.prop(adder_cfgs_visitor[cfg_index], 'prop_float', text = '')
box_layout.prop(op_cfgs_visitor[cfg_index], 'prop_float', text = '')
case UTIL_bme.PrototypeShowcaseCfgsTypes.Boolean:
box_layout.prop(adder_cfgs_visitor[cfg_index], 'prop_bool', text = '')
box_layout.prop(op_cfgs_visitor[cfg_index], 'prop_bool', text = '')
case UTIL_bme.PrototypeShowcaseCfgsTypes.Face:
# face will show a special layout (grid view)
grids = box_layout.grid_flow(
row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
grids.alignment = 'CENTER'
grids.separator()
grids.prop(adder_cfgs_visitor[cfg_index + 0], 'prop_bool', text = 'Top') # top
grids.prop(adder_cfgs_visitor[cfg_index + 2], 'prop_bool', text = 'Front') # front
grids.prop(adder_cfgs_visitor[cfg_index + 4], 'prop_bool', text = 'Left') # left
grids.prop(op_cfgs_visitor[cfg_index + 0], 'prop_bool', text = 'Top') # top
grids.prop(op_cfgs_visitor[cfg_index + 2], 'prop_bool', text = 'Front') # front
grids.prop(op_cfgs_visitor[cfg_index + 4], 'prop_bool', text = 'Left') # left
grids.label(text = '', icon = 'CUBE') # show a 3d cube as icon
grids.prop(adder_cfgs_visitor[cfg_index + 5], 'prop_bool', text = 'Right') # right
grids.prop(adder_cfgs_visitor[cfg_index + 3], 'prop_bool', text = 'Back') # back
grids.prop(adder_cfgs_visitor[cfg_index + 1], 'prop_bool', text = 'Bottom') # bottom
grids.prop(op_cfgs_visitor[cfg_index + 5], 'prop_bool', text = 'Right') # right
grids.prop(op_cfgs_visitor[cfg_index + 3], 'prop_bool', text = 'Back') # back
grids.prop(op_cfgs_visitor[cfg_index + 1], 'prop_bool', text = 'Bottom') # bottom
grids.separator()
# show extra transform props
# forcely order that each one are placed horizontally
layout.label(text = "Extra Transform:")
layout.label(text = "Extra Transform")
# translation
layout.label(text = 'Translation')
hbox_layout: bpy.types.UILayout = layout.row()
@ -285,7 +294,8 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
cop = layout.operator(
cls.bl_idname,
text = _g_EnumHelper_BmeStructType.get_bme_showcase_title(ident),
icon_value = _g_EnumHelper_BmeStructType.get_bme_showcase_icon(ident)
icon_value = _g_EnumHelper_BmeStructType.get_bme_showcase_icon(ident),
text_ctxt = UTIL_translation.build_prototype_showcase_context(ident)
)
# and assign its init type value
cop.bme_struct_type = _g_EnumHelper_BmeStructType.to_selection(ident)

View File

@ -8,10 +8,11 @@ from . import PROP_ballance_element, PROP_virtools_group, PROP_ballance_map_info
class ComponentSectorParam():
component_sector: bpy.props.IntProperty(
name = "Sector",
description = "Define which sector the object will be grouped in",
description = "The sector which this component will be grouped in.",
min = 1, max = 999,
soft_min = 1, soft_max = 8,
default = 1,
translation_context = 'BBP/OP_ADDS_component.ComponentSectorParam/property'
) # type: ignore
def general_get_component_sector(self) -> int:
@ -23,10 +24,11 @@ class ComponentSectorParam():
class ComponentCountParam():
component_count: bpy.props.IntProperty(
name = "Count",
description = "The count of components you want to generate",
description = "The count of components which you want to generate",
min = 1, max = 64,
soft_min = 1, soft_max = 32,
default = 1,
translation_context = 'BBP/OP_ADDS_component.ComponentCountParam/property'
) # type: ignore
def general_get_component_count(self) -> int:
@ -192,15 +194,17 @@ _g_EnumHelper_Component: UTIL_functions.EnumPropHelper = UTIL_functions.EnumProp
)
class BBP_OT_add_component(bpy.types.Operator, ComponentSectorParam):
"""Add Component"""
"""Add ordinary Component"""
bl_idname = "bbp.add_component"
bl_label = "Add Component"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_add_component'
component_type: bpy.props.EnumProperty(
name = "Type",
description = "This component type",
description = "The type of this component.",
items = _g_EnumHelper_Component.generate_items(),
translation_context = 'BBP_OT_add_component/property'
) # type: ignore
def invoke(self, context, event):
@ -241,7 +245,8 @@ class BBP_OT_add_component(bpy.types.Operator, ComponentSectorParam):
cop = layout.operator(
BBP_OT_add_component.bl_idname, text = item_name,
icon_value = UTIL_icons_manager.get_component_icon(item_name)
icon_value = UTIL_icons_manager.get_component_icon(item_name),
translate = False
)
cop.component_type = _g_EnumHelper_Component.to_selection(item)
@ -254,6 +259,7 @@ class BBP_OT_add_nong_extra_point(bpy.types.Operator, ComponentSectorParam, Comp
bl_idname = "bbp.add_nong_extra_point"
bl_label = "Nong Extra Point"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_nong_extra_point'
def draw(self, context):
layout = self.layout
@ -289,6 +295,7 @@ class BBP_OT_add_nong_ventilator(bpy.types.Operator, ComponentSectorParam, Compo
bl_idname = "bbp.add_nong_ventilator"
bl_label = "Nong Ventilator"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_nong_ventilator'
ventilator_count_source: bpy.props.EnumProperty(
name = "Ventilator Count Source",
@ -296,6 +303,7 @@ class BBP_OT_add_nong_ventilator(bpy.types.Operator, ComponentSectorParam, Compo
('DEFINED', "Predefined", "Pre-defined ventilator count."),
('CUSTOM', "Custom", "User specified ventilator count."),
],
translation_context = 'BBP_OT_add_nong_ventilator/property'
) # type: ignore
preset_vetilator_count: bpy.props.EnumProperty(
@ -307,6 +315,7 @@ class BBP_OT_add_nong_ventilator(bpy.types.Operator, ComponentSectorParam, Compo
('WOOD', 'Wood', 'The ventilator count (6) can push wood ball up.'),
('STONE', 'Stone', 'The ventilator count (32) can push stone ball up.'),
],
translation_context = 'BBP_OT_add_nong_ventilator/property'
) # type: ignore
def draw(self, context):
@ -363,6 +372,7 @@ class BBP_OT_add_tilting_block_series(bpy.types.Operator, ComponentSectorParam,
bl_idname = "bbp.add_tilting_block_series"
bl_label = "Tilting Block Series"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_tilting_block_series'
component_span: bpy.props.FloatProperty(
name = "Span",
@ -370,6 +380,7 @@ class BBP_OT_add_tilting_block_series(bpy.types.Operator, ComponentSectorParam,
min = 0.0, max = 100.0,
soft_min = 0.0, soft_max = 12.0,
default = 6.0022,
translation_context = 'BBP_OT_add_tilting_block_series/property'
) # type: ignore
def draw(self, context):
@ -407,6 +418,7 @@ class BBP_OT_add_swing_series(bpy.types.Operator, ComponentSectorParam, Componen
bl_idname = "bbp.add_swing_series"
bl_label = "Swing Series"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_swing_series'
component_span: bpy.props.FloatProperty(
name = "Span",
@ -414,12 +426,14 @@ class BBP_OT_add_swing_series(bpy.types.Operator, ComponentSectorParam, Componen
min = 0.0, max = 100.0,
soft_min = 0.0, soft_max = 30.0,
default = 15.0,
translation_context = 'BBP_OT_add_swing_series/property'
) # type: ignore
staggered_swing: bpy.props.BoolProperty(
name = 'Staggered',
description = 'Whether place Swing staggered. Staggered Swing accept any ball however Non-Staggered Swing only accept Wood and Paper ball.',
default = True
default = True,
translation_context = 'BBP_OT_add_swing_series/property'
) # type: ignore
def draw(self, context):
@ -465,6 +479,7 @@ class BBP_OT_add_ventilator_series(bpy.types.Operator, ComponentSectorParam, Com
bl_idname = "bbp.add_ventilator_series"
bl_label = "Ventilator Series"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_ventilator_series'
component_translation: bpy.props.FloatVectorProperty(
name = "Delta Vector",
@ -473,6 +488,7 @@ class BBP_OT_add_ventilator_series(bpy.types.Operator, ComponentSectorParam, Com
min = 0.0, max = 100.0,
soft_min = 0.0, soft_max = 50.0,
default = (0.0, 0.0, 15.0),
translation_context = 'BBP_OT_add_ventilator_series/property'
) # type: ignore
def draw(self, context):
@ -514,6 +530,7 @@ class BBP_OT_add_sector_component_pair(bpy.types.Operator, ComponentSectorParam)
bl_idname = "bbp.add_sector_component_pair"
bl_label = "Sector Pair"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_add_sector_component_pair'
def __get_checkpoint(self) -> tuple[PROP_ballance_element.BallanceElementType, int]:
if self.general_get_component_sector() == 1:

View File

@ -46,7 +46,8 @@ class SharedExtraTransform():
size = 3,
subtype = 'TRANSLATION',
step = 50, # same step as the float entry of BBP_PG_bme_adder_cfgs
default = (0.0, 0.0, 0.0)
default = (0.0, 0.0, 0.0),
translation_context = 'BBP/OP_ADDS_rail.SharedExtraTransform/property'
) # type: ignore
extra_rotation: bpy.props.FloatVectorProperty(
name = "Extra Rotation",
@ -54,7 +55,8 @@ class SharedExtraTransform():
size = 3,
subtype = 'EULER',
step = 100, # We choosen 100, mean 1. Sync with property window.
default = (0.0, 0.0, 0.0)
default = (0.0, 0.0, 0.0),
translation_context = 'BBP/OP_ADDS_rail.SharedExtraTransform/property'
) # type: ignore
def draw_extra_transform_input(self, layout: bpy.types.UILayout) -> None:
@ -91,6 +93,7 @@ class SharedRailSectionInputProperty():
('RAIL', "Rail", ""),
],
default = 'RAIL',
translation_context = 'BBP/OP_ADDS_rail.SharedRailSectionInputProperty/property'
) # type: ignore
def draw_rail_section_input(self, layout: bpy.types.UILayout) -> None:
@ -109,13 +112,15 @@ class SharedRailCapInputProperty():
rail_start_cap: bpy.props.BoolProperty(
name = 'Start Cap',
description = 'Whether this rail should have cap at start terminal.',
default = False
default = False,
translation_context = 'BBP/OP_ADDS_rail.SharedRailCapInputProperty/property'
) # type: ignore
rail_end_cap: bpy.props.BoolProperty(
name = 'End Cap',
description = 'Whether this rail should have cap at end terminal.',
default = False
default = False,
translation_context = 'BBP/OP_ADDS_rail.SharedRailCapInputProperty/property'
) # type: ignore
def draw_rail_cap_input(self, layout: bpy.types.UILayout) -> None:
@ -140,7 +145,8 @@ class SharedStraightRailInputProperty():
default = 5.0,
min = 0,
step = 50, # same unit as BME Struct
unit = 'LENGTH'
unit = 'LENGTH',
translation_context = 'BBP/OP_ADDS_rail.SharedStraightRailInputProperty/property'
) # type: ignore
def draw_straight_rail_input(self, layout: bpy.types.UILayout) -> None:
@ -159,6 +165,7 @@ class SharedScrewRailInputProperty():
description = "The segment count per iteration. More segment, more smooth but lower performance.",
default = 28,
min = 1,
translation_context = 'BBP/OP_ADDS_rail.SharedScrewRailInputProperty/property'
) # type: ignore
rail_screw_radius: bpy.props.FloatProperty(
@ -166,25 +173,29 @@ class SharedScrewRailInputProperty():
description = "The screw radius.",
default = 5,
min = 0,
unit = 'LENGTH'
unit = 'LENGTH',
translation_context = 'BBP/OP_ADDS_rail.SharedScrewRailInputProperty/property'
) # type: ignore
rail_screw_flip_x: bpy.props.BoolProperty(
name = 'Flip X',
description = 'Whether flip this rail with X axis',
default = False
default = False,
translation_context = 'BBP/OP_ADDS_rail.SharedScrewRailInputProperty/property'
) # type: ignore
rail_screw_flip_y: bpy.props.BoolProperty(
name = 'Flip Y',
description = 'Whether flip this rail with Y axis',
default = False
default = False,
translation_context = 'BBP/OP_ADDS_rail.SharedScrewRailInputProperty/property'
) # type: ignore
rail_screw_flip_z: bpy.props.BoolProperty(
name = 'Flip Z',
description = 'Whether flip this rail with Z axis',
default = False
default = False,
translation_context = 'BBP/OP_ADDS_rail.SharedScrewRailInputProperty/property'
) # type: ignore
def draw_screw_rail_input(self, layout: bpy.types.UILayout) -> None:
@ -220,6 +231,7 @@ class BBP_OT_add_rail_section(SharedRailSectionInputProperty, bpy.types.Operator
bl_idname = "bbp.add_rail_section"
bl_label = "Rail Section"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_rail_section'
def execute(self, context):
UTIL_rail_creator.rail_creator_wrapper(
@ -240,6 +252,7 @@ class BBP_OT_add_transition_section(bpy.types.Operator):
bl_idname = "bbp.add_transition_section"
bl_label = "Transition Section"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_transition_section'
def execute(self, context):
UTIL_rail_creator.rail_creator_wrapper(
@ -257,6 +270,7 @@ class BBP_OT_add_straight_rail(SharedExtraTransform, SharedRailSectionInputPrope
bl_idname = "bbp.add_straight_rail"
bl_label = "Straight Rail"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_straight_rail'
def execute(self, context):
UTIL_rail_creator.rail_creator_wrapper(
@ -285,6 +299,7 @@ class BBP_OT_add_transition_rail(SharedExtraTransform, SharedRailCapInputPropert
bl_idname = "bbp.add_transition_rail"
bl_label = "Transition Rail"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_transition_rail'
def execute(self, context):
UTIL_rail_creator.rail_creator_wrapper(
@ -312,6 +327,7 @@ class BBP_OT_add_side_rail(SharedExtraTransform, SharedRailCapInputProperty, Sha
bl_idname = "bbp.add_side_rail"
bl_label = "Side Rail"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_side_rail'
side_rail_type: bpy.props.EnumProperty(
name = "Side Type",
@ -321,6 +337,7 @@ class BBP_OT_add_side_rail(SharedExtraTransform, SharedRailCapInputProperty, Sha
('STONE', "Stone Specific", "The side rail which also allow stone ball passed."),
],
default = 'NORMAL',
translation_context = 'BBP_OT_add_side_rail/property'
) # type: ignore
def execute(self, context):
@ -351,6 +368,7 @@ class BBP_OT_add_arc_rail(SharedExtraTransform, SharedRailSectionInputProperty,
bl_idname = "bbp.add_arc_rail"
bl_label = "Arc Rail"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_arc_rail'
rail_screw_angle: bpy.props.FloatProperty(
name = "Angle",
@ -358,6 +376,7 @@ class BBP_OT_add_arc_rail(SharedExtraTransform, SharedRailSectionInputProperty,
default = math.radians(90),
min = 0, max = math.radians(360),
subtype = 'ANGLE',
translation_context = 'BBP_OT_add_arc_rail/property'
) # type: ignore
def execute(self, context):
@ -392,12 +411,14 @@ class BBP_OT_add_spiral_rail(SharedExtraTransform, SharedRailCapInputProperty, S
bl_idname = "bbp.add_spiral_rail"
bl_label = "Spiral Rail"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_spiral_rail'
rail_screw_screw: bpy.props.FloatProperty(
name = "Screw",
description = "The increased height in each iteration. Minus height also is accepted.",
default = c_SpiralRailScrew,
unit = 'LENGTH'
unit = 'LENGTH',
translation_context = 'BBP_OT_add_spiral_rail/property'
) # type: ignore
rail_screw_iterations: bpy.props.IntProperty(
@ -405,6 +426,7 @@ class BBP_OT_add_spiral_rail(SharedExtraTransform, SharedRailCapInputProperty, S
description = "Indicate how many layers of this spiral rail should be generated.",
default = 1,
min = 1,
translation_context = 'BBP_OT_add_spiral_rail/property'
) # type: ignore
def execute(self, context):
@ -439,6 +461,7 @@ class BBP_OT_add_side_spiral_rail(SharedExtraTransform, SharedRailSectionInputPr
bl_idname = "bbp.add_side_spiral_rail"
bl_label = "Side Spiral Rail"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_add_side_spiral_rail'
rail_screw_iterations: bpy.props.IntProperty(
name = "Iterations",
@ -447,6 +470,7 @@ class BBP_OT_add_side_spiral_rail(SharedExtraTransform, SharedRailSectionInputPr
# at least 2 ietrations can create 1 useful side spiral rail.
# becuase side spiral rail is edge shared.
min = 2,
translation_context = 'BBP_OT_add_side_spiral_rail/property'
) # type: ignore
def execute(self, context):

View File

@ -6,19 +6,19 @@ class BBP_OT_export_bmfile(bpy.types.Operator, UTIL_file_browser.ExportBmxFile,
bl_idname = "bbp.export_bmfile"
bl_label = "Export BM (Ballance Map) File"
bl_options = {'PRESET'}
bl_translation_context = 'BBP_OT_export_bmfile'
@classmethod
def poll(cls, context):
return PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder()
def execute(self, context):
self.report({'ERROR'}, 'This function not supported yet.')
self.report({'ERROR'}, 'This feature is 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(context, layout.box())
def register() -> None:

View File

@ -11,6 +11,7 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
bl_idname = "bbp.export_virtools"
bl_label = "Export Virtools File"
bl_options = {'PRESET'}
bl_translation_context = 'BBP_OT_export_virtools'
@classmethod
def poll(cls, context):

View File

@ -6,19 +6,19 @@ class BBP_OT_import_bmfile(bpy.types.Operator, UTIL_file_browser.ImportBmxFile,
bl_idname = "bbp.import_bmfile"
bl_label = "Import BM (Ballance Map) File"
bl_options = {'PRESET', 'UNDO'}
bl_translation_context = 'BBP_OT_import_bmfile'
@classmethod
def poll(cls, context):
return PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder()
def execute(self, context):
self.report({'ERROR'}, 'This function not supported yet.')
self.report({'ERROR'}, 'This feature is not supported yet.')
# 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:

View File

@ -11,6 +11,7 @@ class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtool
bl_idname = "bbp.import_virtools"
bl_label = "Import Virtools File"
bl_options = {'PRESET', 'UNDO'}
bl_translation_context = 'BBP_OT_import_virtools'
@classmethod
def poll(cls, context):

View File

@ -5,8 +5,9 @@ from . import PROP_virtools_material, PROP_preferences
class BBP_OT_fix_all_material(bpy.types.Operator):
"""Fix All Materials by Its Referred Ballance Texture Name."""
bl_idname = "bbp.fix_all_material"
bl_label = "Fix Material"
bl_label = "Fix All Materials"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_fix_all_material'
@classmethod
def poll(cls, context):

View File

@ -43,24 +43,29 @@ class BBP_PG_legacy_align_history(bpy.types.PropertyGroup):
align_x: bpy.props.BoolProperty(
name = "X Position",
default = False,
translation_context = 'BBP_PG_legacy_align_history/property'
) # type: ignore
align_y: bpy.props.BoolProperty(
name = "Y Position",
default = False,
translation_context = 'BBP_PG_legacy_align_history/property'
) # type: ignore
align_z: bpy.props.BoolProperty(
name = "Z Position",
default = False,
translation_context = 'BBP_PG_legacy_align_history/property'
) # type: ignore
current_align_mode: bpy.props.EnumProperty(
name = "Current Object (Active Object)",
items = _g_EnumHelper_AlignMode.generate_items(),
default = _g_EnumHelper_AlignMode.to_selection(AlignMode.AxisCenter),
translation_context = 'BBP_PG_legacy_align_history/property'
) # type: ignore
target_align_mode: bpy.props.EnumProperty(
name = "Target Objects (Other Objects)",
items = _g_EnumHelper_AlignMode.generate_items(),
default = _g_EnumHelper_AlignMode.to_selection(AlignMode.AxisCenter),
translation_context = 'BBP_PG_legacy_align_history/property'
) # type: ignore
#endregion
@ -70,6 +75,7 @@ class BBP_OT_legacy_align(bpy.types.Operator):
bl_idname = "bbp.legacy_align"
bl_label = "3ds Max Align"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_legacy_align'
# the updator for apply flag value
def apply_flag_updated(self, context):
@ -111,17 +117,20 @@ class BBP_OT_legacy_align(bpy.types.Operator):
options = {'HIDDEN', 'SKIP_SAVE'},
default = True, # default True value to make it as a "light" button, not a grey one.
update = apply_flag_updated,
translation_context = 'BBP_OT_legacy_align/property'
) # type: ignore
recursive_hinder: bpy.props.BoolProperty(
name = "Recursive Hinder",
description = "An internal flag to prevent the loop calling to apply_flags's updator.",
# TR: internal used property should not have name and description, otherwise it will be translated.
# name = "Recursive Hinder",
# description = "An internal flag to prevent the loop calling to apply_flags's updator.",
options = {'HIDDEN', 'SKIP_SAVE'},
default = False,
default = False
) # type: ignore
align_history : bpy.props.CollectionProperty(
name = "Historys",
description = "Align history.",
type = BBP_PG_legacy_align_history,
# TR: same reason for no name and description.
# name = "Historys",
# description = "Align history.",
type = BBP_PG_legacy_align_history
) # type: ignore
@classmethod

View File

@ -7,6 +7,7 @@ class BBP_OT_regulate_objects_name(bpy.types.Operator):
bl_idname = "bbp.regulate_objects_name"
bl_label = "Regulate Objects Name"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_regulate_objects_name'
def invoke(self, context, event):
wm = context.window_manager
@ -24,6 +25,7 @@ class BBP_OT_auto_grouping(bpy.types.Operator):
bl_idname = "bbp.auto_grouping"
bl_label = "Auto Grouping"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_auto_grouping'
def invoke(self, context, event):
wm = context.window_manager
@ -41,6 +43,7 @@ class BBP_OT_convert_to_imengyu(bpy.types.Operator):
bl_idname = "bbp.convert_to_imengyu"
bl_label = "Convert to Imengyu"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_convert_to_imengyu'
def invoke(self, context, event):
wm = context.window_manager

View File

@ -7,6 +7,7 @@ class BBP_OT_snoop_group_then_to_mesh(bpy.types.Operator):
bl_idname = "bbp.snoop_group_then_to_mesh"
bl_label = "Snoop Group then to Mesh"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_snoop_group_then_to_mesh'
@classmethod
def poll(cls, context):

View File

@ -32,12 +32,14 @@ class BBP_OT_select_object_by_virtools_group(bpy.types.Operator, PROP_virtools_g
bl_idname = "bbp.select_object_by_virtools_group"
bl_label = "Select by Virtools Group"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_select_object_by_virtools_group'
selection_mode: bpy.props.EnumProperty(
name = "Mode",
description = "Selection mode",
items = _g_EnumHelper_SelectMode.generate_items(),
default = _g_EnumHelper_SelectMode.to_selection(SelectMode.Intersect)
default = _g_EnumHelper_SelectMode.to_selection(SelectMode.Intersect),
translation_context = 'BBP_OT_select_object_by_virtools_group/property'
) # type: ignore
@classmethod
@ -122,6 +124,7 @@ class BBP_OT_add_objects_virtools_group(bpy.types.Operator, PROP_virtools_group.
bl_idname = "bbp.add_objects_virtools_group"
bl_label = "Grouping Objects"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_add_objects_virtools_group'
@classmethod
def poll(cls, context):
@ -147,6 +150,7 @@ class BBP_OT_rm_objects_virtools_group(bpy.types.Operator, PROP_virtools_group.S
bl_idname = "bbp.rm_objects_virtools_group"
bl_label = "Ungrouping Objects"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_rm_objects_virtools_group'
@classmethod
def poll(cls, context):
@ -172,6 +176,7 @@ class BBP_OT_clear_objects_virtools_group(bpy.types.Operator):
bl_idname = "bbp.clear_objects_virtools_group"
bl_label = "Clear All Groups"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_clear_objects_virtools_group'
@classmethod
def poll(cls, context):

View File

@ -78,6 +78,7 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
bl_idname = "bbp.flatten_uv"
bl_label = "Flatten UV"
bl_options = {'REGISTER', 'UNDO'}
bl_translation_context = 'BBP_OT_flatten_uv'
reference_edge: bpy.props.IntProperty(
name = "Reference Edge",
@ -85,6 +86,7 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
min = 0,
soft_min = 0, soft_max = 3,
default = 0,
translation_context = 'BBP_OT_flatten_uv/property'
) # type: ignore
flatten_method: bpy.props.EnumProperty(
@ -94,7 +96,8 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
('FLOOR', "Floor", "Floor specific flatten UV."),
('WOOD', "Wood", "Wood specific flatten UV."),
],
default = 'RAW'
default = 'RAW',
translation_context = 'BBP_OT_flatten_uv/property'
) # type: ignore
scale_mode: bpy.props.EnumProperty(
@ -103,7 +106,8 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
('NUM', "Scale Size", "Scale UV with specific number."),
('REF', "Ref. Point", "Scale UV with Reference Point feature."),
],
default = 'NUM'
default = 'NUM',
translation_context = 'BBP_OT_flatten_uv/property'
) # type: ignore
scale_number: bpy.props.FloatProperty(
@ -114,6 +118,7 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
default = 5.0,
step = 10,
precision = 1,
translation_context = 'BBP_OT_flatten_uv/property'
) # type: ignore
reference_point: bpy.props.IntProperty(
@ -122,6 +127,7 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
min = 2, # 0 and 1 is invalid. we can not order the reference edge to be set on the outside of uv axis
soft_min = 2, soft_max = 3,
default = 2,
translation_context = 'BBP_OT_flatten_uv/property'
) # type: ignore
reference_uv: bpy.props.FloatProperty(
@ -131,6 +137,7 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
default = 0.5,
step = 10,
precision = 2,
translation_context = 'BBP_OT_flatten_uv/property'
) # type: ignore
@classmethod

View File

@ -8,10 +8,11 @@ class BBP_OT_rail_uv(bpy.types.Operator):
bl_idname = "bbp.rail_uv"
bl_label = "Rail UV"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_rail_uv'
@classmethod
def poll(cls, context):
return _check_rail_target()
return _check_rail_target(context)
def invoke(self, context, event):
wm: bpy.types.WindowManager = context.window_manager
@ -26,7 +27,13 @@ class BBP_OT_rail_uv(bpy.types.Operator):
return {'CANCELLED'}
# apply rail uv
_create_rail_uv(_get_rail_target(), mtl)
(has_invalid_objs, meshes) = _get_rail_target(context)
_create_rail_uv(meshes, mtl)
# show warning if there is invalid objects
if has_invalid_objs:
self.report({'WARNING'}, 'Some objects are invalid for this operation. See Console for more details.')
return {'FINISHED'}
def draw(self, context):
@ -36,8 +43,8 @@ class BBP_OT_rail_uv(bpy.types.Operator):
#region Real Worker Functions
def _check_rail_target() -> bool:
for obj in bpy.context.selected_objects:
def _check_rail_target(context: bpy.types.Context) -> bool:
for obj in context.selected_objects:
if obj.type != 'MESH':
continue
if obj.mode != 'OBJECT':
@ -47,11 +54,11 @@ def _check_rail_target() -> bool:
return True
return False
def _get_rail_target() -> typing.Iterable[bpy.types.Mesh]:
def _get_rail_target(context: bpy.types.Context) -> tuple[bool, typing.Iterable[bpy.types.Mesh]]:
# collect objects
meshes: list[bpy.types.Mesh] = []
error_objname: list[str] = []
for obj in bpy.context.selected_objects:
for obj in context.selected_objects:
if obj.type != 'MESH':
error_objname.append(obj.name)
continue
@ -62,28 +69,21 @@ def _get_rail_target() -> typing.Iterable[bpy.types.Mesh]:
error_objname.append(obj.name)
continue
meshes.append(obj.data)
meshes.append(typing.cast(bpy.types.Mesh, obj.data))
# display warning window if necessary
if len(error_objname) != 0:
# show dialog
UTIL_functions.message_box(
("Some objects is not processed, see Console for more infos.", ),
"Object Type Warning",
UTIL_icons_manager.BlenderPresetIcons.Warning.value
)
has_invalid_objs = len(error_objname) != 0
if has_invalid_objs:
# output to console
print('')
print('=====')
print('========== Rail UV Report ==========')
print('Following objects are not processed by Rail UV because they do not meet the requirements of Rail UV.')
for objname in error_objname:
print(objname)
print('=====')
print('')
# return valid
return meshes
return (has_invalid_objs, meshes)
def _tt_reflection_mapping_compute(
point_: UTIL_virtools_types.ConstVxVector3,

View File

@ -96,12 +96,14 @@ def is_ballance_element(name: str) -> bool:
class BBP_PG_ballance_element(bpy.types.PropertyGroup):
element_id: bpy.props.IntProperty(
name = "Element Id",
default = 0
default = 0,
translation_context = 'BBP_PG_ballance_element/property'
) # type: ignore
mesh_ptr: bpy.props.PointerProperty(
name = "Mesh",
type = bpy.types.Mesh
type = bpy.types.Mesh,
translation_context = 'BBP_PG_ballance_element/property'
) # type: ignore
def get_ballance_elements(scene: bpy.types.Scene) -> UTIL_functions.CollectionVisitor[BBP_PG_ballance_element]:
@ -322,6 +324,7 @@ class BBP_OT_reset_ballance_elements(bpy.types.Operator):
bl_idname = "bbp.reset_ballance_elements"
bl_label = "Reset Ballance Elements"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_reset_ballance_elements'
@classmethod
def poll(cls, context):
@ -331,11 +334,7 @@ class BBP_OT_reset_ballance_elements(bpy.types.Operator):
with BallanceElementsHelper(context.scene) as helper:
helper.reset_elements()
# show a window to let user know, not silence
UTIL_functions.message_box(
('Reset OK.', ),
"Reset Result",
UTIL_icons_manager.BlenderPresetIcons.Info.value
)
self.report({'INFO'}, 'Reset Ballance elements successfully.')
return {'FINISHED'}
class BBP_PT_ballance_elements(bpy.types.Panel):
@ -345,6 +344,7 @@ class BBP_PT_ballance_elements(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
bl_translation_context = 'BBP_PT_ballance_elements'
@classmethod
def poll(cls, context):

View File

@ -22,7 +22,8 @@ class BBP_PG_ballance_map_info(bpy.types.PropertyGroup):
default = 1,
max = 999, min = 1,
soft_max = 8, soft_min = 1,
step = 1
step = 1,
translation_context = 'BBP_PG_ballance_map_info/property'
) # type: ignore
def get_ballance_map_info(scene: bpy.types.Scene) -> BBP_PG_ballance_map_info:
@ -51,6 +52,7 @@ class BBP_PT_ballance_map_info(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
bl_translation_context = 'BBP_PT_ballance_map_info'
@classmethod
def poll(cls, context):

View File

@ -77,12 +77,14 @@ _g_BMEMaterialPresets: dict[str, _BMEMaterialPreset] = {
class BBP_PG_bme_material(bpy.types.PropertyGroup):
bme_material_name: bpy.props.StringProperty(
name = "Name",
default = ""
default = "",
translation_context = 'BBP_PG_bme_material/property'
) # type: ignore
material_ptr: bpy.props.PointerProperty(
name = "Material",
type = bpy.types.Material
type = bpy.types.Material,
translation_context = 'BBP_PG_bme_material/property'
) # type: ignore
def get_bme_materials(scene: bpy.types.Scene) -> UTIL_functions.CollectionVisitor[BBP_PG_bme_material]:
@ -175,6 +177,14 @@ class BMEMaterialsHelper():
self.__mMaterialMap[preset_name] = new_mtl
return new_mtl
def reset_materials(self) -> None:
if not self.is_valid():
raise UTIL_functions.BBPException('calling invalid BMEMaterialsHelper')
# load all items
for preset_name, mtl in self.__mMaterialMap.items():
_load_bme_material_preset(mtl, preset_name)
def __write_to_bme_materials(self) -> None:
mtls = get_bme_materials(self.__mAssocScene)
mtls.clear()
@ -194,28 +204,6 @@ class BMEMaterialsHelper():
# add into map
self.__mMaterialMap[item.bme_material_name] = item.material_ptr
def reset_bme_materials(scene: bpy.types.Scene) -> None:
invalid_idx: list[int] = []
mtls = get_bme_materials(scene)
# re-load all elements
index: int = 0
item: BBP_PG_bme_material
for item in mtls:
# load or record invalid entry
if item.material_ptr is None:
invalid_idx.append(index)
else:
_load_bme_material_preset(item.material_ptr, item.bme_material_name)
# inc counter
index += 1
# remove invalid one with reversed order
invalid_idx.reverse()
for idx in invalid_idx:
mtls.remove(idx)
#endregion
#region BME Materials Representation
@ -233,19 +221,17 @@ class BBP_OT_reset_bme_materials(bpy.types.Operator):
bl_idname = "bbp.reset_bme_materials"
bl_label = "Reset BME Materials"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_reset_bme_materials'
@classmethod
def poll(cls, context):
return context.scene is not None
def execute(self, context):
reset_bme_materials(context.scene)
with BMEMaterialsHelper(context.scene) as helper:
helper.reset_materials()
# show a window to let user know, not silence
UTIL_functions.message_box(
('Reset OK.', ),
"Reset Result",
UTIL_icons_manager.BlenderPresetIcons.Info.value
)
self.report({'INFO'}, 'Reset BME materials successfully.')
return {'FINISHED'}
class BBP_PT_bme_materials(bpy.types.Panel):
@ -255,6 +241,7 @@ class BBP_PT_bme_materials(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
bl_translation_context = 'BBP_PT_bme_materials'
@classmethod
def poll(cls, context):

View File

@ -22,18 +22,20 @@ class BBPPreferences(bpy.types.AddonPreferences):
ballance_texture_folder: bpy.props.StringProperty(
name = "Ballance Texture Folder",
description = "The path to folder which will be used by this plugin to get external Ballance texture.",
subtype='DIR_PATH',
subtype = 'DIR_PATH',
default = RawPreferences.cBallanceTextureFolder,
translation_context = 'BBPPreferences/property'
) # type: ignore
no_component_collection: bpy.props.StringProperty(
name = "No Component Collection",
description = "(Import) The object which stored in this collectiion will not be saved as component. (Export) All forced no component objects will be stored in this collection",
description = "When importing, it is the name of collection where objects store will not be saved as component. When exporting, all forced no component objects will be stored in this name represented collection",
default = RawPreferences.cNoComponentCollection,
translation_context = 'BBPPreferences/property'
) # type: ignore
def draw(self, context):
layout = self.layout
layout: bpy.types.UILayout = self.layout
row = layout.row()
col = row.column()

View File

@ -12,7 +12,8 @@ from . import UTIL_functions, UTIL_virtools_types
class BBP_PG_bmap_encoding(bpy.types.PropertyGroup):
encoding: bpy.props.StringProperty(
name = "Encoding",
default = ""
default = "",
translation_context = 'BBP_PG_bmap_encoding/property'
) # type: ignore
class BBP_UL_bmap_encoding(bpy.types.UIList):
@ -24,23 +25,25 @@ class BBP_PG_ptrprop_resolver(bpy.types.PropertyGroup):
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(
type = bpy.types.Collection,
name = "Collection",
description = "The collection exported. Nested collections allowed."
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(
type = bpy.types.Object,
name = "Object",
description = "The object exported"
description = "The object exported",
type = bpy.types.Object,
translation_context = 'BBP_PG_ptrprop_resolver/property'
) # type: ignore
ioport_encodings: bpy.props.CollectionProperty(
type = BBP_PG_bmap_encoding
) # 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
@ -62,6 +65,7 @@ class BBP_OT_add_ioport_encodings(bpy.types.Operator):
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:
@ -77,6 +81,7 @@ class BBP_OT_rm_ioport_encodings(bpy.types.Operator):
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:
@ -100,6 +105,7 @@ class BBP_OT_up_ioport_encodings(bpy.types.Operator):
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:
@ -119,6 +125,7 @@ class BBP_OT_down_ioport_encodings(bpy.types.Operator):
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:
@ -138,6 +145,7 @@ class BBP_OT_clear_ioport_encodings(bpy.types.Operator):
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:

View File

@ -7,7 +7,8 @@ from . import UTIL_functions, UTIL_icons_manager
class BBP_PG_virtools_group(bpy.types.PropertyGroup):
group_name: bpy.props.StringProperty(
name = "Group Name",
default = ""
default = "",
translation_context = 'BBP_PG_virtools_group/property'
) # type: ignore
def get_virtools_groups(obj: bpy.types.Object) -> UTIL_functions.CollectionVisitor[BBP_PG_virtools_group]:
@ -251,18 +252,21 @@ class SharedGroupNameInputProperties():
('DEFINED', "Predefined", "Pre-defined group name."),
('CUSTOM', "Custom", "User specified group name."),
),
translation_context = 'BME/PROP_virtools_grourp.SharedGroupNameInputProperties/property'
) # type: ignore
preset_group_name: bpy.props.EnumProperty(
name = "Group Name",
description = "Pick vanilla Ballance group name.",
items = _g_EnumHelper_Group.generate_items(),
translation_context = 'BME/PROP_virtools_grourp.SharedGroupNameInputProperties/property'
) # type: ignore
custom_group_name: bpy.props.StringProperty(
name = "Custom Group Name",
description = "Input your custom group name.",
default = "",
translation_context = 'BME/PROP_virtools_grourp.SharedGroupNameInputProperties/property'
) # type: ignore
def draw_group_name_input(self, layout: bpy.types.UILayout) -> None:
@ -291,6 +295,7 @@ class BBP_OT_add_virtools_group(bpy.types.Operator, SharedGroupNameInputProperti
bl_idname = "bbp.add_virtools_groups"
bl_label = "Add to Virtools Groups"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_add_virtools_group'
@classmethod
def poll(cls, context: bpy.types.Context):
@ -315,6 +320,7 @@ class BBP_OT_rm_virtools_group(bpy.types.Operator):
bl_idname = "bbp.rm_virtools_groups"
bl_label = "Remove from Virtools Groups"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_rm_virtools_group'
## This class is slightly unique.
# Because we need get user selected group name first.
@ -347,6 +353,7 @@ class BBP_OT_clear_virtools_groups(bpy.types.Operator):
bl_idname = "bbp.clear_virtools_groups"
bl_label = "Clear Virtools Groups"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_clear_virtools_groups'
@classmethod
def poll(cls, context: bpy.types.Context):
@ -369,6 +376,7 @@ class BBP_PT_virtools_groups(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
bl_translation_context = 'BBP_PT_virtools_groups'
@classmethod
def poll(cls, context):

View File

@ -80,7 +80,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
name = "Type",
description = "The type of this light",
items = _g_Helper_VXLIGHT_TYPE.generate_items(),
default = _g_Helper_VXLIGHT_TYPE.to_selection(RawVirtoolsLight.cDefaultType)
default = _g_Helper_VXLIGHT_TYPE.to_selection(RawVirtoolsLight.cDefaultType),
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
light_color: bpy.props.FloatVectorProperty(
@ -90,7 +91,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = 1.0,
size = 3,
default = RawVirtoolsLight.cDefaultColor.to_const_rgb()
default = RawVirtoolsLight.cDefaultColor.to_const_rgb(),
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
constant_attenuation: bpy.props.FloatProperty(
@ -99,7 +101,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultConstantAttenuation
default = RawVirtoolsLight.cDefaultConstantAttenuation,
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
linear_attenuation: bpy.props.FloatProperty(
@ -108,7 +111,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultLinearAttenuation
default = RawVirtoolsLight.cDefaultLinearAttenuation,
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
quadratic_attenuation: bpy.props.FloatProperty(
@ -117,7 +121,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultQuadraticAttenuation
default = RawVirtoolsLight.cDefaultQuadraticAttenuation,
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
light_range: bpy.props.FloatProperty(
@ -126,7 +131,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = 200.0,
step = 100,
default = RawVirtoolsLight.cDefaultRange
default = RawVirtoolsLight.cDefaultRange,
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
hot_spot: bpy.props.FloatProperty(
@ -135,7 +141,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = math.radians(180),
subtype = 'ANGLE',
default = RawVirtoolsLight.cDefaultHotSpot
default = RawVirtoolsLight.cDefaultHotSpot,
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
falloff: bpy.props.FloatProperty(
@ -144,7 +151,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = math.radians(180),
subtype = 'ANGLE',
default = RawVirtoolsLight.cDefaultFalloff
default = RawVirtoolsLight.cDefaultFalloff,
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
falloff_shape: bpy.props.FloatProperty(
@ -153,7 +161,8 @@ class BBP_PG_virtools_light(bpy.types.PropertyGroup):
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultFalloffShape
default = RawVirtoolsLight.cDefaultFalloffShape,
translation_context = 'BBP_PG_virtools_light/property'
) # type: ignore
# Getter Setter and Applyer
@ -239,6 +248,7 @@ class BBP_OT_apply_virtools_light(bpy.types.Operator):
bl_idname = "bbp.apply_virtools_light"
bl_label = "Apply to Blender Light"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_apply_virtools_light'
@classmethod
def poll(cls, context):
@ -258,6 +268,7 @@ class BBP_PT_virtools_light(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data" # idk why blender use `data` as the light tab same as mesh.
bl_translation_context = 'BBP_PT_virtools_light'
@classmethod
def poll(cls, context):

View File

@ -132,7 +132,8 @@ class BBP_PG_virtools_material(bpy.types.PropertyGroup):
min = 0.0,
max = 1.0,
size = 3,
default = RawVirtoolsMaterial.cDefaultAmbient.to_const_rgb()
default = RawVirtoolsMaterial.cDefaultAmbient.to_const_rgb(),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
diffuse: bpy.props.FloatVectorProperty(
@ -142,7 +143,8 @@ class BBP_PG_virtools_material(bpy.types.PropertyGroup):
min = 0.0,
max = 1.0,
size = 4,
default = RawVirtoolsMaterial.cDefaultDiffuse.to_const_rgba()
default = RawVirtoolsMaterial.cDefaultDiffuse.to_const_rgba(),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
specular: bpy.props.FloatVectorProperty(
@ -152,7 +154,8 @@ class BBP_PG_virtools_material(bpy.types.PropertyGroup):
min = 0.0,
max = 1.0,
size = 3,
default = RawVirtoolsMaterial.cDefaultSpecular.to_const_rgb()
default = RawVirtoolsMaterial.cDefaultSpecular.to_const_rgb(),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
emissive: bpy.props.FloatVectorProperty(
@ -162,7 +165,8 @@ class BBP_PG_virtools_material(bpy.types.PropertyGroup):
min = 0.0,
max = 1.0,
size = 3,
default = RawVirtoolsMaterial.cDefaultEmissive.to_const_rgb()
default = RawVirtoolsMaterial.cDefaultEmissive.to_const_rgb(),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
specular_power: bpy.props.FloatProperty(
@ -170,13 +174,15 @@ class BBP_PG_virtools_material(bpy.types.PropertyGroup):
description = "Specular highlight power",
min = 0.0,
max = 100.0,
default = RawVirtoolsMaterial.cDefaultSpecularPower
default = RawVirtoolsMaterial.cDefaultSpecularPower,
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
texture: bpy.props.PointerProperty(
type = bpy.types.Image,
name = "Texture",
description = "Texture of the material"
description = "Texture of the material",
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
texture_border_color: bpy.props.FloatVectorProperty(
@ -186,89 +192,103 @@ class BBP_PG_virtools_material(bpy.types.PropertyGroup):
min = 0.0,
max = 1.0,
size = 4,
default = RawVirtoolsMaterial.cDefaultTextureBorderColor.to_const_rgba()
default = RawVirtoolsMaterial.cDefaultTextureBorderColor.to_const_rgba(),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
texture_blend_mode: bpy.props.EnumProperty(
name = "Texture Blend",
description = "Texture blend mode",
items = _g_Helper_VXTEXTURE_BLENDMODE.generate_items(),
default = _g_Helper_VXTEXTURE_BLENDMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureBlendMode)
default = _g_Helper_VXTEXTURE_BLENDMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureBlendMode),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
texture_min_mode: bpy.props.EnumProperty(
name = "Filter Min",
description = "Texture filter mode when the texture is minified",
items = _g_Helper_VXTEXTURE_FILTERMODE.generate_items(),
default = _g_Helper_VXTEXTURE_FILTERMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureMinMode)
default = _g_Helper_VXTEXTURE_FILTERMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureMinMode),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
texture_mag_mode: bpy.props.EnumProperty(
name = "Filter Mag",
description = "Texture filter mode when the texture is magnified",
items = _g_Helper_VXTEXTURE_FILTERMODE.generate_items(),
default = _g_Helper_VXTEXTURE_FILTERMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureMagMode)
default = _g_Helper_VXTEXTURE_FILTERMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureMagMode),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
texture_address_mode: bpy.props.EnumProperty(
name = "Address Mode",
description = "The address mode controls how the texture coordinates outside the range 0..1",
items = _g_Helper_VXTEXTURE_ADDRESSMODE.generate_items(),
default = _g_Helper_VXTEXTURE_ADDRESSMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureAddressMode)
default = _g_Helper_VXTEXTURE_ADDRESSMODE.to_selection(RawVirtoolsMaterial.cDefaultTextureAddressMode),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
source_blend: bpy.props.EnumProperty(
name = "Source Blend",
description = "Source blend factor",
items = _g_Helper_VXBLEND_MODE.generate_items(),
default = _g_Helper_VXBLEND_MODE.to_selection(RawVirtoolsMaterial.cDefaultSourceBlend)
default = _g_Helper_VXBLEND_MODE.to_selection(RawVirtoolsMaterial.cDefaultSourceBlend),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
dest_blend: bpy.props.EnumProperty(
name = "Destination Blend",
description = "Destination blend factor",
items = _g_Helper_VXBLEND_MODE.generate_items(),
default = _g_Helper_VXBLEND_MODE.to_selection(RawVirtoolsMaterial.cDefaultDestBlend)
default = _g_Helper_VXBLEND_MODE.to_selection(RawVirtoolsMaterial.cDefaultDestBlend),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
fill_mode: bpy.props.EnumProperty(
name = "Fill Mode",
description = "Fill mode",
items = _g_Helper_VXFILL_MODE.generate_items(),
default = _g_Helper_VXFILL_MODE.to_selection(RawVirtoolsMaterial.cDefaultFillMode)
default = _g_Helper_VXFILL_MODE.to_selection(RawVirtoolsMaterial.cDefaultFillMode),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
shade_mode: bpy.props.EnumProperty(
name = "Shade Mode",
description = "Shade mode",
items = _g_Helper_VXSHADE_MODE.generate_items(),
default = _g_Helper_VXSHADE_MODE.to_selection(RawVirtoolsMaterial.cDefaultShadeMode)
default = _g_Helper_VXSHADE_MODE.to_selection(RawVirtoolsMaterial.cDefaultShadeMode),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
enable_alpha_test: bpy.props.BoolProperty(
name = "Alpha Test",
description = "Whether the alpha test is enabled",
default = RawVirtoolsMaterial.cDefaultEnableAlphaTest
default = RawVirtoolsMaterial.cDefaultEnableAlphaTest,
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
enable_alpha_blend: bpy.props.BoolProperty(
name = "Blend",
description = "Whether alpha blending is enabled or not.",
default = RawVirtoolsMaterial.cDefaultEnableAlphaBlend
default = RawVirtoolsMaterial.cDefaultEnableAlphaBlend,
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
enable_perspective_correction: bpy.props.BoolProperty(
name = "Perspective Correction",
description = "Whether texture perspective correction is enabled",
default = RawVirtoolsMaterial.cDefaultEnablePerspectiveCorrection
default = RawVirtoolsMaterial.cDefaultEnablePerspectiveCorrection,
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
enable_z_write: bpy.props.BoolProperty(
name = "Z-Buffer Write",
description = "Whether writing in ZBuffer is enabled.",
default = RawVirtoolsMaterial.cDefaultEnableZWrite
default = RawVirtoolsMaterial.cDefaultEnableZWrite,
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
enable_two_sided: bpy.props.BoolProperty(
name = "Both Sided",
description = "Whether the material is both sided or not",
default = RawVirtoolsMaterial.cDefaultEnableTwoSided
default = RawVirtoolsMaterial.cDefaultEnableTwoSided,
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
alpha_ref: bpy.props.IntProperty(
@ -276,21 +296,24 @@ class BBP_PG_virtools_material(bpy.types.PropertyGroup):
description = "Alpha referential value",
min = 0,
max = 255,
default = RawVirtoolsMaterial.cDefaultAlphaRef
default = RawVirtoolsMaterial.cDefaultAlphaRef,
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
alpha_func: bpy.props.EnumProperty(
name = "Alpha Test Function",
description = "Alpha comparision function",
items = _g_Helper_VXCMPFUNC.generate_items(),
default = _g_Helper_VXCMPFUNC.to_selection(RawVirtoolsMaterial.cDefaultAlphaFunc)
default = _g_Helper_VXCMPFUNC.to_selection(RawVirtoolsMaterial.cDefaultAlphaFunc),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
z_func: bpy.props.EnumProperty(
name = "Z Compare Function",
description = "Z Comparison function",
items = _g_Helper_VXCMPFUNC.generate_items(),
default = _g_Helper_VXCMPFUNC.to_selection(RawVirtoolsMaterial.cDefaultZFunc)
default = _g_Helper_VXCMPFUNC.to_selection(RawVirtoolsMaterial.cDefaultZFunc),
translation_context = 'BBP_PG_virtools_material/property'
) # type: ignore
#region Getter Setter
@ -877,6 +900,7 @@ class BBP_OT_apply_virtools_material(bpy.types.Operator):
bl_idname = "bbp.apply_virtools_material"
bl_label = "Apply to Blender Material"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_apply_virtools_material'
@classmethod
def poll(cls, context):
@ -892,6 +916,7 @@ class BBP_OT_fix_single_material(bpy.types.Operator):
bl_idname = "bbp.fix_single_material"
bl_label = "Fix Material"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_fix_single_material'
@classmethod
def poll(cls, context):
@ -911,7 +936,7 @@ class BBP_OT_fix_single_material(bpy.types.Operator):
# if suc, apply to blender mtl and show info
if ret:
apply_to_blender_material(mtl)
self.report({'INFO'}, 'Fix done.')
self.report({'INFO'}, 'Fix material successfully.')
else:
# otherwise report warning
self.report({'WARNING'}, 'This material is not suit for fixer.')
@ -923,6 +948,7 @@ class BBP_OT_preset_virtools_material(bpy.types.Operator):
bl_idname = "bbp.preset_virtools_material"
bl_label = "Preset Virtools Material"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_preset_virtools_material'
preset_type: bpy.props.EnumProperty(
name = "Preset",
@ -957,6 +983,7 @@ class BBP_OT_direct_set_virtools_texture(bpy.types.Operator, UTIL_file_browser.I
bl_idname = "bbp.direct_set_virtools_texture"
bl_label = "Import and Assign Texture"
bl_options = {'UNDO'}
bl_translation_context = 'BBP_OT_direct_set_virtools_texture'
@classmethod
def poll(cls, context):
@ -1009,6 +1036,7 @@ class BBP_PT_virtools_material(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "material"
bl_translation_context = 'BBP_PT_virtools_material'
@classmethod
def poll(cls, context):

View File

@ -24,7 +24,8 @@ class BBP_PG_virtools_mesh(bpy.types.PropertyGroup):
name = "Lit Mode",
description = "Lighting mode of the mesh.",
items = _g_Helper_VXMESH_LITMODE.generate_items(),
default = _g_Helper_VXMESH_LITMODE.to_selection(RawVirtoolsMesh.cDefaultLitMode)
default = _g_Helper_VXMESH_LITMODE.to_selection(RawVirtoolsMesh.cDefaultLitMode),
translation_context = 'BBP_PG_virtools_mesh/property'
) # type: ignore
# Getter Setter
@ -54,6 +55,7 @@ class BBP_PT_virtools_mesh(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data" # idk why blender use `data` as the mesh tab.
bl_translation_context = 'BBP_PT_virtools_mesh'
@classmethod
def poll(cls, context):

View File

@ -29,14 +29,16 @@ class BBP_PG_virtools_texture(bpy.types.PropertyGroup):
name = "Save Options",
description = "When saving a composition textures or sprites can be kept as reference to external files or converted to a given format and saved inside the composition file.",
items = _g_Helper_CK_TEXTURE_SAVEOPTIONS.generate_items(),
default = _g_Helper_CK_TEXTURE_SAVEOPTIONS.to_selection(RawVirtoolsTexture.cDefaultSaveOptions)
default = _g_Helper_CK_TEXTURE_SAVEOPTIONS.to_selection(RawVirtoolsTexture.cDefaultSaveOptions),
translation_context = 'BBP_PG_virtools_texture/property'
) # type: ignore
video_format: bpy.props.EnumProperty(
name = "Video Format",
description = "The desired surface pixel format in video memory.",
items = _g_Helper_VX_PIXELFORMAT.generate_items(),
default = _g_Helper_VX_PIXELFORMAT.to_selection(RawVirtoolsTexture.cDefaultVideoFormat)
default = _g_Helper_VX_PIXELFORMAT.to_selection(RawVirtoolsTexture.cDefaultVideoFormat),
translation_context = 'BBP_PG_virtools_texture/property'
) # type: ignore
#region Virtools Texture Getter Setter

View File

@ -159,6 +159,7 @@ class ImportParams():
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process texture name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Current),
translation_context = 'BME/UTIL_ioport_shared.ImportParams/property'
) # type: ignore
material_conflict_strategy: bpy.props.EnumProperty(
@ -166,6 +167,7 @@ class ImportParams():
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process material name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
translation_context = 'BME/UTIL_ioport_shared.ImportParams/property'
) # type: ignore
mesh_conflict_strategy: bpy.props.EnumProperty(
@ -173,6 +175,7 @@ class ImportParams():
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process mesh name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
translation_context = 'BME/UTIL_ioport_shared.ImportParams/property'
) # type: ignore
light_conflict_strategy: bpy.props.EnumProperty(
@ -180,6 +183,7 @@ class ImportParams():
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process light name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
translation_context = 'BME/UTIL_ioport_shared.ImportParams/property'
) # type: ignore
object_conflict_strategy: bpy.props.EnumProperty(
@ -187,6 +191,7 @@ class ImportParams():
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process object name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
translation_context = 'BME/UTIL_ioport_shared.ImportParams/property'
) # type: ignore
def draw_import_params(self, layout: bpy.types.UILayout) -> None:
@ -240,6 +245,7 @@ class ExportParams():
('COLLECTION', "Collection", "Export a collection", 'OUTLINER_COLLECTION', 0),
('OBJECT', "Object", "Export an object", 'OBJECT_DATA', 1),
),
translation_context = 'BME/UTIL_ioport_shared.ExportParams/property'
) # type: ignore
def draw_export_params(self, context: bpy.types.Context, layout: bpy.types.UILayout) -> None:
@ -284,13 +290,15 @@ class VirtoolsParams():
name = "Global Texture Save Options",
description = "Decide how texture saved if texture is specified as Use Global as its Save Options.",
items = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.generate_items(),
default = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.to_selection(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_EXTERNAL)
default = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.to_selection(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_EXTERNAL),
translation_context = 'BME/UTIL_ioport_shared.VirtoolsParams/property'
) # type: ignore
use_compress: bpy.props.BoolProperty(
name="Use Compress",
description = "Whether use ZLib to compress result when saving composition.",
default = True,
translation_context = 'BME/UTIL_ioport_shared.VirtoolsParams/property'
) # type: ignore
compress_level: bpy.props.IntProperty(
@ -298,6 +306,7 @@ class VirtoolsParams():
description = "The ZLib compress level used by Virtools Engine when saving composition.",
min = 1, max = 9,
default = 5,
translation_context = 'BME/UTIL_ioport_shared.VirtoolsParams/property'
) # type: ignore
def draw_virtools_params(self, context: bpy.types.Context, layout: bpy.types.UILayout, is_importer: bool) -> None:
@ -344,6 +353,7 @@ class BallanceParams():
name="Successive Sector",
description = "Whether order exporter to use document specified sector count to make sure sector is successive.",
default = True,
translation_context = 'BME/UTIL_ioport_shared.BallanceParams/property'
) # type: ignore
def draw_ballance_params(self, layout: bpy.types.UILayout, is_importer: bool) -> None:

View File

@ -0,0 +1,87 @@
import bpy
#region Translation Contexts
## NOTE: Translation Priniciple
# Due to the shitty design of Blender I18N tools (I can't specify context for every translation entries and its static analyse is so bad),
# I will specify all context but I can't do anything if Blender throw my translation context away.
#
# BME module has its own context naming convention which make sure all configuration fields of prototypes are properly translated.
# This module also provide a corresponding function to compute these context string from given BME prototype name and the index of configuration fields.
#
# For BBP plugin self, there is a priniciple list which you should follow when providing translation context.
# - For operator, menu, panel and etc, set their `bl_translation_context` to their names, such as `BBP_OT_some_operator`
# - For property located in operator, menu, panel and etc, set their `translation_context` to corresponding class name,
# plus `/property` suffix, such as `BBP_OT_some_operator/property`.
# - For draw function located in operator, menu, panel and etc, set their `translation_context` to corresponding class name,
# plus `/draw` suffix, such as `BBP_OT_some_operator/draw`.
# - For property loacted in shared class (usually shared by multiple operators), set their `translation_context` to `BME/<MODULE_NAME>.<CLASS_NAME>/property`.
# `<MODULE_NAME>` is the module name (file name) where this class located. `<CLASS_NAME>` is the name of this class.
# For example, `BBP/some_module.some_class/property`
#
# Due to the shitty design, I can't find a way to add translation context for descrption field.
# So these description may collide with Blender official translation and thus not put in result file.
# I have no idea about this.
#
# Due to the shitty static analyse ability of Blender I18N plugin, all context should be written in literal,
# not the reference to other fields or the return value of some function.
# However for those strings, which originally should not be extracted by Blender I18N plugin, the way to get their context string is free.
#
#
# For the string given to Python `print()` which will be output in console,
# please use `bpy.app.translations.pgettext_rpt()` to get translation message because they are report.
# For the string given to `UTIL_functions.message_box()`, please use `bpy.app.translations.pgettext_iface` because they are UI elements.
#
# It seema that `bpy.app.translations.pgettext` function family has fatal error when extracting message with context
# (it will produce a correct one and a wrong one which just simply concat the message and its context. I don't know why).
#
#
# All translation annotation are started with `TR:`
#
# The universal translation context prefix for BBP_NG plugin.
CTX_BBP: str = 'BBP'
# The universal translation context prefix for BME module in BBP_NG plugin.
CTX_BBP_BME: str = CTX_BBP + '/BME'
def build_prototype_showcase_context(identifier: str) -> str:
"""
Build the context for getting the translation for BME prototype showcase title.
@param[in] identifier The identifier of this prototype.
@return The context for getting translation.
"""
return CTX_BBP_BME + '/' + identifier
def build_prototype_showcase_cfg_context(identifier: str, cfg_index: int) -> str:
"""
Build the context for getting the translation for BME prototype showcase configuration title or description.
@param[in] identifier The identifier of this prototype.
@param[in] cfg_index The index of this configuration in this prototype showcase.
@return The context for getting translation.
"""
return CTX_BBP_BME + f'/{identifier}/[{cfg_index}]'
#endregion
# ##### BEGIN AUTOGENERATED I18N SECTION #####
# NOTE: You can safely move around this auto-generated block (with the begin/end markers!),
# and edit the translations by hand.
# Just carefully respect the format of the tuple!
# Tuple of tuples:
# ((msgctxt, msgid), (sources, gen_comments), (lang, translation, (is_fuzzy, comments)), ...)
translations_tuple = ()
translations_dict = {}
for msg in translations_tuple:
key = msg[0]
for lang, trans, (is_fuzzy, comments) in msg[2:]:
if trans and not is_fuzzy:
translations_dict.setdefault(lang, {})[key] = trans
# ##### END AUTOGENERATED I18N SECTION #####
def register() -> None:
bpy.app.translations.register(__package__, translations_dict)
def unregister() -> None:
bpy.app.translations.unregister(__package__)

View File

@ -5,6 +5,8 @@ import bpy
import typing, collections
# reload if needed
# TODO: finish reload feature if needed.
# (reload script raise too much exceptions so I usually restart blender to test my plugin.)
if "bpy" in locals():
import importlib
@ -16,6 +18,7 @@ from . import UTIL_icons_manager
UTIL_icons_manager.register()
# then load other modules
from . import UTIL_translation
from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_virtools_light, PROP_virtools_group
from . import PROP_ballance_element, PROP_bme_material, PROP_ballance_map_info
from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools
@ -29,29 +32,31 @@ from . import OP_OBJECT_legacy_align, OP_OBJECT_virtools_group, OP_OBJECT_snoop_
# ===== Menu Defines =====
class BBP_MT_View3DMenu(bpy.types.Menu):
"""Ballance 3D Operators"""
"""Ballance 3D related operators"""
bl_idname = "BBP_MT_View3DMenu"
bl_label = "Ballance"
bl_translation_context = 'BBP_MT_View3DMenu'
def draw(self, context):
layout = self.layout
layout.label(text = 'UV', icon = 'UV')
layout.label(text='UV', icon='UV')
layout.operator(OP_UV_flatten_uv.BBP_OT_flatten_uv.bl_idname)
layout.operator(OP_UV_rail_uv.BBP_OT_rail_uv.bl_idname)
layout.separator()
layout.label(text = 'Align', icon = 'SNAP_ON')
layout.label(text='Align', icon='SNAP_ON')
layout.operator(OP_OBJECT_legacy_align.BBP_OT_legacy_align.bl_idname)
layout.separator()
layout.label(text = 'Select', icon = 'SELECT_SET')
layout.label(text='Select', icon='SELECT_SET')
layout.operator(OP_OBJECT_virtools_group.BBP_OT_select_object_by_virtools_group.bl_idname)
layout.separator()
layout.label(text = 'Material', icon = 'MATERIAL')
layout.label(text='Material', icon='MATERIAL')
layout.operator(OP_MTL_fix_material.BBP_OT_fix_all_material.bl_idname)
class BBP_MT_AddBmeMenu(bpy.types.Menu):
"""Add Ballance Floor"""
bl_idname = "BBP_MT_AddBmeMenu"
bl_label = "Floors"
bl_translation_context = 'BBP_MT_AddBmeMenu'
def draw(self, context):
layout = self.layout
@ -61,49 +66,52 @@ class BBP_MT_AddRailMenu(bpy.types.Menu):
"""Add Ballance Rail"""
bl_idname = "BBP_MT_AddRailMenu"
bl_label = "Rails"
bl_translation_context = 'BBP_MT_AddRailMenu'
def draw(self, context):
layout = self.layout
layout.label(text = "Sections", icon = 'MESH_CIRCLE')
layout.label(text="Sections", icon='MESH_CIRCLE')
layout.operator(OP_ADDS_rail.BBP_OT_add_rail_section.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_transition_section.bl_idname)
layout.separator()
layout.label(text = "Straight Rails", icon = 'IPO_CONSTANT')
layout.label(text="Straight Rails", icon='IPO_CONSTANT')
layout.operator(OP_ADDS_rail.BBP_OT_add_straight_rail.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_transition_rail.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_side_rail.bl_idname)
layout.separator()
layout.label(text = "Curve Rails", icon = 'MOD_SCREW')
layout.label(text="Curve Rails", icon='MOD_SCREW')
layout.operator(OP_ADDS_rail.BBP_OT_add_arc_rail.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_spiral_rail.bl_idname)
layout.operator(OP_ADDS_rail.BBP_OT_add_side_spiral_rail.bl_idname)
class BBP_MT_AddComponentsMenu(bpy.types.Menu):
"""Add Ballance Components"""
"""Add Ballance Component"""
bl_idname = "BBP_MT_AddComponentsMenu"
bl_label = "Components"
bl_translation_context = 'BBP_MT_AddComponentsMenu'
def draw(self, context):
layout = self.layout
layout.label(text = "Basic Components")
layout.label(text="Basic Components")
OP_ADDS_component.BBP_OT_add_component.draw_blc_menu(layout)
layout.separator()
layout.label(text = "Nong Components")
layout.label(text="Nong Components")
OP_ADDS_component.BBP_OT_add_nong_extra_point.draw_blc_menu(layout)
OP_ADDS_component.BBP_OT_add_nong_ventilator.draw_blc_menu(layout)
layout.separator()
layout.label(text = "Series Components")
layout.label(text="Series Components")
OP_ADDS_component.BBP_OT_add_tilting_block_series.draw_blc_menu(layout)
OP_ADDS_component.BBP_OT_add_swing_series.draw_blc_menu(layout)
OP_ADDS_component.BBP_OT_add_ventilator_series.draw_blc_menu(layout)
layout.separator()
layout.label(text = "Components Pair")
layout.label(text="Components Pair")
OP_ADDS_component.BBP_OT_add_sector_component_pair.draw_blc_menu(layout)
# ===== Menu Drawer =====
@ -112,13 +120,13 @@ 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_virtools.BBP_OT_import_virtools.bl_idname, text = "Virtools File (.nmo/.cmo/.vmo) (experimental)")
#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_virtools.BBP_OT_export_virtools.bl_idname, text = "Virtools File (.nmo/.cmo/.vmo) (experimental)")
#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:
layout: bpy.types.UILayout = self.layout
@ -127,7 +135,7 @@ def menu_drawer_view3d(self, context) -> None:
def menu_drawer_add(self, context) -> None:
layout: bpy.types.UILayout = self.layout
layout.separator()
layout.label(text = "Ballance")
layout.label(text="Ballance")
layout.menu(BBP_MT_AddBmeMenu.bl_idname, icon='MESH_CUBE')
layout.menu(BBP_MT_AddRailMenu.bl_idname, icon='MESH_CIRCLE')
layout.menu(BBP_MT_AddComponentsMenu.bl_idname, icon='MESH_ICOSPHERE')
@ -143,16 +151,16 @@ def menu_drawer_grouping(self, context) -> None:
col = layout.column()
col.operator_context = 'INVOKE_DEFAULT'
col.label(text = "Virtools Group")
col.operator(OP_OBJECT_virtools_group.BBP_OT_add_objects_virtools_group.bl_idname, icon = 'ADD', text = "Group into...")
col.operator(OP_OBJECT_virtools_group.BBP_OT_rm_objects_virtools_group.bl_idname, icon = 'REMOVE', text = "Ungroup from...")
col.operator(OP_OBJECT_virtools_group.BBP_OT_clear_objects_virtools_group.bl_idname, icon = 'TRASH', text = "Clear All Groups")
col.label(text="Virtools Group")
col.operator(OP_OBJECT_virtools_group.BBP_OT_add_objects_virtools_group.bl_idname, icon='ADD', text="Group into...")
col.operator(OP_OBJECT_virtools_group.BBP_OT_rm_objects_virtools_group.bl_idname, icon='REMOVE', text="Ungroup from...")
col.operator(OP_OBJECT_virtools_group.BBP_OT_clear_objects_virtools_group.bl_idname, icon='TRASH', text="Clear All Groups")
def menu_drawer_snoop_then_conv(self, context) -> None:
layout: bpy.types.UILayout = self.layout
layout.separator()
layout.label(text = "Ballance")
layout.operator(OP_OBJECT_snoop_group_then_to_mesh.BBP_OT_snoop_group_then_to_mesh.bl_idname, icon = 'OUTLINER_OB_MESH')
layout.label(text="Ballance")
layout.operator(OP_OBJECT_snoop_group_then_to_mesh.BBP_OT_snoop_group_then_to_mesh.bl_idname, icon='OUTLINER_OB_MESH')
def menu_drawer_naming_convention(self, context) -> None:
layout: bpy.types.UILayout = self.layout
@ -162,10 +170,10 @@ def menu_drawer_naming_convention(self, context) -> None:
col = layout.column()
col.operator_context = 'INVOKE_DEFAULT'
col.label(text = "Ballance")
col.operator(OP_OBJECT_naming_convention.BBP_OT_regulate_objects_name.bl_idname, icon = 'GREASEPENCIL')
col.operator(OP_OBJECT_naming_convention.BBP_OT_auto_grouping.bl_idname, icon = 'GROUP')
col.operator(OP_OBJECT_naming_convention.BBP_OT_convert_to_imengyu.bl_idname, icon = 'ARROW_LEFTRIGHT')
col.label(text="Ballance")
col.operator(OP_OBJECT_naming_convention.BBP_OT_regulate_objects_name.bl_idname, icon='GREASEPENCIL')
col.operator(OP_OBJECT_naming_convention.BBP_OT_auto_grouping.bl_idname, icon='GROUP')
col.operator(OP_OBJECT_naming_convention.BBP_OT_convert_to_imengyu.bl_idname, icon='ARROW_LEFTRIGHT')
#endregion
@ -204,7 +212,9 @@ g_BldMenus: tuple[MenuEntry, ...] = (
def register() -> None:
# register module
UTIL_translation.register()
PROP_preferences.register()
PROP_ptrprop_resolver.register()
PROP_virtools_material.register()
@ -285,7 +295,9 @@ def unregister() -> None:
PROP_virtools_material.unregister()
PROP_ptrprop_resolver.unregister()
PROP_preferences.unregister()
UTIL_translation.unregister()
if __name__ == "__main__":
register()