feat: add BME category display in blender.

- add BME category display in blender, including add menu and side menu.
This commit is contained in:
2025-08-25 13:07:55 +08:00
parent 96a81b165b
commit 7e74e42bd7
4 changed files with 73 additions and 29 deletions

View File

@ -280,17 +280,25 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
@classmethod
def draw_blc_menu(cls, layout: bpy.types.UILayout):
for ident in _g_EnumHelper_BmeStructType.get_bme_identifiers():
for category, idents in _g_EnumHelper_BmeStructType.get_bme_categories().items():
# draw category label
layout.label(text=category, text_ctxt=UTIL_translation.build_prototype_showcase_category_context())
# draw prototypes list
for ident in idents:
# draw 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),
text_ctxt = UTIL_translation.build_prototype_showcase_context(ident),
text_ctxt = UTIL_translation.build_prototype_showcase_title_context(ident),
)
# and assign its init type value
cop.bme_struct_type = _g_EnumHelper_BmeStructType.to_selection(ident)
# draw separator
layout.separator()
#endregion
def register() -> None:

View File

@ -21,7 +21,7 @@ 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(context)
objls: tuple[bpy.types.Object, ...] | None = self.general_get_export_objects(context)
if objls is None:
self.report({'ERROR'}, 'No selected target!')
return {'CANCELLED'}

View File

@ -24,6 +24,7 @@ TOKEN_IDENTIFIER: str = 'identifier'
TOKEN_SHOWCASE: str = 'showcase'
TOKEN_SHOWCASE_TITLE: str = 'title'
TOKEN_SHOWCASE_CATEGORY: str = 'category'
TOKEN_SHOWCASE_ICON: str = 'icon'
TOKEN_SHOWCASE_TYPE: str = 'type'
TOKEN_SHOWCASE_CFGS: str = 'cfgs'
@ -64,10 +65,10 @@ TOKEN_INSTANCES_TRANSFORM: str = 'transform'
#region Prototype Loader
## The list storing BME prototype.
_g_BMEPrototypes: list[dict[str, typing.Any]] = []
## The dict. Key is prototype identifier. value is the index of prototype in prototype list.
"""The list storing BME prototype."""
_g_BMEPrototypeIndexMap: dict[str, int] = {}
"""The dict. Key is prototype identifier. Value is the index of prototype in prototype list."""
# the core loader
for walk_root, walk_dirs, walk_files in os.walk(os.path.join(os.path.dirname(__file__), 'jsons')):
@ -192,7 +193,31 @@ class EnumPropHelper(UTIL_functions.EnumPropHelper[str]):
The BME specialized Blender EnumProperty helper.
"""
showcase_identifiers: tuple[str, ...]
showcase_categories: dict[str, tuple[str, ...]]
def __init__(self):
# build cache for showcase identifiers and categories
# prepare cache value
identifiers: list[str] = []
categories: dict[str, list[str]] = {}
# iterate showcase prototypes
for x in filter(lambda x: x[TOKEN_SHOWCASE] is not None, _g_BMEPrototypes):
# fetch identifier and category
identifier = typing.cast(str, x[TOKEN_IDENTIFIER])
category = typing.cast(str, x[TOKEN_SHOWCASE][TOKEN_SHOWCASE_CATEGORY])
# add into identifier list
identifiers.append(identifier)
# add into categories
categories_inner = categories.get(category, None)
if categories_inner is None:
categories_inner = []
categories[category] = categories_inner
categories_inner.append(identifier)
# tuple the result
self.showcase_identifiers = tuple(identifiers)
self.showcase_categories = {k: tuple(v) for k, v in categories.items()}
# init parent class
super().__init__(
self.get_bme_identifiers(),
@ -206,12 +231,15 @@ class EnumPropHelper(UTIL_functions.EnumPropHelper[str]):
def get_bme_identifiers(self) -> tuple[str, ...]:
"""
Get the identifier of prototype which need to be exposed to user.
Template prototype is not included.
In other words, template prototype is not included.
"""
return tuple(
x[TOKEN_IDENTIFIER] # get identifier
for x in filter(lambda x: x[TOKEN_SHOWCASE] is not None, _g_BMEPrototypes) # filter() to filter no showcase template.
)
return self.showcase_identifiers
def get_bme_categories(self) -> dict[str, tuple[str, ...]]:
"""
Get user-oriented identifier list grouped by category.
"""
return self.showcase_categories
def get_bme_showcase_title(self, ident: str) -> str:
"""

View File

@ -55,14 +55,22 @@ import bpy
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:
CTX_BBP_BME: str = f'{CTX_BBP}/BME'
CTX_BBP_BME_CATEGORY: str = f'{CTX_BBP_BME}/Category'
CTX_BBP_BME_PROTOTYPE: str = f'{CTX_BBP_BME}/Proto'
def build_prototype_showcase_category_context() -> str:
"""
Build the context for getting the translation for BME prototype showcase category.
@return The context for getting translation.
"""
return CTX_BBP_BME_CATEGORY
def build_prototype_showcase_title_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
return f'{CTX_BBP_BME_PROTOTYPE}/{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.
@ -70,7 +78,7 @@ def build_prototype_showcase_cfg_context(identifier: str, cfg_index: int) -> str
@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}]'
return f'{CTX_BBP_BME_PROTOTYPE}/{identifier}/[{cfg_index}]'
#endregion