Updated icons
- new master svg file for storing icons bonsai_icons.svg script for exporting png files and generating light mode versions support for light mode
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 767 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 997 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 956 B |
|
After Width: | Height: | Size: 895 B |
|
After Width: | Height: | Size: 176 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 191 B |
|
After Width: | Height: | Size: 308 B |
|
After Width: | Height: | Size: 248 B |
|
After Width: | Height: | Size: 405 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 495 B |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 752 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 799 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 821 B |
|
Before Width: | Height: | Size: 689 B |
|
Before Width: | Height: | Size: 801 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 971 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1016 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 180 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 400 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 190 B |
|
After Width: | Height: | Size: 346 B |
|
After Width: | Height: | Size: 277 B |
|
After Width: | Height: | Size: 433 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 571 B |
|
After Width: | Height: | Size: 270 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 925 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 493 B |
|
After Width: | Height: | Size: 829 B |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 863 B |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -231,6 +231,7 @@ def unregister():
|
|||||||
bpy.utils.unregister_tool(workspace.CableCarrierTool)
|
bpy.utils.unregister_tool(workspace.CableCarrierTool)
|
||||||
bpy.utils.unregister_tool(workspace.CableTool)
|
bpy.utils.unregister_tool(workspace.CableTool)
|
||||||
bpy.utils.unregister_tool(workspace.BimTool)
|
bpy.utils.unregister_tool(workspace.BimTool)
|
||||||
|
|
||||||
del bpy.types.Scene.BIMModelProperties
|
del bpy.types.Scene.BIMModelProperties
|
||||||
del bpy.types.Object.BIMArrayProperties
|
del bpy.types.Object.BIMArrayProperties
|
||||||
del bpy.types.Object.BIMStairProperties
|
del bpy.types.Object.BIMStairProperties
|
||||||
@@ -239,7 +240,9 @@ def unregister():
|
|||||||
del bpy.types.Object.BIMDoorProperties
|
del bpy.types.Object.BIMDoorProperties
|
||||||
del bpy.types.Object.BIMRailingProperties
|
del bpy.types.Object.BIMRailingProperties
|
||||||
del bpy.types.Object.BIMRoofProperties
|
del bpy.types.Object.BIMRoofProperties
|
||||||
|
|
||||||
bpy.app.handlers.load_post.remove(handler.load_post)
|
bpy.app.handlers.load_post.remove(handler.load_post)
|
||||||
bpy.types.VIEW3D_MT_mesh_add.remove(ui.add_mesh_object_menu)
|
bpy.types.VIEW3D_MT_mesh_add.remove(ui.add_mesh_object_menu)
|
||||||
bpy.types.VIEW3D_MT_add.remove(ui.add_menu)
|
bpy.types.VIEW3D_MT_add.remove(ui.add_menu)
|
||||||
|
|
||||||
workspace.unload_custom_icons()
|
workspace.unload_custom_icons()
|
||||||
@@ -29,16 +29,36 @@ from bonsai.bim.module.model.data import AuthoringData
|
|||||||
from bonsai.bim.module.system.data import PortData
|
from bonsai.bim.module.system.data import PortData
|
||||||
from bonsai.bim.module.model.prop import get_ifc_class
|
from bonsai.bim.module.model.prop import get_ifc_class
|
||||||
|
|
||||||
custom_icon_previews = None
|
|
||||||
|
def check_display_mode():
|
||||||
|
global display_mode
|
||||||
|
try:
|
||||||
|
theme = bpy.context.preferences.themes['Default']
|
||||||
|
text_color = theme.user_interface.wcol_menu_item.text
|
||||||
|
background_color = theme.user_interface.wcol_menu_item.outline
|
||||||
|
print(f"text_color = {text_color}")
|
||||||
|
print(f"background_color = {background_color}")
|
||||||
|
if sum(text_color) < 2.6:
|
||||||
|
display_mode = "lm"
|
||||||
|
else:
|
||||||
|
display_mode = "dm"
|
||||||
|
except:
|
||||||
|
display_mode = "dm"
|
||||||
|
|
||||||
|
|
||||||
def load_custom_icons():
|
def load_custom_icons():
|
||||||
global custom_icon_previews
|
global custom_icon_previews
|
||||||
|
if display_mode is None:
|
||||||
|
check_display_mode()
|
||||||
|
|
||||||
icons_dir = os.path.join(os.path.dirname(__file__), "..", "..", "data", "icons")
|
icons_dir = os.path.join(os.path.dirname(__file__), "..", "..", "data", "icons")
|
||||||
custom_icon_previews = bpy.utils.previews.new()
|
custom_icon_previews = bpy.utils.previews.new()
|
||||||
|
|
||||||
|
prefix = f"{display_mode}_"
|
||||||
|
|
||||||
for entry in os.scandir(icons_dir):
|
for entry in os.scandir(icons_dir):
|
||||||
if entry.name.endswith(".png"):
|
if entry.name.endswith(".png") and entry.name.startswith(prefix):
|
||||||
name = os.path.splitext(entry.name)[0]
|
name = os.path.splitext(entry.name)[0].replace(prefix, "", 1)
|
||||||
custom_icon_previews.load(name.upper(), entry.path, "IMAGE")
|
custom_icon_previews.load(name.upper(), entry.path, "IMAGE")
|
||||||
|
|
||||||
|
|
||||||
@@ -240,13 +260,6 @@ class CableTool(BimTool):
|
|||||||
BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
BimToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
|
||||||
|
|
||||||
|
|
||||||
MODIFIERS = {
|
|
||||||
"A": ("EVENT_ALT", "OPTION" if sys.platform == "Darwin" else "ALT"),
|
|
||||||
"C": ("EVENT_CTRL", "CTRL"),
|
|
||||||
"S": ("EVENT_SHIFT", "⇧"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context=""):
|
def add_layout_hotkey_operator(layout, text, hotkey, description, ui_context=""):
|
||||||
modifier, key = hotkey.split("_")
|
modifier, key = hotkey.split("_")
|
||||||
|
|
||||||
@@ -816,7 +829,7 @@ class BimToolUI:
|
|||||||
row = cls.layout.row(align=True)
|
row = cls.layout.row(align=True)
|
||||||
if AuthoringData.data["relating_type_id"]:
|
if AuthoringData.data["relating_type_id"]:
|
||||||
prop_with_search(row, cls.props, "relating_type_id", text="")
|
prop_with_search(row, cls.props, "relating_type_id", text="")
|
||||||
row.operator("bim.add_constr_type_instance", text=text, icon_value=custom_icon_previews["ADD"].icon_id)
|
row.operator("bim.add_constr_type_instance", text=text, icon_value=custom_icon_previews[f"ADD"].icon_id)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
row.label(text="No Construction Type", icon="FILE_3D")
|
row.label(text="No Construction Type", icon="FILE_3D")
|
||||||
@@ -1168,6 +1181,13 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
else:
|
else:
|
||||||
bpy.ops.bim.show_openings()
|
bpy.ops.bim.show_openings()
|
||||||
|
|
||||||
|
custom_icon_previews = None
|
||||||
|
display_mode = None
|
||||||
|
|
||||||
LIST_OF_TOOLS = [cls.bl_idname for cls in (BimTool.__subclasses__() + [BimTool])]
|
LIST_OF_TOOLS = [cls.bl_idname for cls in (BimTool.__subclasses__() + [BimTool])]
|
||||||
TOOLS_TO_CLASSES_MAP = {cls.bl_idname: cls.ifc_element_type for cls in BimTool.__subclasses__()}
|
TOOLS_TO_CLASSES_MAP = {cls.bl_idname: cls.ifc_element_type for cls in BimTool.__subclasses__()}
|
||||||
|
MODIFIERS = {
|
||||||
|
"A": ("EVENT_ALT", "OPTION" if sys.platform == "Darwin" else "ALT"),
|
||||||
|
"C": ("EVENT_CTRL", "CTRL"),
|
||||||
|
"S": ("EVENT_SHIFT", "⇧"),
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 94 KiB |
@@ -0,0 +1,108 @@
|
|||||||
|
# the SVG_FILE should be the file that contains all the icons (each icon should be in a unique layer group, and colored for dark mode)
|
||||||
|
# the EXPORT_FOLDER is where the png files get exported to
|
||||||
|
# the script will export dark mode version and modify colors for a light mode verion
|
||||||
|
# requires inkscape to run
|
||||||
|
# to run on mac: python3 generate_png_icons.py
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import re
|
||||||
|
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
SVG_FILE = os.path.join(SCRIPT_DIR, 'bonsai_icons.svg')
|
||||||
|
EXPORT_FOLDER = os.path.join(SCRIPT_DIR, '..', 'bonsai', 'bim', 'data', 'icons')
|
||||||
|
|
||||||
|
overwrite_all = False
|
||||||
|
skip_all = False
|
||||||
|
|
||||||
|
def dark_to_light(svg_content):
|
||||||
|
svg_content = re.sub(r'#ffffff', '#434343', svg_content, flags=re.IGNORECASE) # white to drak grey
|
||||||
|
|
||||||
|
svg_content = re.sub(r'#00d27b', '#009d5c', svg_content, flags=re.IGNORECASE) # make green darker
|
||||||
|
svg_content = re.sub(r'#009a5f', '#00663f', svg_content, flags=re.IGNORECASE) # make dark green darker
|
||||||
|
svg_content = re.sub(r'#75ffaf', '#3dff8f', svg_content, flags=re.IGNORECASE) # make light green darker
|
||||||
|
|
||||||
|
svg_content = re.sub(r'#cce3ff', '#3391ff', svg_content, flags=re.IGNORECASE) # make blue darker
|
||||||
|
svg_content = re.sub(r'#4c9fff', '#005fcc', svg_content, flags=re.IGNORECASE) # make dark blue darker
|
||||||
|
svg_content = re.sub(r'#c9e0ff', '#80b8ff', svg_content, flags=re.IGNORECASE) # make light blue darker
|
||||||
|
|
||||||
|
return svg_content
|
||||||
|
|
||||||
|
def prompt_overwrite(file_path, png_name):
|
||||||
|
global overwrite_all, skip_all
|
||||||
|
|
||||||
|
if skip_all and os.path.exists(file_path):
|
||||||
|
return 'n'
|
||||||
|
|
||||||
|
if overwrite_all:
|
||||||
|
return 'y'
|
||||||
|
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
while True:
|
||||||
|
response = input(f"File '{png_name}' already exists.\nOverwrite? (Enter = yes, s = skip, y = yes all, n = no all): ").strip().lower()
|
||||||
|
if response in {'', 'y', 'n', 's'}:
|
||||||
|
if response == 'y':
|
||||||
|
overwrite_all = True
|
||||||
|
elif response == 'n':
|
||||||
|
skip_all = True
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
print("Invalid option. Please enter Enter, y, n, or s.")
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def export_svg_group(group_content, group_label, mode, output_folder):
|
||||||
|
temp_svg_file = os.path.join(output_folder, f'{group_label}_{mode}.svg')
|
||||||
|
svg_content = f"""<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
width="31.999998" height="31.999998" viewBox="0 0 8.4666661 8.4666661">
|
||||||
|
{group_content}
|
||||||
|
</svg>"""
|
||||||
|
|
||||||
|
with open(temp_svg_file, 'w') as file:
|
||||||
|
file.write(svg_content)
|
||||||
|
|
||||||
|
png_name = f'{mode}_{group_label}.png'
|
||||||
|
output_png_file = os.path.join(output_folder, png_name)
|
||||||
|
|
||||||
|
user_choice = prompt_overwrite(output_png_file, png_name)
|
||||||
|
|
||||||
|
if user_choice in {'y', ''}:
|
||||||
|
subprocess.run(['inkscape', temp_svg_file, '--export-type=png', '--export-filename=' + output_png_file])
|
||||||
|
print(f'\033[32mExported PNG file: {output_png_file}\033[0m')
|
||||||
|
|
||||||
|
|
||||||
|
elif user_choice == 'n':
|
||||||
|
print(f"Skipping {png_name}")
|
||||||
|
|
||||||
|
elif user_choice == 's':
|
||||||
|
print(f'Skipped exporting {output_png_file}.')
|
||||||
|
|
||||||
|
os.remove(temp_svg_file)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def export_svg_groups_to_png(svg_file, output_folder):
|
||||||
|
tree = ET.parse(svg_file)
|
||||||
|
root = tree.getroot()
|
||||||
|
ns = {'svg': 'http://www.w3.org/2000/svg'}
|
||||||
|
|
||||||
|
for group in root.findall('.//svg:g', ns):
|
||||||
|
group_label = group.get('{http://www.inkscape.org/namespaces/inkscape}label')
|
||||||
|
if not group_label:
|
||||||
|
continue
|
||||||
|
|
||||||
|
style = group.get('style', '')
|
||||||
|
if 'display:none' in style:
|
||||||
|
style = style.replace('display:none', 'display:inline')
|
||||||
|
elif 'display' not in style:
|
||||||
|
style += ';display:inline'
|
||||||
|
group.set('style', style)
|
||||||
|
|
||||||
|
group_content = ET.tostring(group, encoding='unicode', method='xml')
|
||||||
|
export_svg_group(group_content, group_label, 'dm', output_folder)
|
||||||
|
light_mode_svg = dark_to_light(group_content)
|
||||||
|
export_svg_group(light_mode_svg, group_label, 'lm', output_folder)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
os.makedirs(EXPORT_FOLDER, exist_ok=True)
|
||||||
|
export_svg_groups_to_png(SVG_FILE, EXPORT_FOLDER)
|
||||||