New timerless thumbnailed type manager.

This commit is contained in:
Dion Moult
2022-10-11 13:49:46 +11:00
parent 36fdd3f7fc
commit 38f563d4f4
7 changed files with 139 additions and 20 deletions
@@ -20,12 +20,14 @@ import bpy
from . import handler, prop, ui, grid, product, wall, slab, stair, opening, pie, workspace, profile from . import handler, prop, ui, grid, product, wall, slab, stair, opening, pie, workspace, profile
classes = ( classes = (
product.AddEmptyType,
product.AddConstrTypeInstance, product.AddConstrTypeInstance,
product.DisplayConstrTypes, product.AddEmptyType,
product.ReinvokeOperator,
product.AlignProduct, product.AlignProduct,
product.ChangeTypePage,
product.DisplayConstrTypes,
product.DynamicallyVoidProduct, product.DynamicallyVoidProduct,
product.LoadTypeThumbnails,
product.ReinvokeOperator,
workspace.Hotkey, workspace.Hotkey,
wall.AlignWall, wall.AlignWall,
wall.ChangeExtrusionDepth, wall.ChangeExtrusionDepth,
@@ -65,6 +67,7 @@ classes = (
prop.BIMModelProperties, prop.BIMModelProperties,
ui.BIM_PT_authoring, ui.BIM_PT_authoring,
ui.DisplayConstrTypesUI, ui.DisplayConstrTypesUI,
ui.LaunchTypeManager,
ui.HelpConstrTypes, ui.HelpConstrTypes,
ui.BIM_MT_model, ui.BIM_MT_model,
grid.BIM_OT_add_object, grid.BIM_OT_add_object,
@@ -16,8 +16,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import functools
import bpy import bpy
import math
import functools
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound from blenderbim.bim.module.model.root import ConstrTypeEntityNotFound
@@ -30,6 +31,7 @@ def refresh():
class AuthoringData: class AuthoringData:
data = {} data = {}
type_thumbnails = {} type_thumbnails = {}
types_per_page = 9
is_loaded = False is_loaded = False
@classmethod @classmethod
@@ -39,6 +41,11 @@ class AuthoringData:
cls.load_ifc_classes() cls.load_ifc_classes()
cls.load_relating_types() cls.load_relating_types()
cls.load_relating_types_browser() cls.load_relating_types_browser()
cls.data["total_types"] = cls.total_types()
cls.data["total_pages"] = cls.total_pages()
cls.data["next_page"] = cls.next_page()
cls.data["prev_page"] = cls.prev_page()
cls.data["paginated_relating_types"] = cls.paginated_relating_types()
cls.data["type_thumbnail"] = cls.type_thumbnail() cls.data["type_thumbnail"] = cls.type_thumbnail()
cls.data["is_voidable_element"] = cls.is_voidable_element() cls.data["is_voidable_element"] = cls.is_voidable_element()
cls.data["has_visible_openings"] = cls.has_visible_openings() cls.data["has_visible_openings"] = cls.has_visible_openings()
@@ -46,13 +53,9 @@ class AuthoringData:
@classmethod @classmethod
def type_thumbnail(cls): def type_thumbnail(cls):
props = bpy.context.scene.BIMModelProperties if not cls.props.relating_type_id:
if not props.relating_type_id:
return 0
element = tool.Ifc.get().by_id(int(props.relating_type_id))
obj = tool.Ifc.get_object(element)
if not obj:
return 0 return 0
element = tool.Ifc.get().by_id(int(cls.props.relating_type_id))
return cls.type_thumbnails.get(element.id(), None) or 0 return cls.type_thumbnails.get(element.id(), None) or 0
@classmethod @classmethod
@@ -67,6 +70,45 @@ class AuthoringData:
def load_relating_types_browser(cls): def load_relating_types_browser(cls):
cls.data["relating_types_ids_browser"] = cls.relating_types_browser() cls.data["relating_types_ids_browser"] = cls.relating_types_browser()
@classmethod
def total_types(cls):
ifc_class = cls.props.ifc_class
return len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0
@classmethod
def total_pages(cls):
ifc_class = cls.props.ifc_class
total_types = len(tool.Ifc.get().by_type(ifc_class)) if ifc_class else 0
return math.ceil(total_types / cls.types_per_page)
@classmethod
def next_page(cls):
if cls.props.type_page < cls.total_pages():
return cls.props.type_page + 1
@classmethod
def prev_page(cls):
if cls.props.type_page > 1:
return cls.props.type_page - 1
@classmethod
def paginated_relating_types(cls):
ifc_class = cls.props.ifc_class
if not ifc_class:
return []
results = []
elements = sorted(tool.Ifc.get().by_type(ifc_class), key=lambda e: e.Name or "Unnamed")
elements = elements[(cls.props.type_page - 1) * cls.types_per_page:cls.props.type_page * cls.types_per_page]
for element in elements:
results.append({
"id": element.id(),
"ifc_class": element.is_a(),
"name": element.Name or "Unnamed",
"description": element.Description or "No Description",
"icon_id": cls.type_thumbnails.get(element.id(), None) or 0,
})
return results
@classmethod @classmethod
def is_voidable_element(cls): def is_voidable_element(cls):
element = tool.Ifc.get_entity(bpy.context.active_object) element = tool.Ifc.get_entity(bpy.context.active_object)
@@ -194,6 +194,17 @@ class AddConstrTypeInstance(bpy.types.Operator):
pass # Dumb block generator? Eh? :) pass # Dumb block generator? Eh? :)
class ChangeTypePage(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.change_type_page"
bl_label = "Change Type Page"
bl_options = {"REGISTER"}
page: bpy.props.IntProperty()
def _execute(self, context):
context.scene.BIMModelProperties.type_page = self.page
return {"FINISHED"}
class DisplayConstrTypes(bpy.types.Operator): class DisplayConstrTypes(bpy.types.Operator):
bl_idname = "bim.display_constr_types" bl_idname = "bim.display_constr_types"
bl_label = "Browse Construction Types" bl_label = "Browse Construction Types"
@@ -408,13 +419,13 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator):
thicknesses = [l.LayerThickness for l in material.MaterialLayers] thicknesses = [l.LayerThickness for l in material.MaterialLayers]
total_thickness = sum(thicknesses) total_thickness = sum(thicknesses)
si_total_thickness = total_thickness * unit_scale si_total_thickness = total_thickness * unit_scale
if si_total_thickness < 0.05: if si_total_thickness <= 0.051:
width = 10 width = 10
elif si_total_thickness < 0.1: elif si_total_thickness <= 0.11:
width = 20 width = 20
elif si_total_thickness < 0.2: elif si_total_thickness <= 0.21:
width = 30 width = 30
elif si_total_thickness < 0.3: elif si_total_thickness <= 0.31:
width = 40 width = 40
else: else:
width = 50 width = 50
@@ -94,6 +94,10 @@ def update_relating_type(self, context):
AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail() AuthoringData.data["type_thumbnail"] = AuthoringData.type_thumbnail()
def update_type_page(self, context):
AuthoringData.data["paginated_relating_types"] = AuthoringData.paginated_relating_types()
def update_relating_type_browser(self, context): def update_relating_type_browser(self, context):
AuthoringData.load_relating_types_browser() AuthoringData.load_relating_types_browser()
if not self.updating: if not self.updating:
@@ -201,3 +205,4 @@ class BIMModelProperties(PropertyGroup):
y: bpy.props.FloatProperty(name="Y", default=0.5) y: bpy.props.FloatProperty(name="Y", default=0.5)
z: bpy.props.FloatProperty(name="Z", default=0.5) z: bpy.props.FloatProperty(name="Z", default=0.5)
rl: bpy.props.FloatProperty(name="RL", default=1) rl: bpy.props.FloatProperty(name="RL", default=1)
type_page: bpy.props.IntProperty(name="Type Page", default=1, update=update_type_page)
@@ -23,6 +23,66 @@ from blenderbim.bim.module.model.prop import store_cursor_position
from blenderbim.bim.helper import prop_with_search, close_operator_panel from blenderbim.bim.helper import prop_with_search, close_operator_panel
class LaunchTypeManager(bpy.types.Operator):
bl_idname = "bim.launch_type_manager"
bl_label = "Launch Type Manager"
bl_options = {"REGISTER"}
bl_description = "Display all available Construction Types to add new instances"
def execute(self, context):
return {"FINISHED"}
def invoke(self, context, event):
props = context.scene.BIMModelProperties
props.type_page = 1
bpy.ops.bim.load_type_thumbnails(ifc_class=props.ifc_class)
if not AuthoringData.is_loaded:
AuthoringData.load()
return context.window_manager.invoke_popup(self, width=550)
def draw(self, context):
props = context.scene.BIMModelProperties
row = self.layout.row(align=True)
row.alignment = "RIGHT"
#row.label(text=f"", icon="FILE_VOLUME")
text = f"{AuthoringData.data['total_types']} types"
if AuthoringData.data["total_pages"] > 1:
text += f" ({props.type_page}/{AuthoringData.data['total_pages']}) "
row.label(text=text)
if AuthoringData.data["prev_page"]:
op = row.operator("bim.change_type_page", icon="TRIA_LEFT", text="")
op.page = AuthoringData.data["prev_page"]
if AuthoringData.data["next_page"]:
op = row.operator("bim.change_type_page", icon="TRIA_RIGHT", text="")
op.page = AuthoringData.data["next_page"]
flow = self.layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=True, align=True)
for relating_type in AuthoringData.data["paginated_relating_types"]:
outer_col = flow.column()
box = outer_col.box()
row = box.row()
row.alignment = "CENTER"
row.label(text=relating_type["name"], icon="FILE_3D")
row = box.row()
row.alignment = "CENTER"
row.label(text=relating_type["description"])
row = box.row()
row.template_icon(icon_value=relating_type["icon_id"], scale=4)
row = box.row()
op = row.operator("bim.add_constr_type_instance", icon="ADD")
op.from_invoke = True
op.ifc_class = relating_type["ifc_class"]
op.relating_type_id = relating_type["id"]
class BIM_PT_authoring(Panel): class BIM_PT_authoring(Panel):
bl_label = "Architectural" bl_label = "Architectural"
bl_idname = "BIM_PT_authoring" bl_idname = "BIM_PT_authoring"
@@ -58,9 +118,7 @@ class DisplayConstrTypesUI(Operator):
browser_state.updating = True browser_state.updating = True
def run_operator(): def run_operator():
bpy.ops.bim.reinvoke_operator( bpy.ops.bim.reinvoke_operator("INVOKE_DEFAULT", operator="bim.display_constr_types_ui")
"INVOKE_DEFAULT", operator="bim.display_constr_types_ui"
)
browser_state.updating = False browser_state.updating = False
if not browser_state.updating: if not browser_state.updating:
@@ -757,7 +757,7 @@ class DumbWallJoiner:
axis1["reference"][0], axis1["reference"][1] = axis1["reference"][1], axis1["reference"][0] axis1["reference"][0], axis1["reference"][1] = axis1["reference"][1], axis1["reference"][0]
flip_matrix = Matrix.Rotation(pi, 4, "Z") flip_matrix = Matrix.Rotation(pi, 4, "Z")
wall1.rotation_euler.rotate(flip_matrix) wall1.matrix_world = wall1.matrix_world @ flip_matrix
bpy.context.view_layer.update() bpy.context.view_layer.update()
self.recreate_wall(element1, wall1, axis1["reference"], axis1["reference"]) self.recreate_wall(element1, wall1, axis1["reference"], axis1["reference"])
@@ -93,6 +93,7 @@ class BimTool(WorkSpaceTool):
if relating_types_ids: if relating_types_ids:
row.label(text="", icon="FILE_3D") row.label(text="", icon="FILE_3D")
prop_with_search(row, props, "relating_type_id", text="") prop_with_search(row, props, "relating_type_id", text="")
row.operator("bim.launch_type_manager", icon="LIGHTPROBE_GRID", text="")
else: else:
row.label(text="No Construction Type", icon="FILE_3D") row.label(text="No Construction Type", icon="FILE_3D")
if ifc_classes: if ifc_classes:
@@ -121,11 +122,10 @@ class BimTool(WorkSpaceTool):
else: else:
row.label(text="No Construction Type", icon="FILE_3D") row.label(text="No Construction Type", icon="FILE_3D")
box = layout.box()
if AuthoringData.data["type_thumbnail"]: if AuthoringData.data["type_thumbnail"]:
box = layout.box()
box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5) box.template_icon(icon_value=AuthoringData.data["type_thumbnail"], scale=5)
else: else:
box = layout.box()
op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH") op = box.operator("bim.load_type_thumbnails", text="Load Thumbnails", icon="FILE_REFRESH")
op.ifc_class = props.ifc_class op.ifc_class = props.ifc_class