black format
This commit is contained in:
parent
f1aaa1dfca
commit
2b692432c2
1
.python-version
Normal file
1
.python-version
Normal file
@ -0,0 +1 @@
|
||||
3.12
|
||||
209
Types.py
209
Types.py
@ -5,82 +5,75 @@ from bpy.props import *
|
||||
from .properties import CustomShelfProps
|
||||
|
||||
|
||||
class Types():
|
||||
def initialyse(self, label) :
|
||||
package = __package__.replace('_','').replace('-','').lower()
|
||||
idname = label.replace(' ','_').replace('-','_').lower()
|
||||
class Types:
|
||||
def initialyse(self, label):
|
||||
package = __package__.replace("_", "").replace("-", "").lower()
|
||||
idname = label.replace(" ", "_").replace("-", "_").lower()
|
||||
|
||||
self.bl_label = title(label)
|
||||
self.bl_idname = '%s.%s'%(package, idname)
|
||||
|
||||
#self.bl_props = bpy.context.scene.CustomShelf
|
||||
#self.prefs = ""
|
||||
|
||||
self.bl_idname = "%s.%s" % (package, idname)
|
||||
|
||||
# self.bl_props = bpy.context.scene.CustomShelf
|
||||
# self.prefs = ""
|
||||
|
||||
|
||||
class CSHELF_OT_shelf_popup(Types, Operator):
|
||||
#props = None
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
# props = None
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@property
|
||||
def props(self) :
|
||||
#print(getattr(bpy.context.window_manager.CustomShelf,self.prop))
|
||||
def props(self):
|
||||
# print(getattr(bpy.context.window_manager.CustomShelf,self.prop))
|
||||
return getattr(bpy.context.window_manager.CustomShelf, self.prop)
|
||||
|
||||
def get_props(self):
|
||||
properties = self.props.bl_rna.properties
|
||||
#props =
|
||||
return {k:v for k,v in self.args.items() if k in properties}
|
||||
# props =
|
||||
return {k: v for k, v in self.args.items() if k in properties}
|
||||
|
||||
def set_props(self,prop,value):
|
||||
setattr(bpy.context.window_manager.CustomShelf,prop,value)
|
||||
def set_props(self, prop, value):
|
||||
setattr(bpy.context.window_manager.CustomShelf, prop, value)
|
||||
|
||||
def initialyse(self,label,info) :
|
||||
super().initialyse(CSHELF_OT_shelf_popup,label)
|
||||
def initialyse(self, label, info):
|
||||
super().initialyse(CSHELF_OT_shelf_popup, label)
|
||||
|
||||
self.args = dic_to_args(info)
|
||||
|
||||
|
||||
Props = type("props",(PropertyGroup,),{'__annotations__' : dict(self.args)})
|
||||
Props = type("props", (PropertyGroup,), {"__annotations__": dict(self.args)})
|
||||
bpy.utils.register_class(Props)
|
||||
|
||||
setattr(CustomShelfProps, arg_name(label), PointerProperty(type=Props))
|
||||
#self.props = getattr(bpy.context.window_manager,self.bl_idname)
|
||||
# self.props = getattr(bpy.context.window_manager,self.bl_idname)
|
||||
self.info = info
|
||||
self.prop = arg_name(label)
|
||||
|
||||
# print(self.args)
|
||||
|
||||
# properties = self.get_props().bl_rna.properties
|
||||
# props = {k:v for k,v in self.args.items() if k in properties or hasattr(v,"bl_idname")}
|
||||
|
||||
#print(self.args)
|
||||
|
||||
|
||||
|
||||
#properties = self.get_props().bl_rna.properties
|
||||
#props = {k:v for k,v in self.args.items() if k in properties or hasattr(v,"bl_idname")}
|
||||
|
||||
return #props
|
||||
return # props
|
||||
|
||||
def invoke(self, context, event):
|
||||
if event.alt :
|
||||
for t in [t for t in bpy.data.texts if t.filepath == self.script] :
|
||||
if event.alt:
|
||||
for t in [t for t in bpy.data.texts if t.filepath == self.script]:
|
||||
bpy.data.texts.remove(t)
|
||||
|
||||
text = bpy.data.texts.load(self.script)
|
||||
|
||||
areas = []
|
||||
text_editor = None
|
||||
for area in context.screen.areas :
|
||||
if area.type == 'TEXT_EDITOR' :
|
||||
for area in context.screen.areas:
|
||||
if area.type == "TEXT_EDITOR":
|
||||
text_editor = area
|
||||
|
||||
else :
|
||||
else:
|
||||
areas.append(area)
|
||||
if not text_editor :
|
||||
bpy.ops.screen.area_split(direction = "VERTICAL")
|
||||
if not text_editor:
|
||||
bpy.ops.screen.area_split(direction="VERTICAL")
|
||||
|
||||
for area in context.screen.areas :
|
||||
if area not in areas :
|
||||
for area in context.screen.areas:
|
||||
if area not in areas:
|
||||
text_editor = area
|
||||
text_editor.type = "TEXT_EDITOR"
|
||||
text_editor.spaces[0].show_syntax_highlight = True
|
||||
@ -88,82 +81,77 @@ class CSHELF_OT_shelf_popup(Types, Operator):
|
||||
text_editor.spaces[0].show_line_numbers = True
|
||||
|
||||
context_copy = context.copy()
|
||||
context_copy['area'] = text_editor
|
||||
#bpy.ops.text.properties(context_copy)
|
||||
#bpy.ops.view3d.toolshelf(context_copy)
|
||||
context_copy["area"] = text_editor
|
||||
# bpy.ops.text.properties(context_copy)
|
||||
# bpy.ops.view3d.toolshelf(context_copy)
|
||||
|
||||
text_editor.spaces[0].text = text
|
||||
|
||||
return {"FINISHED"}
|
||||
else :
|
||||
if self.args :
|
||||
#set default value for collection
|
||||
for k,v in self.info.items() :
|
||||
if isinstance(v,dict) and v.get('collection') :
|
||||
else:
|
||||
if self.args:
|
||||
# set default value for collection
|
||||
for k, v in self.info.items():
|
||||
if isinstance(v, dict) and v.get("collection"):
|
||||
collection = getattr(bpy.data, id_type[v["collection"]])
|
||||
|
||||
setattr(self.props, k,collection.get(v["value"]))
|
||||
|
||||
|
||||
setattr(self.props, k, collection.get(v["value"]))
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
else :
|
||||
else:
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
def bl_report(self,*args) :
|
||||
if len(args) and args[0] in ('INFO','ERROR', 'WARNING') :
|
||||
return self.report({args[0]},' '.join(args[1:]))
|
||||
else :
|
||||
def bl_report(self, *args):
|
||||
if len(args) and args[0] in ("INFO", "ERROR", "WARNING"):
|
||||
return self.report({args[0]}, " ".join(args[1:]))
|
||||
else:
|
||||
print(*args)
|
||||
|
||||
def execute(self,context):
|
||||
def execute(self, context):
|
||||
info, lines = read_info(self.script)
|
||||
|
||||
values = dict(info)
|
||||
for arg in self.args :
|
||||
value = getattr(self.props,arg)
|
||||
for arg in self.args:
|
||||
value = getattr(self.props, arg)
|
||||
|
||||
if hasattr(value,"name") :
|
||||
values[arg] = {'value': value.name}
|
||||
if hasattr(value, "name"):
|
||||
values[arg] = {"value": value.name}
|
||||
|
||||
elif isinstance(info.get(arg),dict) :
|
||||
values[arg] = {'value': value}
|
||||
elif isinstance(info.get(arg), dict):
|
||||
values[arg] = {"value": value}
|
||||
|
||||
else :
|
||||
else:
|
||||
values[arg] = value
|
||||
|
||||
info_str = "info = %s\n\n"%values
|
||||
lines_str = '\n'.join(lines)
|
||||
info_str = "info = %s\n\n" % values
|
||||
lines_str = "\n".join(lines)
|
||||
script = f"{info_str}\n\n{lines_str}"
|
||||
|
||||
exec(script, {'info': values, 'print': self.bl_report})
|
||||
exec(script, {"info": values, "print": self.bl_report})
|
||||
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self,context) :
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
bl_props = context.scene.CustomShelf
|
||||
|
||||
#print(self.get_props())
|
||||
# print(self.get_props())
|
||||
|
||||
for k in self.args :
|
||||
#filter
|
||||
for k in self.args:
|
||||
# filter
|
||||
|
||||
row = layout.row(align = True)
|
||||
row = layout.row(align=True)
|
||||
row.label(text=title(k))
|
||||
|
||||
row.prop(self.props,k,text='')
|
||||
#row.prop_search(self.props,k,self.props,k+"_prop_search",text='')
|
||||
#op = self.args[k+"_prop_search"]
|
||||
#row.operator(op.bl_idname,text="",icon ="COLLAPSEMENU" )
|
||||
row.prop(self.props, k, text="")
|
||||
# row.prop_search(self.props,k,self.props,k+"_prop_search",text='')
|
||||
# op = self.args[k+"_prop_search"]
|
||||
# row.operator(op.bl_idname,text="",icon ="COLLAPSEMENU" )
|
||||
|
||||
|
||||
def check(self,context) :
|
||||
def check(self, context):
|
||||
return True
|
||||
|
||||
|
||||
|
||||
"""
|
||||
class ShelfPropSearch(Types,Operator):
|
||||
bl_property = "enum"
|
||||
@ -194,61 +182,60 @@ class ShelfPropSearch(Types,Operator):
|
||||
"""
|
||||
|
||||
|
||||
class CSHELF_PT_shelf_panel(Types,Panel):
|
||||
class CSHELF_PT_shelf_panel(Types, Panel):
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
#bl_category = "SHELF"
|
||||
# bl_category = "SHELF"
|
||||
settings = {}
|
||||
scripts = []
|
||||
|
||||
@staticmethod
|
||||
def search_filter(search,str) :
|
||||
def search_filter(search, str):
|
||||
return search.lower() in str.lower()
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
bl_props = getattr(context.scene.CustomShelf,self.cat)
|
||||
bl_props = getattr(context.scene.CustomShelf, self.cat)
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
search = bl_props.search
|
||||
shelf = [self.search_filter(search,s["text"]) for s in self.scripts]
|
||||
shelf = [self.search_filter(search, s["text"]) for s in self.scripts]
|
||||
|
||||
#print("settings",self.settings)
|
||||
# print("settings",self.settings)
|
||||
is_taged = True
|
||||
if self.settings and self.settings.get('tags') :
|
||||
if self.settings and self.settings.get("tags"):
|
||||
tag = prefs.tag_filter
|
||||
if not tag :
|
||||
if not tag:
|
||||
tag = os.getenv("CUSTOM_SHELF_TAG")
|
||||
|
||||
is_taged = tag in self.settings['tags']
|
||||
is_taged = tag in self.settings["tags"]
|
||||
|
||||
return any(shelf) and is_taged
|
||||
|
||||
|
||||
def draw(self,context) :
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
bl_props = getattr(context.scene.CustomShelf,self.cat)
|
||||
bl_props = getattr(context.scene.CustomShelf, self.cat)
|
||||
search = bl_props.search
|
||||
|
||||
for script in self.scripts :
|
||||
for script in self.scripts:
|
||||
args = script.copy()
|
||||
if not self.search_filter(search,script["text"]) : continue
|
||||
if not self.search_filter(search, script["text"]):
|
||||
continue
|
||||
|
||||
if bl_props.filter and script["text"].startswith('_') : continue
|
||||
if bl_props.filter and script["text"].startswith("_"):
|
||||
continue
|
||||
|
||||
args["text"] = title(script["text"])
|
||||
|
||||
#print(script)
|
||||
# print(script)
|
||||
layout.operator(**args)
|
||||
|
||||
|
||||
|
||||
class CSHELF_PT_shelf_header(Panel):
|
||||
bl_label = "Custom Shelf"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_options = {"HIDE_HEADER"}
|
||||
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
bl_props = bpy.context.scene.CustomShelf
|
||||
@ -256,16 +243,20 @@ class CSHELF_PT_shelf_header(Panel):
|
||||
|
||||
cat_props = getattr(bl_props, self.cat)
|
||||
|
||||
row = layout.row(align = True)
|
||||
row = layout.row(align=True)
|
||||
|
||||
row.operator_menu_enum("customshelf.set_tag_filter",'tag_filter',icon= "DOWNARROW_HLT",text='')
|
||||
row.operator("customshelf.refresh", text='',emboss=True,icon= "FILE_REFRESH")
|
||||
#row.separator()
|
||||
row.operator_menu_enum(
|
||||
"customshelf.set_tag_filter", "tag_filter", icon="DOWNARROW_HLT", text=""
|
||||
)
|
||||
row.operator("customshelf.refresh", text="", emboss=True, icon="FILE_REFRESH")
|
||||
# row.separator()
|
||||
|
||||
row.prop(cat_props, "filter",text='',emboss=True,icon= "FILTER")
|
||||
#row.separator()
|
||||
row.prop(cat_props, "filter", text="", emboss=True, icon="FILTER")
|
||||
# row.separator()
|
||||
|
||||
row.prop(cat_props,"search",icon = "VIEWZOOM",text='')
|
||||
#row.separator()
|
||||
row.prop(cat_props, "search", icon="VIEWZOOM", text="")
|
||||
# row.separator()
|
||||
|
||||
row.operator("customshelf.open_shelf_folder", text='',emboss=True,icon= "FILE").path = self.path
|
||||
row.operator(
|
||||
"customshelf.open_shelf_folder", text="", emboss=True, icon="FILE"
|
||||
).path = self.path
|
||||
|
||||
31
__init__.py
31
__init__.py
@ -8,23 +8,24 @@ bl_info = {
|
||||
"doc_url": "https://gitlab.com/autour-de-minuit/blender/custom_shelf/-/blob/main/README.md",
|
||||
"tracker_url": "https://gitlab.com/autour-de-minuit/blender/custom_shelf/-/issues",
|
||||
"support": "COMMUNITY",
|
||||
"category": "User"}
|
||||
|
||||
"category": "User",
|
||||
}
|
||||
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
|
||||
importlib.reload(operators)
|
||||
importlib.reload(panels)
|
||||
importlib.reload(functions)
|
||||
importlib.reload(properties)
|
||||
|
||||
from . utils import report
|
||||
from . functions import read_shelves
|
||||
from .utils import report
|
||||
from .functions import read_shelves
|
||||
from . import operators
|
||||
from . import properties
|
||||
from . import ui
|
||||
from .properties import CustomShelfSettings,CustomShelfProps
|
||||
from .properties import CustomShelfSettings, CustomShelfProps
|
||||
|
||||
import bpy
|
||||
import os
|
||||
@ -41,19 +42,22 @@ bl_classes = [
|
||||
operators.CSHELF_OT_open_shelf_folder,
|
||||
operators.CSHELF_OT_add_script,
|
||||
operators.CSHELF_OT_set_tag_filter,
|
||||
ui.CSHELF_MT_text_editor
|
||||
ui.CSHELF_MT_text_editor,
|
||||
]
|
||||
|
||||
|
||||
def draw_menu(self, context):
|
||||
self.layout.menu('CSHELF_MT_text_editor')
|
||||
self.layout.menu("CSHELF_MT_text_editor")
|
||||
|
||||
|
||||
def register():
|
||||
for bl_class in bl_classes :
|
||||
for bl_class in bl_classes:
|
||||
bpy.utils.register_class(bl_class)
|
||||
|
||||
|
||||
bpy.types.Scene.CustomShelf = bpy.props.PointerProperty(type=CustomShelfSettings)
|
||||
bpy.types.WindowManager.CustomShelf = bpy.props.PointerProperty(type=CustomShelfProps)
|
||||
bpy.types.WindowManager.CustomShelf = bpy.props.PointerProperty(
|
||||
type=CustomShelfProps
|
||||
)
|
||||
|
||||
bpy.types.TEXT_MT_editor_menus.append(draw_menu)
|
||||
|
||||
@ -72,10 +76,11 @@ def register():
|
||||
|
||||
read_shelves()
|
||||
|
||||
|
||||
def unregister():
|
||||
# unregister panel :
|
||||
for panel in CustomShelfSettings.panel_list :
|
||||
try :
|
||||
for panel in CustomShelfSettings.panel_list:
|
||||
try:
|
||||
bpy.utils.unregister_class(panel)
|
||||
except Exception:
|
||||
pass
|
||||
@ -84,5 +89,5 @@ def unregister():
|
||||
del bpy.types.Scene.CustomShelf
|
||||
del bpy.types.WindowManager.CustomShelf
|
||||
|
||||
for bl_class in bl_classes :
|
||||
for bl_class in bl_classes:
|
||||
bpy.utils.unregister_class(bl_class)
|
||||
|
||||
197
functions.py
197
functions.py
@ -1,197 +1,222 @@
|
||||
from .utils import *
|
||||
from bpy.props import *
|
||||
from bpy.types import Panel,Operator
|
||||
from .properties import CustomShelfSettings,CustomShelfPrefs
|
||||
from bpy.types import Panel, Operator
|
||||
from .properties import CustomShelfSettings, CustomShelfPrefs
|
||||
from .Types import *
|
||||
|
||||
|
||||
SHELF_DIR = join(dirname(__file__),'shelves')
|
||||
SHELF_DIR = join(dirname(__file__), "shelves")
|
||||
|
||||
|
||||
def operator(idname,args) :
|
||||
op_execute = args['execute']
|
||||
def operator(idname, args):
|
||||
op_execute = args["execute"]
|
||||
|
||||
def execute(self, context):
|
||||
op_execute(context,self)
|
||||
op_execute(context, self)
|
||||
return {"FINISHED"}
|
||||
|
||||
package = __package__.replace('_','').replace('-','').lower()
|
||||
package = __package__.replace("_", "").replace("-", "").lower()
|
||||
|
||||
args['bl_idname'] = "%s.%s"%(package,idname)
|
||||
args['bl_label'] = title(idname)
|
||||
args['execute'] = execute
|
||||
args["bl_idname"] = "%s.%s" % (package, idname)
|
||||
args["bl_label"] = title(idname)
|
||||
args["execute"] = execute
|
||||
|
||||
op = type('operator',(Operator,),args)
|
||||
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)
|
||||
|
||||
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 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)]
|
||||
return [p for p in additionnal_shelves_path + [shelves_path] if exists(p)]
|
||||
|
||||
|
||||
|
||||
def get_dirs(paths) :
|
||||
if isinstance(paths,(tuple,list)) :
|
||||
def get_dirs(paths):
|
||||
if isinstance(paths, (tuple, list)):
|
||||
dirs = []
|
||||
for dir in paths:
|
||||
if not isinstance(dir, str) :
|
||||
if not isinstance(dir, str):
|
||||
dir = dir.path
|
||||
dirs += filter_dir(scandir(dir))
|
||||
return dirs
|
||||
else :
|
||||
else:
|
||||
return filter_dir(scandir(paths))
|
||||
|
||||
|
||||
def get_categories():
|
||||
return [d.name for d in get_dirs(get_shelves_folder())]
|
||||
|
||||
def get_tabs() :
|
||||
|
||||
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_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() :
|
||||
def read_shelves():
|
||||
tag_filter_items = []
|
||||
|
||||
# unregister panel :
|
||||
for panel in CustomShelfSettings.panel_list:
|
||||
print(panel)
|
||||
if panel.__name__ not in get_tabs():
|
||||
try :
|
||||
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()
|
||||
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
|
||||
"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)
|
||||
header = type("Header", (CSHELF_PT_shelf_header,), header_info)
|
||||
|
||||
bpy.utils.register_class(header)
|
||||
|
||||
|
||||
#enable bool prefs
|
||||
# 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)
|
||||
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
|
||||
# search and filter
|
||||
props = {
|
||||
"search" : StringProperty(options = {"TEXTEDIT_UPDATE"}),
|
||||
"filter" : BoolProperty(default = True)
|
||||
"search": StringProperty(options={"TEXTEDIT_UPDATE"}),
|
||||
"filter": BoolProperty(default=True),
|
||||
}
|
||||
# Props = type("props",(PropertyGroup,), props)# annotation error
|
||||
Props = type("props",(PropertyGroup,),{'__annotations__': props})
|
||||
Props = type("props", (PropertyGroup,), {"__annotations__": props})
|
||||
bpy.utils.register_class(Props)
|
||||
|
||||
setattr(CustomShelfSettings,cat.name,PointerProperty(type = Props))
|
||||
setattr(CustomShelfSettings, cat.name, PointerProperty(type=Props))
|
||||
|
||||
#enable bool prefs
|
||||
#Prefs = type("CustomShelfPrefs",(PropertyGroup,),{})
|
||||
#bpy.utils.register_class(Prefs)
|
||||
# enable bool prefs
|
||||
# Prefs = type("CustomShelfPrefs",(PropertyGroup,),{})
|
||||
# bpy.utils.register_class(Prefs)
|
||||
|
||||
#setattr(CustomShelfPrefs,cat.name,PointerProperty(type = Prefs))
|
||||
# setattr(CustomShelfPrefs,cat.name,PointerProperty(type = Prefs))
|
||||
|
||||
for tab in get_dirs(cat.path) :
|
||||
#get_settings
|
||||
settings_json = join(tab.path,'settings.json')
|
||||
for tab in get_dirs(cat.path):
|
||||
# get_settings
|
||||
settings_json = join(tab.path, "settings.json")
|
||||
|
||||
tab_settings = {}
|
||||
if exists(settings_json) :
|
||||
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 :
|
||||
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
|
||||
"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")}
|
||||
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)
|
||||
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'):
|
||||
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, lines = read_info(script.path)
|
||||
|
||||
info["description"] = info.get('description',"")
|
||||
info["description"] = info.get("description", "")
|
||||
|
||||
icon = info.get('icon', "WORDWRAP_OFF")
|
||||
icon = info.get("icon", "WORDWRAP_OFF")
|
||||
|
||||
popup = type(script_name, (CSHELF_OT_shelf_popup,),
|
||||
{"script": script.path,
|
||||
'bl_description': info["description"]
|
||||
})
|
||||
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})
|
||||
scripts.append(
|
||||
{"operator": popup.bl_idname, "text": script_name, "icon": icon}
|
||||
)
|
||||
|
||||
panel.scripts = sorted(scripts,key = lambda x :x['text'])
|
||||
panel.scripts = sorted(scripts, key=lambda x: x["text"])
|
||||
|
||||
#Register tag filter enum
|
||||
#setattr(Pre, v)
|
||||
# Register tag filter enum
|
||||
# setattr(Pre, v)
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
|
||||
tag_filter_items.sort()
|
||||
tag_filter_items.insert(0, '__clear__')
|
||||
tag_filter_items.insert(0, "__clear__")
|
||||
|
||||
prefs['tag_filter_items'] = tag_filter_items
|
||||
prefs["tag_filter_items"] = tag_filter_items
|
||||
|
||||
#bpy.utils.unregister_class(CustomShelfPrefs)
|
||||
#bpy.utils.register_class(CustomShelfPrefs)
|
||||
#CustomShelfSettings.folders = list(get_shelves_folder().keys())
|
||||
# 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)
|
||||
# folder_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in CustomShelfSettings.folders])
|
||||
# setattr(CustomShelfSettings,'folders_enum',folder_enum)
|
||||
|
||||
342
operators.py
342
operators.py
@ -7,232 +7,323 @@ from .properties import CustomShelfSettings
|
||||
|
||||
class CSHELF_OT_refresh(Operator):
|
||||
bl_idname = "customshelf.refresh"
|
||||
bl_label = 'Refresh Shelves'
|
||||
bl_label = "Refresh Shelves"
|
||||
|
||||
def execute(self,context) :
|
||||
def execute(self, context):
|
||||
read_shelves()
|
||||
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
def get_tag_items(self,context) :
|
||||
def get_tag_items(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
return [(i,i.title(),"") for i in prefs['tag_filter_items']]
|
||||
return [(i, i.title(), "") for i in prefs["tag_filter_items"]]
|
||||
|
||||
|
||||
class CSHELF_OT_set_tag_filter(Operator):
|
||||
bl_idname = "customshelf.set_tag_filter"
|
||||
bl_label = 'Refresh Shelves'
|
||||
bl_label = "Refresh Shelves"
|
||||
|
||||
tag_filter : EnumProperty(items = get_tag_items)
|
||||
tag_filter: EnumProperty(items=get_tag_items)
|
||||
|
||||
def execute(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
|
||||
tag_filter = self.tag_filter
|
||||
if tag_filter == '__clear__' :
|
||||
if tag_filter == "__clear__":
|
||||
tag_filter = ""
|
||||
|
||||
prefs.tag_filter = tag_filter
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CSHELF_OT_add_shelf_folder(Operator):
|
||||
bl_idname = "customshelf.add_shelves_folder"
|
||||
bl_label = 'Refresh Shelves'
|
||||
bl_label = "Refresh Shelves"
|
||||
|
||||
def execute(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
path = prefs.additionnal_shelves.add()
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CSHELF_OT_remove_shelf_folder(Operator):
|
||||
bl_idname = "customshelf.remove_shelves_folder"
|
||||
bl_label = 'Refresh Shelves'
|
||||
bl_label = "Refresh Shelves"
|
||||
|
||||
index : IntProperty()
|
||||
index: IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
prefs.additionnal_shelves.remove(self.index)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CSHELF_OT_open_shelf_folder(Operator):
|
||||
bl_idname = "customshelf.open_shelf_folder"
|
||||
bl_label = 'Run Function'
|
||||
bl_label = "Run Function"
|
||||
|
||||
path : StringProperty()
|
||||
path: StringProperty()
|
||||
|
||||
def execute(self,context) :
|
||||
def execute(self, context):
|
||||
open_folder(self.path)
|
||||
|
||||
return {'FINISHED'}
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CSHELF_OT_add_script(Operator) :
|
||||
class CSHELF_OT_add_script(Operator):
|
||||
bl_idname = "customshelf.add_script"
|
||||
bl_label = 'Add script to a shelf'
|
||||
bl_label = "Add script to a shelf"
|
||||
|
||||
add_category : BoolProperty()
|
||||
add_tab : BoolProperty()
|
||||
new_category : StringProperty()
|
||||
new_tab : StringProperty()
|
||||
add_category: BoolProperty()
|
||||
add_tab: BoolProperty()
|
||||
new_category: StringProperty()
|
||||
new_tab: StringProperty()
|
||||
|
||||
name : StringProperty()
|
||||
description : StringProperty()
|
||||
icon : StringProperty()
|
||||
show_icons : BoolProperty()
|
||||
name: StringProperty()
|
||||
description: StringProperty()
|
||||
icon: StringProperty()
|
||||
show_icons: BoolProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.area.type == 'TEXT_EDITOR' and context.space_data.text
|
||||
return context.area.type == "TEXT_EDITOR" and context.space_data.text
|
||||
|
||||
def add_folder(self,context,op) :
|
||||
def add_folder(self, context, op):
|
||||
folder = self.folder.add()
|
||||
folder.name = self.name
|
||||
#CustomShelfSettings
|
||||
# CustomShelfSettings
|
||||
|
||||
def remove_folder(self,context,op) :
|
||||
def remove_folder(self, context, op):
|
||||
bl_props = context.scene.CustomShelf
|
||||
index = self.folders.find(self.folders_enum)
|
||||
self.folders.remove(index)
|
||||
|
||||
def get_all_icons (self) :
|
||||
def get_all_icons(self):
|
||||
ui_layout = bpy.types.UILayout
|
||||
icons = ui_layout.bl_rna.functions["prop"].parameters["icon"].enum_items.keys()
|
||||
|
||||
prefixes = ('BRUSH_','MATCAP_','COLORSET_')
|
||||
exception = ('BRUSH_DATA')
|
||||
prefixes = ("BRUSH_", "MATCAP_", "COLORSET_")
|
||||
exception = "BRUSH_DATA"
|
||||
|
||||
return [i for i in icons if not i.startswith(prefixes) or i in exception]
|
||||
|
||||
def get_icons(self,context,op) :
|
||||
def get_icons(self, context, op):
|
||||
icons = [
|
||||
["SCENE_DATA","RENDERLAYERS","MATERIAL_DATA","GROUP_UVS","TEXTURE","WORLD","SPEAKER","TEXT","NODETREE","NODE_INSERT_OFF","PARTICLES","SORTALPHA"],
|
||||
["MODIFIER","MOD_WAVE","MOD_SUBSURF","MOD_FLUIDSIM","MOD_OCEAN","BLANK1",
|
||||
"ARMATURE_DATA","BONE_DATA","GROUP_BONE"],
|
||||
["SEQUENCE","CAMERA_DATA","SCENE","BLANK1",
|
||||
"FILE_NEW","CONSOLE","BLENDER","APPEND_BLEND"],
|
||||
["GROUP","MESH_CUBE","MESH_PLANE","MESH_CIRCLE","MESH_UVSPHERE","MESH_GRID","EMPTY_DATA","OUTLINER_DATA_MESH",
|
||||
"LIGHT_SUN","LIGHT_SPOT","LIGHT"],
|
||||
["TRIA_RIGHT_BAR","REC","PLAY","PREV_KEYFRAME","NEXT_KEYFRAME","PAUSE","X","ADD","REMOVE","RESTRICT_VIEW_OFF","RESTRICT_VIEW_ON","RESTRICT_SELECT_OFF",],
|
||||
["BRUSH_DATA","GREASEPENCIL","LINE_DATA","PARTICLEMODE","SCULPTMODE_HLT","WPAINT_HLT","TPAINT_HLT","VIEWZOOM","HAND","KEY_HLT","KEY_DEHLT",],
|
||||
["PLUGIN","SCRIPT","PREFERENCES",
|
||||
"ACTION","SOLO_OFF",
|
||||
"RNDCURVE","SNAP_ON",
|
||||
"FORCE_WIND","COPY_ID","EYEDROPPER","AUTO","UNLOCKED","LOCKED",
|
||||
"UNPINNED","PINNED","PLUGIN","HELP","GHOST_ENABLED","GHOST_DISABLED","COLOR",
|
||||
"LINKED","UNLINKED","LINKED","ZOOM_ALL",
|
||||
"FREEZE","STYLUS_PRESSURE","FILE_TICK",
|
||||
"QUIT","RECOVER_LAST","TIME","PREVIEW_RANGE",
|
||||
"OUTLINER","NLA","EDITMODE_HLT",
|
||||
"BOIDS","RNA","CAMERA_STEREO"],
|
||||
[
|
||||
"SCENE_DATA",
|
||||
"RENDERLAYERS",
|
||||
"MATERIAL_DATA",
|
||||
"GROUP_UVS",
|
||||
"TEXTURE",
|
||||
"WORLD",
|
||||
"SPEAKER",
|
||||
"TEXT",
|
||||
"NODETREE",
|
||||
"NODE_INSERT_OFF",
|
||||
"PARTICLES",
|
||||
"SORTALPHA",
|
||||
],
|
||||
[
|
||||
"MODIFIER",
|
||||
"MOD_WAVE",
|
||||
"MOD_SUBSURF",
|
||||
"MOD_FLUIDSIM",
|
||||
"MOD_OCEAN",
|
||||
"BLANK1",
|
||||
"ARMATURE_DATA",
|
||||
"BONE_DATA",
|
||||
"GROUP_BONE",
|
||||
],
|
||||
[
|
||||
"SEQUENCE",
|
||||
"CAMERA_DATA",
|
||||
"SCENE",
|
||||
"BLANK1",
|
||||
"FILE_NEW",
|
||||
"CONSOLE",
|
||||
"BLENDER",
|
||||
"APPEND_BLEND",
|
||||
],
|
||||
[
|
||||
"GROUP",
|
||||
"MESH_CUBE",
|
||||
"MESH_PLANE",
|
||||
"MESH_CIRCLE",
|
||||
"MESH_UVSPHERE",
|
||||
"MESH_GRID",
|
||||
"EMPTY_DATA",
|
||||
"OUTLINER_DATA_MESH",
|
||||
"LIGHT_SUN",
|
||||
"LIGHT_SPOT",
|
||||
"LIGHT",
|
||||
],
|
||||
[
|
||||
"TRIA_RIGHT_BAR",
|
||||
"REC",
|
||||
"PLAY",
|
||||
"PREV_KEYFRAME",
|
||||
"NEXT_KEYFRAME",
|
||||
"PAUSE",
|
||||
"X",
|
||||
"ADD",
|
||||
"REMOVE",
|
||||
"RESTRICT_VIEW_OFF",
|
||||
"RESTRICT_VIEW_ON",
|
||||
"RESTRICT_SELECT_OFF",
|
||||
],
|
||||
[
|
||||
"BRUSH_DATA",
|
||||
"GREASEPENCIL",
|
||||
"LINE_DATA",
|
||||
"PARTICLEMODE",
|
||||
"SCULPTMODE_HLT",
|
||||
"WPAINT_HLT",
|
||||
"TPAINT_HLT",
|
||||
"VIEWZOOM",
|
||||
"HAND",
|
||||
"KEY_HLT",
|
||||
"KEY_DEHLT",
|
||||
],
|
||||
[
|
||||
"PLUGIN",
|
||||
"SCRIPT",
|
||||
"PREFERENCES",
|
||||
"ACTION",
|
||||
"SOLO_OFF",
|
||||
"RNDCURVE",
|
||||
"SNAP_ON",
|
||||
"FORCE_WIND",
|
||||
"COPY_ID",
|
||||
"EYEDROPPER",
|
||||
"AUTO",
|
||||
"UNLOCKED",
|
||||
"LOCKED",
|
||||
"UNPINNED",
|
||||
"PINNED",
|
||||
"PLUGIN",
|
||||
"HELP",
|
||||
"GHOST_ENABLED",
|
||||
"GHOST_DISABLED",
|
||||
"COLOR",
|
||||
"LINKED",
|
||||
"UNLINKED",
|
||||
"LINKED",
|
||||
"ZOOM_ALL",
|
||||
"FREEZE",
|
||||
"STYLUS_PRESSURE",
|
||||
"FILE_TICK",
|
||||
"QUIT",
|
||||
"RECOVER_LAST",
|
||||
"TIME",
|
||||
"PREVIEW_RANGE",
|
||||
"OUTLINER",
|
||||
"NLA",
|
||||
"EDITMODE_HLT",
|
||||
"BOIDS",
|
||||
"RNA",
|
||||
"CAMERA_STEREO",
|
||||
],
|
||||
]
|
||||
|
||||
self.icons = icons
|
||||
|
||||
|
||||
def set_icon(self,context,op) :
|
||||
#bl_props = context.scene.CustomShelf
|
||||
def set_icon(self, context, op):
|
||||
# bl_props = context.scene.CustomShelf
|
||||
self.icon = op.icon
|
||||
self.icons = []
|
||||
|
||||
|
||||
def draw(self,context) :
|
||||
def draw(self, context):
|
||||
bl_props = context.scene.CustomShelf
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row()
|
||||
row.operator("customshelf.get_icons",text= '',icon = self.icon)
|
||||
row.prop(self,"name",text ="")
|
||||
row.operator("customshelf.get_icons", text="", icon=self.icon)
|
||||
row.prop(self, "name", text="")
|
||||
|
||||
col = layout.column(align = True)
|
||||
col = layout.column(align=True)
|
||||
|
||||
for icon_list in self.icons:
|
||||
i = 0
|
||||
for icon in icon_list:
|
||||
if not i % 12:
|
||||
row = col.row(align=True)
|
||||
|
||||
for icon_list in self.icons :
|
||||
i=0
|
||||
for icon in icon_list :
|
||||
if not i%12 :
|
||||
row = col.row(align= True)
|
||||
|
||||
row.operator("customshelf.set_icon", icon=icon, emboss=False, text="").icon=icon
|
||||
row.operator(
|
||||
"customshelf.set_icon", icon=icon, emboss=False, text=""
|
||||
).icon = icon
|
||||
i += 1
|
||||
row = col.row(align= True)
|
||||
row = col.row(align=True)
|
||||
|
||||
layout.prop(self, "description", text="")
|
||||
layout.separator()
|
||||
|
||||
#Category Row
|
||||
folder_row = layout.row(align = True)
|
||||
folder_row.label(text="", icon='FILE_FOLDER')
|
||||
# Category Row
|
||||
folder_row = layout.row(align=True)
|
||||
folder_row.label(text="", icon="FILE_FOLDER")
|
||||
folder_row.separator()
|
||||
if not self.add_category :
|
||||
folder_row.prop(bl_props,"category_enum",expand = True)
|
||||
if not self.add_category:
|
||||
folder_row.prop(bl_props, "category_enum", expand=True)
|
||||
|
||||
else :
|
||||
else:
|
||||
|
||||
folder_row.prop(self,"new_category",text='')
|
||||
folder_row.prop(self, "new_category", text="")
|
||||
|
||||
folder_row.prop(self,"add_category",icon = 'ADD',text='')
|
||||
folder_row.prop(self, "add_category", icon="ADD", text="")
|
||||
|
||||
# Tabs row
|
||||
tab_row = layout.row(align = True)
|
||||
tab_row.label(text='', icon='MENU_PANEL')
|
||||
tab_row = layout.row(align=True)
|
||||
tab_row.label(text="", icon="MENU_PANEL")
|
||||
tab_row.separator()
|
||||
if not self.add_tab :
|
||||
if not self.add_tab:
|
||||
category_tabs = get_category_tabs(bl_props.category_enum)
|
||||
for t in [t for t in category_tabs if t in self.tabs] :
|
||||
tab_row.prop_enum(bl_props,"tab_enum",t)
|
||||
for t in [t for t in category_tabs if t in self.tabs]:
|
||||
tab_row.prop_enum(bl_props, "tab_enum", t)
|
||||
|
||||
else :
|
||||
tab_row.prop(self,"new_tab",text='')
|
||||
else:
|
||||
tab_row.prop(self, "new_tab", text="")
|
||||
|
||||
tab_row.prop(self,"add_tab",icon = 'ADD',text='')
|
||||
#folder_row.operator("customshelf.remove_folder",icon = 'REMOVE',text='')
|
||||
tab_row.prop(self, "add_tab", icon="ADD", text="")
|
||||
# folder_row.operator("customshelf.remove_folder",icon = 'REMOVE',text='')
|
||||
|
||||
def write_script(self,f) :
|
||||
keys = ['icon','description']
|
||||
def write_script(self, f):
|
||||
keys = ["icon", "description"]
|
||||
keys += [k for k in self.info if k not in keys]
|
||||
f.write("info = "+dic_to_str(self.info,keys))
|
||||
f.write("info = " + dic_to_str(self.info, keys))
|
||||
|
||||
print(self.lines)
|
||||
f.write('\n'.join(self.lines))
|
||||
f.write("\n".join(self.lines))
|
||||
|
||||
|
||||
def execute(self,context) :
|
||||
def execute(self, context):
|
||||
preferences = context.preferences
|
||||
bl_props = context.scene.CustomShelf
|
||||
addon_prefs = preferences.addons[__package__].preferences
|
||||
|
||||
if self.new_category :
|
||||
if self.new_category:
|
||||
category_path = get_category_path(self.new_category)
|
||||
if not exists(category_path):
|
||||
mkdir(new_category)
|
||||
else :
|
||||
else:
|
||||
category_path = get_category_path(bl_props.category_enum)
|
||||
|
||||
if self.new_tab :
|
||||
if self.new_tab:
|
||||
tab_path = join(category_path, self.new_tab)
|
||||
if not exists(tab_path):
|
||||
mkdir(tab_path)
|
||||
else :
|
||||
tab_path = join(category_path,bl_props.tab_enum)
|
||||
else:
|
||||
tab_path = join(category_path, bl_props.tab_enum)
|
||||
|
||||
script_name = self.name.replace(" ", "_").replace("-", "_")
|
||||
|
||||
script_name = self.name.replace(' ','_').replace('-','_')
|
||||
|
||||
script_path = join(tab_path,script_name+'.py')
|
||||
script_path = join(tab_path, script_name + ".py")
|
||||
if os.path.exists(script_path):
|
||||
os.remove(script_path)
|
||||
|
||||
self.info["icon"] = self.icon
|
||||
self.info["description"] = self.description
|
||||
|
||||
self.info['icon'] = self.icon
|
||||
self.info['description'] = self.description
|
||||
|
||||
with open(script_path,"w") as f :
|
||||
with open(script_path, "w") as f:
|
||||
self.write_script(f)
|
||||
|
||||
line_index = self.active_text.current_line_index
|
||||
@ -246,21 +337,21 @@ class CSHELF_OT_add_script(Operator) :
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
def check(self,context) :
|
||||
def check(self, context):
|
||||
return True
|
||||
|
||||
def invoke(self,context,event) :
|
||||
def invoke(self, context, event):
|
||||
bl_props = context.scene.CustomShelf
|
||||
self.active_text = context.space_data.text
|
||||
|
||||
self.info,self.lines = read_info([l.body for l in self.active_text.lines])
|
||||
self.info, self.lines = read_info([l.body for l in self.active_text.lines])
|
||||
|
||||
icon = "LONGDISPLAY"
|
||||
if self.info.get('icon') :
|
||||
if self.info.get("icon"):
|
||||
icon = self.info["icon"]
|
||||
|
||||
description = "Some description"
|
||||
if self.info.get('description') :
|
||||
if self.info.get("description"):
|
||||
description = self.info["description"]
|
||||
|
||||
self.icon = icon
|
||||
@ -272,25 +363,32 @@ class CSHELF_OT_add_script(Operator) :
|
||||
self.new_shelf = ""
|
||||
self.icons = []
|
||||
|
||||
operator("get_icons", {'execute': self.get_icons})
|
||||
operator("set_icon", {'execute': self.set_icon, '__annotations__': {'icon' : StringProperty()}})
|
||||
operator("add_folder", {'execute': self.add_folder})
|
||||
#operator("remove_folder",{'execute':self.remove_folder})
|
||||
operator("get_icons", {"execute": self.get_icons})
|
||||
operator(
|
||||
"set_icon",
|
||||
{"execute": self.set_icon, "__annotations__": {"icon": StringProperty()}},
|
||||
)
|
||||
operator("add_folder", {"execute": self.add_folder})
|
||||
# operator("remove_folder",{'execute':self.remove_folder})
|
||||
|
||||
self.tabs = get_tabs()
|
||||
self.categories = get_categories()
|
||||
|
||||
CustomShelfSettings.category_enum = EnumProperty(items=[(i,i,"") for i in self.categories])
|
||||
CustomShelfSettings.tab_enum = EnumProperty(items=[(i,i,"") for i in self.tabs])
|
||||
CustomShelfSettings.category_enum = EnumProperty(
|
||||
items=[(i, i, "") for i in self.categories]
|
||||
)
|
||||
CustomShelfSettings.tab_enum = EnumProperty(
|
||||
items=[(i, i, "") for i in self.tabs]
|
||||
)
|
||||
|
||||
if self.active_text.filepath :
|
||||
if self.active_text.filepath:
|
||||
tab_path = dirname(self.active_text.filepath)
|
||||
category = basename(dirname(tab_path))
|
||||
tab = basename(tab_path)
|
||||
|
||||
if category in self.categories :
|
||||
if category in self.categories:
|
||||
bl_props.category_enum = category
|
||||
if tab in self.tabs :
|
||||
if tab in self.tabs:
|
||||
bl_props.tab_enum = tab
|
||||
|
||||
return context.window_manager.invoke_props_dialog(self, width=500)
|
||||
|
||||
@ -2,47 +2,53 @@ from .utils import *
|
||||
from bpy.props import *
|
||||
|
||||
|
||||
|
||||
class CustomShelfSettings(bpy.types.PropertyGroup) :
|
||||
class CustomShelfSettings(bpy.types.PropertyGroup):
|
||||
panel_list = []
|
||||
#category_enum = EnumProperty(items = )
|
||||
#tab_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in s.tabs])
|
||||
# category_enum = EnumProperty(items = )
|
||||
# tab_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in s.tabs])
|
||||
|
||||
#search = StringProperty(options = {"TEXTEDIT_UPDATE"})
|
||||
#filter = BoolProperty(default = True)
|
||||
#folders = PointerProperty(type= CustomShelfFolders)
|
||||
#variables = bpy.props.PointerProperty(type= CustomShelfVariables)
|
||||
# search = StringProperty(options = {"TEXTEDIT_UPDATE"})
|
||||
# filter = BoolProperty(default = True)
|
||||
# folders = PointerProperty(type= CustomShelfFolders)
|
||||
# variables = bpy.props.PointerProperty(type= CustomShelfVariables)
|
||||
|
||||
class CustomShelfProps(bpy.types.PropertyGroup) :
|
||||
|
||||
class CustomShelfProps(bpy.types.PropertyGroup):
|
||||
pass
|
||||
|
||||
class AdditionnalShelves(bpy.types.PropertyGroup) :
|
||||
path: StringProperty(name="Path",subtype = 'FILE_PATH')
|
||||
|
||||
class AdditionnalShelves(bpy.types.PropertyGroup):
|
||||
path: StringProperty(name="Path", subtype="FILE_PATH")
|
||||
|
||||
|
||||
class CustomShelfPrefs(bpy.types.AddonPreferences):
|
||||
bl_idname = __package__
|
||||
|
||||
global_path = join(dirname(__file__),'shelves')
|
||||
global_shelves : StringProperty(name="Shelves Path",subtype = 'DIR_PATH',default =global_path)
|
||||
additionnal_shelves : CollectionProperty(type = AdditionnalShelves)
|
||||
tag_filter : StringProperty()
|
||||
|
||||
global_path = join(dirname(__file__), "shelves")
|
||||
global_shelves: StringProperty(
|
||||
name="Shelves Path", subtype="DIR_PATH", default=global_path
|
||||
)
|
||||
additionnal_shelves: CollectionProperty(type=AdditionnalShelves)
|
||||
tag_filter: StringProperty()
|
||||
|
||||
def draw(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
layout = self.layout
|
||||
layout.prop(self, "global_shelves")
|
||||
|
||||
row = layout.row(align = True)
|
||||
row.operator("customshelf.add_shelves_folder",icon="ADD",text="")
|
||||
row.label(text='Additionnal Shelves folder')
|
||||
row = layout.row(align=True)
|
||||
row.operator("customshelf.add_shelves_folder", icon="ADD", text="")
|
||||
row.label(text="Additionnal Shelves folder")
|
||||
|
||||
for i,shelf in enumerate(prefs.additionnal_shelves) :
|
||||
row = layout.row(align = True)
|
||||
for i, shelf in enumerate(prefs.additionnal_shelves):
|
||||
row = layout.row(align=True)
|
||||
row.prop(shelf, "path")
|
||||
row.operator("customshelf.remove_shelves_folder",icon="REMOVE",text="").index = i
|
||||
row.operator(
|
||||
"customshelf.remove_shelves_folder", icon="REMOVE", text=""
|
||||
).index = i
|
||||
|
||||
row = layout.row(align = True)
|
||||
row = layout.row(align=True)
|
||||
row.prop(self, "tag_filter")
|
||||
row.operator_menu_enum("customshelf.set_tag_filter",'tag_filter',icon= "DOWNARROW_HLT",text='')
|
||||
row.operator_menu_enum(
|
||||
"customshelf.set_tag_filter", "tag_filter", icon="DOWNARROW_HLT", text=""
|
||||
)
|
||||
|
||||
12
pyproject.toml
Normal file
12
pyproject.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[project]
|
||||
name = "custom-shelf"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"black>=25.11.0",
|
||||
]
|
||||
5
ui.py
5
ui.py
@ -1,4 +1,3 @@
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
@ -7,9 +6,7 @@ class CSHELF_MT_text_editor(bpy.types.Menu):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("customshelf.add_script", text='Add Script', icon="FILE_NEW")
|
||||
|
||||
|
||||
layout.operator("customshelf.add_script", text="Add Script", icon="FILE_NEW")
|
||||
|
||||
|
||||
"""
|
||||
|
||||
227
utils.py
227
utils.py
@ -1,192 +1,231 @@
|
||||
import bpy
|
||||
import os
|
||||
from os import listdir,mkdir,scandir
|
||||
from os.path import join,dirname,splitext,isdir,exists,basename
|
||||
from os import listdir, mkdir, scandir
|
||||
from os.path import join, dirname, splitext, isdir, exists, basename
|
||||
from bpy.types import Operator, Panel, PropertyGroup
|
||||
from bpy.props import *
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
|
||||
id_type = {"Action" : "actions", "Armature":"armatures", "Brush":"brushes", "CacheFile":"cache_files", "Camera":"cameras",
|
||||
"Curve":"curves", "FreestyleLineStyle":"linestyles", "GreasePencil":"grease_pencil", "Group":"groups",
|
||||
"Image":"images", "Key":"shape_keys", "Light":"lights", "Lattice":"lattices", "Library":"librairies", "Mask":"masks",
|
||||
"Material":"materials", "Mesh":"meshes", "MetaBall":"metaballs", "MovieClip":"movieclips", "NodeTree":"node_groups",
|
||||
"Object":"objects", "PaintCurve":"paint_curves", "Palette":"palettes", "ParticleSettings":"particles",
|
||||
"Scene":"scenes", "Screen":"screens", "Sound":"sounds", "Speaker":"speakers", "Text":"texts", "Texture":"textures",
|
||||
"Collection":"collections", "VectorFont":"fonts", "WindowManager":"window_managers", "World":"worlds"}
|
||||
id_type = {
|
||||
"Action": "actions",
|
||||
"Armature": "armatures",
|
||||
"Brush": "brushes",
|
||||
"CacheFile": "cache_files",
|
||||
"Camera": "cameras",
|
||||
"Curve": "curves",
|
||||
"FreestyleLineStyle": "linestyles",
|
||||
"GreasePencil": "grease_pencil",
|
||||
"Group": "groups",
|
||||
"Image": "images",
|
||||
"Key": "shape_keys",
|
||||
"Light": "lights",
|
||||
"Lattice": "lattices",
|
||||
"Library": "librairies",
|
||||
"Mask": "masks",
|
||||
"Material": "materials",
|
||||
"Mesh": "meshes",
|
||||
"MetaBall": "metaballs",
|
||||
"MovieClip": "movieclips",
|
||||
"NodeTree": "node_groups",
|
||||
"Object": "objects",
|
||||
"PaintCurve": "paint_curves",
|
||||
"Palette": "palettes",
|
||||
"ParticleSettings": "particles",
|
||||
"Scene": "scenes",
|
||||
"Screen": "screens",
|
||||
"Sound": "sounds",
|
||||
"Speaker": "speakers",
|
||||
"Text": "texts",
|
||||
"Texture": "textures",
|
||||
"Collection": "collections",
|
||||
"VectorFont": "fonts",
|
||||
"WindowManager": "window_managers",
|
||||
"World": "worlds",
|
||||
}
|
||||
|
||||
|
||||
|
||||
def report(var,message,type='INFO') :
|
||||
def report(var, message, type="INFO"):
|
||||
print([a for a in locals()])
|
||||
print([a for a in globals()])
|
||||
|
||||
if "self" in var:
|
||||
var["self"].report({type}, message)
|
||||
|
||||
if 'self' in var :
|
||||
var['self'].report({type}, message)
|
||||
|
||||
else :
|
||||
print('')
|
||||
else:
|
||||
print("")
|
||||
print(type)
|
||||
print(message)
|
||||
|
||||
|
||||
def read_json(path):
|
||||
jsonFile = path
|
||||
if os.path.exists(jsonFile):
|
||||
try :
|
||||
try:
|
||||
with open(jsonFile) as data_file:
|
||||
return (json.load(data_file))
|
||||
except :
|
||||
print("the file %s not json readable"%jsonFile)
|
||||
return json.load(data_file)
|
||||
except:
|
||||
print("the file %s not json readable" % jsonFile)
|
||||
return
|
||||
|
||||
|
||||
|
||||
def search_filter(search,str) :
|
||||
def search_filter(search, str):
|
||||
return search.lower() in str.lower()
|
||||
|
||||
def title(string) :
|
||||
return string.replace('_',' ').replace('-',' ').title()
|
||||
|
||||
def arg_name(string) :
|
||||
return string.replace(' ','_').replace('-','_').lower().strip('_')
|
||||
def title(string):
|
||||
return string.replace("_", " ").replace("-", " ").title()
|
||||
|
||||
def open_folder(path) :
|
||||
|
||||
def arg_name(string):
|
||||
return string.replace(" ", "_").replace("-", "_").lower().strip("_")
|
||||
|
||||
|
||||
def open_folder(path):
|
||||
try:
|
||||
os.startfile(path)
|
||||
except:
|
||||
subprocess.Popen(['xdg-open', path])
|
||||
subprocess.Popen(["xdg-open", path])
|
||||
|
||||
|
||||
def dic_to_args(dic):
|
||||
import collections
|
||||
|
||||
args = collections.OrderedDict()
|
||||
|
||||
prop_type = {
|
||||
str: StringProperty,
|
||||
bool: BoolProperty,
|
||||
float: FloatProperty,
|
||||
int : IntProperty
|
||||
int: IntProperty,
|
||||
}
|
||||
|
||||
for k, v in dic.items() :
|
||||
if k in ('icon','description') or not isinstance(k,str):
|
||||
for k, v in dic.items():
|
||||
if k in ("icon", "description") or not isinstance(k, str):
|
||||
continue
|
||||
|
||||
if isinstance(v,str) :
|
||||
if '/' in v or '\\' in v :
|
||||
args[k] = StringProperty(default=v,subtype = "FILE_PATH")
|
||||
else :
|
||||
if isinstance(v, str):
|
||||
if "/" in v or "\\" in v:
|
||||
args[k] = StringProperty(default=v, subtype="FILE_PATH")
|
||||
else:
|
||||
args[k] = StringProperty(default=v)
|
||||
|
||||
elif isinstance(v,bool) :
|
||||
elif isinstance(v, bool):
|
||||
args[k] = BoolProperty(default=v)
|
||||
|
||||
elif isinstance(v, float) :
|
||||
args[k] = FloatProperty(default=v,precision=3)
|
||||
elif isinstance(v, float):
|
||||
args[k] = FloatProperty(default=v, precision=3)
|
||||
|
||||
elif isinstance(v,int) :
|
||||
elif isinstance(v, int):
|
||||
args[k] = IntProperty(default=v)
|
||||
|
||||
elif isinstance(v, dict) :
|
||||
if v.get("items") and isinstance(v["items"],(tuple,list)) :
|
||||
args[k] = EnumProperty(items = [(i,i,"") for i in v["items"]])
|
||||
elif isinstance(v, dict):
|
||||
if v.get("items") and isinstance(v["items"], (tuple, list)):
|
||||
args[k] = EnumProperty(items=[(i, i, "") for i in v["items"]])
|
||||
|
||||
elif v.get("collection") and isinstance(v["collection"],str) :
|
||||
if v["collection"] not in id_type :
|
||||
print("Collection %s not supported must be in %s"%(v["collection"],id_type))
|
||||
#args[k] = PointerProperty(type = getattr(bpy.types,v["collection"]))
|
||||
else :
|
||||
args[k] = PointerProperty(type = getattr(bpy.types,v["collection"]),poll = v.get('poll'))
|
||||
elif v.get("collection") and isinstance(v["collection"], str):
|
||||
if v["collection"] not in id_type:
|
||||
print(
|
||||
"Collection %s not supported must be in %s"
|
||||
% (v["collection"], id_type)
|
||||
)
|
||||
# args[k] = PointerProperty(type = getattr(bpy.types,v["collection"]))
|
||||
else:
|
||||
args[k] = PointerProperty(
|
||||
type=getattr(bpy.types, v["collection"]), poll=v.get("poll")
|
||||
)
|
||||
else:
|
||||
args[k] = prop_type[type(v['default'])](**v)
|
||||
|
||||
|
||||
args[k] = prop_type[type(v["default"])](**v)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def read_info(script_path) :
|
||||
def read_info(script_path):
|
||||
import collections
|
||||
|
||||
if isinstance(script_path,list) :
|
||||
lines =script_path
|
||||
else :
|
||||
with open(script_path,encoding="utf-8") as f:
|
||||
if isinstance(script_path, list):
|
||||
lines = script_path
|
||||
else:
|
||||
with open(script_path, encoding="utf-8") as f:
|
||||
lines = f.read().splitlines()
|
||||
|
||||
info = {}
|
||||
for i,l in enumerate(lines) :
|
||||
if i >= 10 :
|
||||
return info,lines
|
||||
info = {}
|
||||
for i, l in enumerate(lines):
|
||||
if i >= 10:
|
||||
return info, lines
|
||||
|
||||
if l.startswith("info") :
|
||||
if l.startswith("info"):
|
||||
info_start = i
|
||||
info_str = l
|
||||
|
||||
while info_str.endswith(',') or not info_str.endswith('}') or i == len(lines)-1:
|
||||
i+=1
|
||||
info_str+= lines[i]
|
||||
while (
|
||||
info_str.endswith(",")
|
||||
or not info_str.endswith("}")
|
||||
or i == len(lines) - 1
|
||||
):
|
||||
i += 1
|
||||
info_str += lines[i]
|
||||
|
||||
info_end = i
|
||||
|
||||
opening_brace_index = info_str.find('{')
|
||||
opening_brace_index = info_str.find("{")
|
||||
|
||||
try :
|
||||
try:
|
||||
info = eval(info_str[opening_brace_index:])
|
||||
except :
|
||||
print('The info header in the file %s cannot be read'%script_path)
|
||||
except:
|
||||
print("The info header in the file %s cannot be read" % script_path)
|
||||
break
|
||||
|
||||
info = [(k,v) for k,v in info.items()]
|
||||
info.sort(key = lambda x : info_str.find(x[0]))
|
||||
info = [(k, v) for k, v in info.items()]
|
||||
info.sort(key=lambda x: info_str.find(x[0]))
|
||||
|
||||
info = collections.OrderedDict(info)
|
||||
|
||||
del lines[info_start:info_end+1]
|
||||
del lines[info_start : info_end + 1]
|
||||
|
||||
break
|
||||
|
||||
# remove backspace
|
||||
for i in range(len(lines)) :
|
||||
if lines[0] :
|
||||
for i in range(len(lines)):
|
||||
if lines[0]:
|
||||
break
|
||||
else :
|
||||
else:
|
||||
lines.pop(0)
|
||||
|
||||
for i in range(len(lines)) :
|
||||
if lines[-1] :
|
||||
for i in range(len(lines)):
|
||||
if lines[-1]:
|
||||
break
|
||||
else :
|
||||
else:
|
||||
lines.pop(-1)
|
||||
|
||||
return info,lines
|
||||
return info, lines
|
||||
|
||||
def dic_to_str(dic,keys= None,spaces = 4) :
|
||||
if not keys :
|
||||
|
||||
def dic_to_str(dic, keys=None, spaces=4):
|
||||
if not keys:
|
||||
keys = sorted(dic)
|
||||
|
||||
line = '{\n'
|
||||
for k in keys :
|
||||
line = "{\n"
|
||||
for k in keys:
|
||||
v = dic[k]
|
||||
|
||||
line += ' '*spaces
|
||||
line += " " * spaces
|
||||
|
||||
if isinstance(k,str) :
|
||||
line +="'%s'"%k
|
||||
else :
|
||||
line += "%s"%k
|
||||
if isinstance(k, str):
|
||||
line += "'%s'" % k
|
||||
else:
|
||||
line += "%s" % k
|
||||
|
||||
line += ' : '
|
||||
line += " : "
|
||||
|
||||
if isinstance(v,str) :
|
||||
line +="'%s'"%v
|
||||
else :
|
||||
line += "%s"%v
|
||||
if isinstance(v, str):
|
||||
line += "'%s'" % v
|
||||
else:
|
||||
line += "%s" % v
|
||||
|
||||
line += ',\n'
|
||||
line += ",\n"
|
||||
|
||||
line += '}\n\n'
|
||||
line += "}\n\n"
|
||||
|
||||
return line
|
||||
|
||||
113
uv.lock
generated
Normal file
113
uv.lock
generated
Normal file
@ -0,0 +1,113 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "25.11.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "platformdirs" },
|
||||
{ name = "pytokens" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669, upload-time = "2025-11-10T01:53:50.558Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac", size = 1772831, upload-time = "2025-11-10T02:03:47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96", size = 1608520, upload-time = "2025-11-10T01:58:46.895Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd", size = 1682719, upload-time = "2025-11-10T01:56:55.24Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409", size = 1362684, upload-time = "2025-11-10T01:57:07.639Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b", size = 1772446, upload-time = "2025-11-10T02:02:16.181Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd", size = 1607983, upload-time = "2025-11-10T02:02:52.502Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993", size = 1682481, upload-time = "2025-11-10T01:57:12.35Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c", size = 1363869, upload-time = "2025-11-10T01:58:24.608Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170", size = 1771358, upload-time = "2025-11-10T02:03:33.331Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545", size = 1612902, upload-time = "2025-11-10T01:59:33.382Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda", size = 1680571, upload-time = "2025-11-10T01:57:04.239Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664", size = 1382599, upload-time = "2025-11-10T01:57:57.427Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b", size = 204918, upload-time = "2025-11-10T01:53:48.917Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "custom-shelf"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "black" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [{ name = "black", specifier = ">=25.11.0" }]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.12.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytokens"
|
||||
version = "0.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" },
|
||||
]
|
||||
Loading…
x
Reference in New Issue
Block a user