mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
prop_with_search for external styles enum #5569
Ping @Gorgious56 as perhaps you might be interested in this weird case - it seems passing Operator with context_pointer_set makes it OperatorProperties which doesn't have original __annotations__.
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
import importlib
|
||||
import bpy
|
||||
import json
|
||||
import math
|
||||
@@ -237,36 +238,57 @@ def export_attributes(
|
||||
return attributes
|
||||
|
||||
|
||||
ENUM_ITEMS_DATA = Union[bpy.types.PropertyGroup, bpy.types.ID, bpy.types.Operator, bpy.types.OperatorProperties]
|
||||
|
||||
|
||||
def prop_with_search(
|
||||
layout: bpy.types.UILayout,
|
||||
data: Union[bpy.types.PropertyGroup, bpy.types.ID],
|
||||
data: ENUM_ITEMS_DATA,
|
||||
prop_name: str,
|
||||
should_click_ok_to_validate: bool = False,
|
||||
original_operator_path: Optional[str] = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# kwargs are layout.prop arguments (text, icon, etc.)
|
||||
row = layout.row(align=True)
|
||||
row.prop(data, prop_name, **kwargs)
|
||||
try:
|
||||
if len(get_enum_items(data, prop_name)) > 10:
|
||||
if len(get_enum_items(data, prop_name, original_operator_path=original_operator_path)) > 10:
|
||||
# Magick courtesy of https://blender.stackexchange.com/a/203443/86891
|
||||
row.context_pointer_set(name="data", data=data)
|
||||
op = row.operator("bim.enum_property_search", text="", icon="VIEWZOOM")
|
||||
op.prop_name = prop_name
|
||||
op.should_click_ok_to_validate = should_click_ok_to_validate
|
||||
op.original_operator_path = original_operator_path or ""
|
||||
except TypeError: # Prop is not iterable
|
||||
pass
|
||||
|
||||
|
||||
def get_enum_items(
|
||||
data: Union[bpy.types.PropertyGroup, bpy.types.ID], prop_name: str, context: Optional[bpy.types.Context] = None
|
||||
data: ENUM_ITEMS_DATA,
|
||||
prop_name: str,
|
||||
context: Optional[bpy.types.Context] = None,
|
||||
original_operator_path: Optional[str] = None,
|
||||
) -> Union[
|
||||
Iterable[Union[tuple[str, str, str], tuple[str, str, str, int], tuple[str, str, str, str, int], None]], None
|
||||
]:
|
||||
# Retrieve items from a dynamic EnumProperty, which is otherwise not supported
|
||||
# Or throws an error in the console when the items callback returns an empty list
|
||||
# See https://blender.stackexchange.com/q/215781/86891
|
||||
prop = data.__annotations__[prop_name]
|
||||
|
||||
# OperatorProperties is missing __annotations__, so need to somehow provide original Operator.
|
||||
# Couldn't find any way to get Operator from OperatorProperties, so we provide the path explicitly.
|
||||
# E.g. OpeartorProperties occur when Operator is passed with context_pointer_set.
|
||||
if isinstance(data, bpy.types.OperatorProperties):
|
||||
if not original_operator_path:
|
||||
raise Exception("For OperatorProperties providing the original operator path is required.")
|
||||
operator_module_path, operator_class = original_operator_path.rsplit(".", 1)
|
||||
operator_module = importlib.import_module(operator_module_path)
|
||||
annotations_data = getattr(operator_module, operator_class)
|
||||
else:
|
||||
annotations_data = data
|
||||
|
||||
prop = annotations_data.__annotations__[prop_name]
|
||||
items = prop.keywords.get("items")
|
||||
if items is None:
|
||||
return
|
||||
|
||||
@@ -317,7 +317,10 @@ class BrowseExternalStyle(bpy.types.Operator):
|
||||
layout.label(text="Data Block Type")
|
||||
layout.prop(self, "data_block_type", text="", icon="GROUP")
|
||||
layout.label(text="Data Block")
|
||||
layout.prop(self, "data_block", text="")
|
||||
cls = BrowseExternalStyle
|
||||
bonsai.bim.helper.prop_with_search(
|
||||
layout, self, "data_block", text="", original_operator_path=f"{cls.__module__}.{cls.__name__}"
|
||||
)
|
||||
if Path(tool.Ifc.get_path()).is_file():
|
||||
layout.prop(self, "use_relative_path")
|
||||
else:
|
||||
|
||||
@@ -40,7 +40,7 @@ from mathutils import Vector, Matrix, Euler
|
||||
from math import radians
|
||||
from pathlib import Path
|
||||
from collections import namedtuple
|
||||
from typing import List
|
||||
from typing import List, Iterable, Union
|
||||
|
||||
|
||||
class SetTab(bpy.types.Operator):
|
||||
@@ -890,11 +890,14 @@ class BIM_OT_enum_property_search(bpy.types.Operator):
|
||||
collection_predefined_types: bpy.props.CollectionProperty(type=StrProperty)
|
||||
prop_name: bpy.props.StringProperty()
|
||||
should_click_ok_to_validate: bpy.props.BoolProperty(default=False)
|
||||
original_operator_path: bpy.props.StringProperty(name="Original Operator Path", default="", options={"SKIP_SAVE"})
|
||||
|
||||
identifiers: list[str]
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.clear_collections()
|
||||
self.data = context.data
|
||||
items = get_enum_items(self.data, self.prop_name, context)
|
||||
items = get_enum_items(self.data, self.prop_name, context, original_operator_path=self.original_operator_path)
|
||||
if items is None:
|
||||
return {"FINISHED"}
|
||||
self.add_items_regular(items)
|
||||
@@ -909,7 +912,7 @@ class BIM_OT_enum_property_search(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
return {"FINISHED"}
|
||||
|
||||
def clear_collections(self):
|
||||
def clear_collections(self) -> None:
|
||||
self.collection_names.clear()
|
||||
self.collection_identifiers.clear()
|
||||
|
||||
@@ -918,17 +921,21 @@ class BIM_OT_enum_property_search(bpy.types.Operator):
|
||||
self.collection_names.add().name = name
|
||||
self.collection_predefined_types.add().name = predefined_type
|
||||
|
||||
def add_items_regular(self, items):
|
||||
def add_items_regular(
|
||||
self,
|
||||
items: Iterable[Union[tuple[str, str, str], tuple[str, str, str, int], tuple[str, str, str, str, int], None]],
|
||||
) -> None:
|
||||
self.identifiers = []
|
||||
current_value = getattr(self.data, self.prop_name)
|
||||
for item in items:
|
||||
if item is None: # Used as a separator
|
||||
continue
|
||||
self.identifiers.append(item[0])
|
||||
self.add_item(identifier=item[0], name=item[1])
|
||||
if item[0] == getattr(self.data, self.prop_name):
|
||||
if item[0] == current_value:
|
||||
self.dummy_name = item[1] # We found the current enum name
|
||||
|
||||
def add_items_suggestions(self):
|
||||
def add_items_suggestions(self) -> None:
|
||||
getter_suggestions = getattr(self.data, "getter_enum_suggestions", None)
|
||||
if getter_suggestions is not None:
|
||||
mapping = getter_suggestions.get(self.prop_name)
|
||||
|
||||
Reference in New Issue
Block a user