custom_shelf/functions.py
2025-12-03 16:53:18 +01:00

226 lines
7.1 KiB
Python

from os import scandir
from posixpath import splitext
from .utils import *
from bpy.props import *
from bpy.types import Panel, Operator
from .properties import CustomShelfSettings, CustomShelfPrefs
from .Types import *
from os.path import join, dirname, exists
SHELF_DIR = join(dirname(__file__), "shelves")
def operator(idname, args):
op_execute = args["execute"]
def execute(self, context):
op_execute(context, self)
return {"FINISHED"}
package = __package__.replace("_", "").replace("-", "").lower()
args["bl_idname"] = "%s.%s" % (package, idname)
args["bl_label"] = title(idname)
args["execute"] = execute
op = type("operator", (Operator,), args)
bpy.utils.register_class(op)
return op
def register_bl_class(bl_class, args):
a = type("test", (bl_class,), {})
a.initialyse(a, *args)
bpy.utils.register_class(a)
return a
def filter_dir(dir_list):
return [d for d in dir_list if d.is_dir() and not d.name.startswith("_")]
def get_shelves_folder():
prefs = bpy.context.preferences.addons[__package__].preferences
shelves_path = prefs.global_shelves
additionnal_shelves_path = [s.path for s in prefs.additionnal_shelves]
return [p for p in additionnal_shelves_path + [shelves_path] if exists(p)]
def get_dirs(paths):
if isinstance(paths, (tuple, list)):
dirs = []
for dir in paths:
if not isinstance(dir, str):
dir = dir.path
dirs += filter_dir(scandir(dir))
return dirs
else:
return filter_dir(scandir(paths))
def get_categories():
return [d.name for d in get_dirs(get_shelves_folder())]
def get_tabs():
return [d.name for d in get_dirs(get_dirs(get_shelves_folder()))]
def get_category_path(category):
category_dir = [
f for f in get_shelves_folder() if category in [d.name for d in get_dirs(f)]
]
if category_dir:
return join(category_dir[0], category)
def get_category_tabs(category):
return [d.name for d in get_dirs(get_category_path(category))]
def read_shelves():
tag_filter_items = []
# unregister panel :
for panel in CustomShelfSettings.panel_list:
print(panel)
if panel.__name__ not in get_tabs():
try:
bpy.utils.unregister_class(panel)
except Exception:
pass
CustomShelfSettings.panel_list.remove(panel)
for cat in get_dirs(get_shelves_folder()):
cat_name = cat.name.replace("_", " ").title()
header_info = {
"bl_region_type": "UI", # petit ajout pour voir si foncitonne...
"bl_category": cat_name,
"bl_idname": "%s_PT_%s_header"
% (__package__.upper(), cat.name), # -> "%s.%s_header" makes _PT_ warning
"cat": cat.name,
"path": cat.path,
}
header = type("Header", (CSHELF_PT_shelf_header,), header_info)
bpy.utils.register_class(header)
# enable bool prefs
# panel_props = {t.name : BoolProperty(default = False) for t in get_dirs(cat.path)}# give "should be an annotation" field warning
## need annoattion type : https://blender.stackexchange.com/questions/118118/blender-2-8-field-property-declaration-and-dynamic-class-creation
panel_props = {
"__annotations__": {
t.name: BoolProperty(default=False) for t in get_dirs(cat.path)
}
}
PanelProps = type("CustomShelfPrefs", (PropertyGroup,), panel_props)
bpy.utils.register_class(PanelProps)
setattr(CustomShelfPrefs, cat.name, PointerProperty(type=PanelProps))
# search and filter
props = {
"search": StringProperty(options={"TEXTEDIT_UPDATE"}),
"filter": BoolProperty(default=True),
}
# Props = type("props",(PropertyGroup,), props)# annotation error
Props = type("props", (PropertyGroup,), {"__annotations__": props})
bpy.utils.register_class(Props)
setattr(CustomShelfSettings, cat.name, PointerProperty(type=Props))
# enable bool prefs
# Prefs = type("CustomShelfPrefs",(PropertyGroup,),{})
# bpy.utils.register_class(Prefs)
# setattr(CustomShelfPrefs,cat.name,PointerProperty(type = Prefs))
for tab in get_dirs(cat.path):
# get_settings
settings_json = join(tab.path, "settings.json")
tab_settings = {}
if exists(settings_json):
tab_settings = read_json(settings_json)
if not tab_settings or not tab_settings.get("tags"):
continue
for tag in tab_settings["tags"]:
if tag not in tag_filter_items:
tag_filter_items.append(tag)
panel_info = {
"bl_region_type": "UI", # Added, maybe need it in 2.8+...
"bl_category": cat_name,
"bl_idname": "%s_PT_%s_%s"
% (
__package__.upper(),
cat.name,
tab.name,
), # "%s.%s_%s" -> makes _PT_ warning
"bl_label": tab.name.replace("_", " ").title(),
"cat": cat.name,
"settings": tab_settings,
}
space_info = {
k: v
for k, v in tab_settings.items()
if k in ("bl_space_type", "bl_region_type")
}
panel_info.update(space_info)
panel = type("Panel", (CSHELF_PT_shelf_panel,), panel_info)
bpy.utils.register_class(panel)
CustomShelfSettings.panel_list.append(panel)
scripts = []
for script in scandir(tab.path):
if not script.name.endswith(".py"):
continue
print(script.path)
script_name = splitext(script.name)[0]
info, lines = read_info(script.path)
info["description"] = info.get("description", "")
icon = info.get("icon", "WORDWRAP_OFF")
popup = type(
script_name,
(CSHELF_OT_shelf_popup,),
{"script": script.path, "bl_description": info["description"]},
)
popup.initialyse(popup, script_name, info)
bpy.utils.register_class(popup)
scripts.append(
{"operator": popup.bl_idname, "text": script_name, "icon": icon}
)
panel.scripts = sorted(scripts, key=lambda x: x["text"])
# Register tag filter enum
# setattr(Pre, v)
prefs = bpy.context.preferences.addons[__package__].preferences
tag_filter_items.sort()
tag_filter_items.insert(0, "__clear__")
# prefs["tag_filter_items"] = tag_filter_items
# bpy.utils.unregister_class(CustomShelfPrefs)
# bpy.utils.register_class(CustomShelfPrefs)
# CustomShelfSettings.folders = list(get_shelves_folder().keys())
# folder_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in CustomShelfSettings.folders])
# setattr(CustomShelfSettings,'folders_enum',folder_enum)