Quick Favorites Manager - show operators suggestions

This commit is contained in:
Andrej730
2026-03-11 14:49:08 +05:00
parent 594d72d7e1
commit 97f900e62f
5 changed files with 101 additions and 27 deletions
@@ -25,7 +25,7 @@ classes = (
operator.RemoveQuickFavoritesItem,
operator.MoveQuickFavoritesItem,
operator.AddQuickFavoritesItem,
operator.EnableQuickFavoriteSearch,
operator.ConfirmQuickFavoriteOperator,
operator.DrawSystemArrows,
operator.GetConnectedSystemElements,
operator.IfcSverchokUseBonsaiFile,
+48
View File
@@ -0,0 +1,48 @@
# Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import Any
import bpy
def refresh() -> None:
QuickFavoritesData.is_loaded = False
class QuickFavoritesData:
data: dict[str, Any] = {}
is_loaded = False
@classmethod
def load(cls) -> None:
cls.data = {
"operators": cls.operators(),
}
cls.is_loaded = True
@classmethod
def operators(cls) -> list[str]:
items: list[str] = []
for module_name in dir(bpy.ops):
module = getattr(bpy.ops, module_name)
for op_name in dir(module):
op = getattr(module, op_name)
bl_label = op.get_rna_type().name
items.append(f"{module_name}.{op_name} - {bl_label}")
return items
+9 -14
View File
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING, Literal, assert_never, cast, get_args
from typing import TYPE_CHECKING, Literal, assert_never, get_args
import bpy
import ifcopenshell.util.geolocation
@@ -355,9 +355,9 @@ class DrawSystemArrows(bpy.types.Operator, tool.Ifc.Operator):
return matrix
class EnableQuickFavoriteSearch(bpy.types.Operator):
bl_idname = "bim.enable_quick_favorite_search"
bl_label = "Enable Search"
class ConfirmQuickFavoriteOperator(bpy.types.Operator):
bl_idname = "bim.confirm_quick_favorite_operator"
bl_label = "Confirm Operator"
bl_options = {"REGISTER", "UNDO"}
index: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
@@ -367,18 +367,13 @@ class EnableQuickFavoriteSearch(bpy.types.Operator):
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
props = tool.Misc.get_misc_props()
fav = props.quick_favorites[self.index]
name = fav.search.strip()
rna = fav.get_searched_operator()
# TODO: don't use try / except.
try:
module, func = name.split(".", 1)
op = getattr(getattr(bpy.ops, module), func)
rna = cast(bpy.types.Struct, op.get_rna_type())
except (ValueError, AttributeError):
self.report({"ERROR"}, f"Operator '{name}' not found.")
if rna is None:
self.report({"INFO"}, "No operator entered for search.")
return {"CANCELLED"}
fav.operator_id = name
fav.operator_id = tool.Blender.operator_idname_to_py(rna.identifier)
fav.label = rna.name
fav.properties.clear()
has_skipped = False
@@ -429,7 +424,7 @@ class ImportQuickFavorites(bpy.types.Operator):
fav = props.quick_favorites.add()
fav.label = qf.ui_name
fav.search = qf.op_idname_py
bpy.ops.bim.enable_quick_favorite_search(index=i)
bpy.ops.bim.confirm_quick_favorite_operator(index=i)
fav.label = qf.ui_name or fav.label
for prop in fav.properties:
+32 -4
View File
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING, Literal, get_args
from typing import TYPE_CHECKING, Literal, cast, get_args
import bpy
from bpy.props import (
@@ -30,6 +30,8 @@ from bpy.props import (
)
from bpy.types import PropertyGroup
from bonsai.bim.module.misc.data import QuickFavoritesData
QuickFavoriteValueType = Literal["float_value", "bool_value", "int_value", "string_value"]
@@ -61,20 +63,46 @@ class QuickFavoriteProperty(PropertyGroup):
is_active: bool
def get_operator_suggestions(self: "QuickFavoritesItem", context: bpy.types.Context, edit_text: str) -> list[str]:
if not QuickFavoritesData.is_loaded:
QuickFavoritesData.load()
return QuickFavoritesData.data["operators"]
class QuickFavoritesItem(PropertyGroup):
is_expanded: BoolProperty(name="Is Expanded", default=True) # pyright: ignore[reportRedeclaration]
search: StringProperty(name="Search", default="") # pyright: ignore[reportRedeclaration]
is_expanded: BoolProperty(name="Is Expanded", default=False) # pyright: ignore[reportRedeclaration]
search: StringProperty( # pyright: ignore[reportRedeclaration]
name="Search",
default="",
search=get_operator_suggestions,
# Resetting `search_options`, allowing users only to use suggestions.
search_options=set(),
)
properties: CollectionProperty(type=QuickFavoriteProperty) # pyright: ignore[reportRedeclaration]
operator_id: StringProperty(name="Operator ID", default="") # pyright: ignore[reportRedeclaration]
operator_id: StringProperty( # pyright: ignore[reportRedeclaration]
name="Operator ID",
default="",
)
label: StringProperty( # pyright: ignore[reportRedeclaration]
name="Label",
description="Label that will be used in Quick Favorites for this operator",
default="",
)
def get_searched_operator(self) -> bpy.types.Struct | None:
if not self.search:
return None
search_label = self.search
name = search_label.split(" - ", 1)[0]
module, func = name.split(".", 1)
op = getattr(getattr(bpy.ops, module), func)
rna = cast(bpy.types.Struct, op.get_rna_type())
return rna
if TYPE_CHECKING:
is_expanded: bool
search: str
"""Internal property set when confirming results of the search field"""
properties: bpy.types.bpy_prop_collection_idprop[QuickFavoriteProperty]
operator_id: str
label: str
+11 -8
View File
@@ -77,8 +77,8 @@ class BIM_PT_quick_favorites_manager(bpy.types.Panel):
row = layout.row(align=True)
row.label(text="Quick Favorites:")
row.operator("bim.import_quick_favorites", text="", icon="BLENDER")
row.operator("bim.add_quick_favorites_item", text="", icon="ADD")
row.operator("bim.import_quick_favorites", text="", icon="BLENDER")
op = row.operator("bim.show_description", text="", icon="INFO")
op.attr_name = "Quick Favorites Manager"
op.description = (
@@ -115,13 +115,16 @@ class BIM_PT_quick_favorites_manager(bpy.types.Panel):
continue
row = box.row(align=True)
row.prop(fav, "search", text="")
row.operator("bim.enable_quick_favorite_search", text="", icon="VIEWZOOM").index = i
row.operator("bim.confirm_quick_favorite_operator", text="", icon="VIEWZOOM").index = i
if not fav.operator_id:
continue
layout.separator()
box.label(text="Properties:")
prop_box = box.box()
for item in fav.properties:
row = prop_box.row(align=True)
row.prop(item, item.value_prop, text=item.display_name)
row.prop(item, "is_active", text="", icon="RADIOBUT_ON" if item.is_active else "RADIOBUT_OFF")
if fav.properties:
box.label(text="Properties:")
prop_box = box.box()
for item in fav.properties:
row = prop_box.row(align=True)
row.prop(item, item.value_prop, text=item.display_name)
row.prop(item, "is_active", text="", icon="RADIOBUT_ON" if item.is_active else "RADIOBUT_OFF")
else:
box.label(text="No Properties.")