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
|
from .properties import CustomShelfProps
|
||||||
|
|
||||||
|
|
||||||
class Types():
|
class Types:
|
||||||
def initialyse(self, label) :
|
def initialyse(self, label):
|
||||||
package = __package__.replace('_','').replace('-','').lower()
|
package = __package__.replace("_", "").replace("-", "").lower()
|
||||||
idname = label.replace(' ','_').replace('-','_').lower()
|
idname = label.replace(" ", "_").replace("-", "_").lower()
|
||||||
|
|
||||||
self.bl_label = title(label)
|
self.bl_label = title(label)
|
||||||
self.bl_idname = '%s.%s'%(package, idname)
|
self.bl_idname = "%s.%s" % (package, idname)
|
||||||
|
|
||||||
#self.bl_props = bpy.context.scene.CustomShelf
|
|
||||||
#self.prefs = ""
|
|
||||||
|
|
||||||
|
|
||||||
|
# self.bl_props = bpy.context.scene.CustomShelf
|
||||||
|
# self.prefs = ""
|
||||||
|
|
||||||
|
|
||||||
class CSHELF_OT_shelf_popup(Types, Operator):
|
class CSHELF_OT_shelf_popup(Types, Operator):
|
||||||
#props = None
|
# props = None
|
||||||
bl_options = {'REGISTER', 'UNDO'}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def props(self) :
|
def props(self):
|
||||||
#print(getattr(bpy.context.window_manager.CustomShelf,self.prop))
|
# print(getattr(bpy.context.window_manager.CustomShelf,self.prop))
|
||||||
return getattr(bpy.context.window_manager.CustomShelf, self.prop)
|
return getattr(bpy.context.window_manager.CustomShelf, self.prop)
|
||||||
|
|
||||||
def get_props(self):
|
def get_props(self):
|
||||||
properties = self.props.bl_rna.properties
|
properties = self.props.bl_rna.properties
|
||||||
#props =
|
# props =
|
||||||
return {k:v for k,v in self.args.items() if k in properties}
|
return {k: v for k, v in self.args.items() if k in properties}
|
||||||
|
|
||||||
def set_props(self,prop,value):
|
def set_props(self, prop, value):
|
||||||
setattr(bpy.context.window_manager.CustomShelf,prop,value)
|
setattr(bpy.context.window_manager.CustomShelf, prop, value)
|
||||||
|
|
||||||
def initialyse(self,label,info) :
|
def initialyse(self, label, info):
|
||||||
super().initialyse(CSHELF_OT_shelf_popup,label)
|
super().initialyse(CSHELF_OT_shelf_popup, label)
|
||||||
|
|
||||||
self.args = dic_to_args(info)
|
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)
|
bpy.utils.register_class(Props)
|
||||||
|
|
||||||
setattr(CustomShelfProps, arg_name(label), PointerProperty(type=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.info = info
|
||||||
self.prop = arg_name(label)
|
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)
|
return # props
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
if event.alt :
|
if event.alt:
|
||||||
for t in [t for t in bpy.data.texts if t.filepath == self.script] :
|
for t in [t for t in bpy.data.texts if t.filepath == self.script]:
|
||||||
bpy.data.texts.remove(t)
|
bpy.data.texts.remove(t)
|
||||||
|
|
||||||
text = bpy.data.texts.load(self.script)
|
text = bpy.data.texts.load(self.script)
|
||||||
|
|
||||||
areas = []
|
areas = []
|
||||||
text_editor = None
|
text_editor = None
|
||||||
for area in context.screen.areas :
|
for area in context.screen.areas:
|
||||||
if area.type == 'TEXT_EDITOR' :
|
if area.type == "TEXT_EDITOR":
|
||||||
text_editor = area
|
text_editor = area
|
||||||
|
|
||||||
else :
|
else:
|
||||||
areas.append(area)
|
areas.append(area)
|
||||||
if not text_editor :
|
if not text_editor:
|
||||||
bpy.ops.screen.area_split(direction = "VERTICAL")
|
bpy.ops.screen.area_split(direction="VERTICAL")
|
||||||
|
|
||||||
for area in context.screen.areas :
|
for area in context.screen.areas:
|
||||||
if area not in areas :
|
if area not in areas:
|
||||||
text_editor = area
|
text_editor = area
|
||||||
text_editor.type = "TEXT_EDITOR"
|
text_editor.type = "TEXT_EDITOR"
|
||||||
text_editor.spaces[0].show_syntax_highlight = True
|
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
|
text_editor.spaces[0].show_line_numbers = True
|
||||||
|
|
||||||
context_copy = context.copy()
|
context_copy = context.copy()
|
||||||
context_copy['area'] = text_editor
|
context_copy["area"] = text_editor
|
||||||
#bpy.ops.text.properties(context_copy)
|
# bpy.ops.text.properties(context_copy)
|
||||||
#bpy.ops.view3d.toolshelf(context_copy)
|
# bpy.ops.view3d.toolshelf(context_copy)
|
||||||
|
|
||||||
text_editor.spaces[0].text = text
|
text_editor.spaces[0].text = text
|
||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
else :
|
else:
|
||||||
if self.args :
|
if self.args:
|
||||||
#set default value for collection
|
# set default value for collection
|
||||||
for k,v in self.info.items() :
|
for k, v in self.info.items():
|
||||||
if isinstance(v,dict) and v.get('collection') :
|
if isinstance(v, dict) and v.get("collection"):
|
||||||
collection = getattr(bpy.data, id_type[v["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)
|
return context.window_manager.invoke_props_dialog(self)
|
||||||
else :
|
else:
|
||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
|
def bl_report(self, *args):
|
||||||
def bl_report(self,*args) :
|
if len(args) and args[0] in ("INFO", "ERROR", "WARNING"):
|
||||||
if len(args) and args[0] in ('INFO','ERROR', 'WARNING') :
|
return self.report({args[0]}, " ".join(args[1:]))
|
||||||
return self.report({args[0]},' '.join(args[1:]))
|
else:
|
||||||
else :
|
|
||||||
print(*args)
|
print(*args)
|
||||||
|
|
||||||
def execute(self,context):
|
def execute(self, context):
|
||||||
info, lines = read_info(self.script)
|
info, lines = read_info(self.script)
|
||||||
|
|
||||||
values = dict(info)
|
values = dict(info)
|
||||||
for arg in self.args :
|
for arg in self.args:
|
||||||
value = getattr(self.props,arg)
|
value = getattr(self.props, arg)
|
||||||
|
|
||||||
if hasattr(value,"name") :
|
if hasattr(value, "name"):
|
||||||
values[arg] = {'value': value.name}
|
values[arg] = {"value": value.name}
|
||||||
|
|
||||||
elif isinstance(info.get(arg),dict) :
|
elif isinstance(info.get(arg), dict):
|
||||||
values[arg] = {'value': value}
|
values[arg] = {"value": value}
|
||||||
|
|
||||||
else :
|
else:
|
||||||
values[arg] = value
|
values[arg] = value
|
||||||
|
|
||||||
info_str = "info = %s\n\n"%values
|
info_str = "info = %s\n\n" % values
|
||||||
lines_str = '\n'.join(lines)
|
lines_str = "\n".join(lines)
|
||||||
script = f"{info_str}\n\n{lines_str}"
|
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
|
layout = self.layout
|
||||||
bl_props = context.scene.CustomShelf
|
bl_props = context.scene.CustomShelf
|
||||||
|
|
||||||
#print(self.get_props())
|
# print(self.get_props())
|
||||||
|
|
||||||
for k in self.args :
|
for k in self.args:
|
||||||
#filter
|
# filter
|
||||||
|
|
||||||
row = layout.row(align = True)
|
row = layout.row(align=True)
|
||||||
row.label(text=title(k))
|
row.label(text=title(k))
|
||||||
|
|
||||||
row.prop(self.props,k,text='')
|
row.prop(self.props, k, text="")
|
||||||
#row.prop_search(self.props,k,self.props,k+"_prop_search",text='')
|
# row.prop_search(self.props,k,self.props,k+"_prop_search",text='')
|
||||||
#op = self.args[k+"_prop_search"]
|
# op = self.args[k+"_prop_search"]
|
||||||
#row.operator(op.bl_idname,text="",icon ="COLLAPSEMENU" )
|
# row.operator(op.bl_idname,text="",icon ="COLLAPSEMENU" )
|
||||||
|
|
||||||
|
def check(self, context):
|
||||||
def check(self,context) :
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
class ShelfPropSearch(Types,Operator):
|
class ShelfPropSearch(Types,Operator):
|
||||||
bl_property = "enum"
|
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_space_type = "VIEW_3D"
|
||||||
bl_region_type = "UI"
|
bl_region_type = "UI"
|
||||||
#bl_category = "SHELF"
|
# bl_category = "SHELF"
|
||||||
settings = {}
|
settings = {}
|
||||||
scripts = []
|
scripts = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def search_filter(search,str) :
|
def search_filter(search, str):
|
||||||
return search.lower() in str.lower()
|
return search.lower() in str.lower()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(self, context):
|
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
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
search = bl_props.search
|
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
|
is_taged = True
|
||||||
if self.settings and self.settings.get('tags') :
|
if self.settings and self.settings.get("tags"):
|
||||||
tag = prefs.tag_filter
|
tag = prefs.tag_filter
|
||||||
if not tag :
|
if not tag:
|
||||||
tag = os.getenv("CUSTOM_SHELF_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
|
return any(shelf) and is_taged
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
def draw(self,context) :
|
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
bl_props = getattr(context.scene.CustomShelf,self.cat)
|
bl_props = getattr(context.scene.CustomShelf, self.cat)
|
||||||
search = bl_props.search
|
search = bl_props.search
|
||||||
|
|
||||||
for script in self.scripts :
|
for script in self.scripts:
|
||||||
args = script.copy()
|
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"])
|
args["text"] = title(script["text"])
|
||||||
|
|
||||||
#print(script)
|
# print(script)
|
||||||
layout.operator(**args)
|
layout.operator(**args)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CSHELF_PT_shelf_header(Panel):
|
class CSHELF_PT_shelf_header(Panel):
|
||||||
bl_label = "Custom Shelf"
|
bl_label = "Custom Shelf"
|
||||||
bl_space_type = 'VIEW_3D'
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = 'UI'
|
bl_region_type = "UI"
|
||||||
bl_options = {"HIDE_HEADER"}
|
bl_options = {"HIDE_HEADER"}
|
||||||
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
bl_props = bpy.context.scene.CustomShelf
|
bl_props = bpy.context.scene.CustomShelf
|
||||||
@ -256,16 +243,20 @@ class CSHELF_PT_shelf_header(Panel):
|
|||||||
|
|
||||||
cat_props = getattr(bl_props, self.cat)
|
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_menu_enum(
|
||||||
row.operator("customshelf.refresh", text='',emboss=True,icon= "FILE_REFRESH")
|
"customshelf.set_tag_filter", "tag_filter", icon="DOWNARROW_HLT", text=""
|
||||||
#row.separator()
|
)
|
||||||
|
row.operator("customshelf.refresh", text="", emboss=True, icon="FILE_REFRESH")
|
||||||
|
# row.separator()
|
||||||
|
|
||||||
row.prop(cat_props, "filter",text='',emboss=True,icon= "FILTER")
|
row.prop(cat_props, "filter", text="", emboss=True, icon="FILTER")
|
||||||
#row.separator()
|
# row.separator()
|
||||||
|
|
||||||
row.prop(cat_props,"search",icon = "VIEWZOOM",text='')
|
row.prop(cat_props, "search", icon="VIEWZOOM", text="")
|
||||||
#row.separator()
|
# 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",
|
"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",
|
"tracker_url": "https://gitlab.com/autour-de-minuit/blender/custom_shelf/-/issues",
|
||||||
"support": "COMMUNITY",
|
"support": "COMMUNITY",
|
||||||
"category": "User"}
|
"category": "User",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if "bpy" in locals():
|
if "bpy" in locals():
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
importlib.reload(operators)
|
importlib.reload(operators)
|
||||||
importlib.reload(panels)
|
importlib.reload(panels)
|
||||||
importlib.reload(functions)
|
importlib.reload(functions)
|
||||||
importlib.reload(properties)
|
importlib.reload(properties)
|
||||||
|
|
||||||
from . utils import report
|
from .utils import report
|
||||||
from . functions import read_shelves
|
from .functions import read_shelves
|
||||||
from . import operators
|
from . import operators
|
||||||
from . import properties
|
from . import properties
|
||||||
from . import ui
|
from . import ui
|
||||||
from .properties import CustomShelfSettings,CustomShelfProps
|
from .properties import CustomShelfSettings, CustomShelfProps
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import os
|
import os
|
||||||
@ -41,19 +42,22 @@ bl_classes = [
|
|||||||
operators.CSHELF_OT_open_shelf_folder,
|
operators.CSHELF_OT_open_shelf_folder,
|
||||||
operators.CSHELF_OT_add_script,
|
operators.CSHELF_OT_add_script,
|
||||||
operators.CSHELF_OT_set_tag_filter,
|
operators.CSHELF_OT_set_tag_filter,
|
||||||
ui.CSHELF_MT_text_editor
|
ui.CSHELF_MT_text_editor,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def draw_menu(self, context):
|
def draw_menu(self, context):
|
||||||
self.layout.menu('CSHELF_MT_text_editor')
|
self.layout.menu("CSHELF_MT_text_editor")
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
for bl_class in bl_classes :
|
for bl_class in bl_classes:
|
||||||
bpy.utils.register_class(bl_class)
|
bpy.utils.register_class(bl_class)
|
||||||
|
|
||||||
bpy.types.Scene.CustomShelf = bpy.props.PointerProperty(type=CustomShelfSettings)
|
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)
|
bpy.types.TEXT_MT_editor_menus.append(draw_menu)
|
||||||
|
|
||||||
@ -72,10 +76,11 @@ def register():
|
|||||||
|
|
||||||
read_shelves()
|
read_shelves()
|
||||||
|
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
# unregister panel :
|
# unregister panel :
|
||||||
for panel in CustomShelfSettings.panel_list :
|
for panel in CustomShelfSettings.panel_list:
|
||||||
try :
|
try:
|
||||||
bpy.utils.unregister_class(panel)
|
bpy.utils.unregister_class(panel)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@ -84,5 +89,5 @@ def unregister():
|
|||||||
del bpy.types.Scene.CustomShelf
|
del bpy.types.Scene.CustomShelf
|
||||||
del bpy.types.WindowManager.CustomShelf
|
del bpy.types.WindowManager.CustomShelf
|
||||||
|
|
||||||
for bl_class in bl_classes :
|
for bl_class in bl_classes:
|
||||||
bpy.utils.unregister_class(bl_class)
|
bpy.utils.unregister_class(bl_class)
|
||||||
|
|||||||
197
functions.py
197
functions.py
@ -1,197 +1,222 @@
|
|||||||
from .utils import *
|
from .utils import *
|
||||||
from bpy.props import *
|
from bpy.props import *
|
||||||
from bpy.types import Panel,Operator
|
from bpy.types import Panel, Operator
|
||||||
from .properties import CustomShelfSettings,CustomShelfPrefs
|
from .properties import CustomShelfSettings, CustomShelfPrefs
|
||||||
from .Types import *
|
from .Types import *
|
||||||
|
|
||||||
|
|
||||||
SHELF_DIR = join(dirname(__file__),'shelves')
|
SHELF_DIR = join(dirname(__file__), "shelves")
|
||||||
|
|
||||||
|
|
||||||
def operator(idname,args) :
|
def operator(idname, args):
|
||||||
op_execute = args['execute']
|
op_execute = args["execute"]
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
op_execute(context,self)
|
op_execute(context, self)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
package = __package__.replace('_','').replace('-','').lower()
|
package = __package__.replace("_", "").replace("-", "").lower()
|
||||||
|
|
||||||
args['bl_idname'] = "%s.%s"%(package,idname)
|
args["bl_idname"] = "%s.%s" % (package, idname)
|
||||||
args['bl_label'] = title(idname)
|
args["bl_label"] = title(idname)
|
||||||
args['execute'] = execute
|
args["execute"] = execute
|
||||||
|
|
||||||
op = type('operator',(Operator,),args)
|
op = type("operator", (Operator,), args)
|
||||||
|
|
||||||
bpy.utils.register_class(op)
|
bpy.utils.register_class(op)
|
||||||
|
|
||||||
return op
|
return op
|
||||||
|
|
||||||
def register_bl_class(bl_class,args) :
|
|
||||||
a = type('test',(bl_class,),{})
|
def register_bl_class(bl_class, args):
|
||||||
a.initialyse(a,*args)
|
a = type("test", (bl_class,), {})
|
||||||
|
a.initialyse(a, *args)
|
||||||
bpy.utils.register_class(a)
|
bpy.utils.register_class(a)
|
||||||
|
|
||||||
return 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():
|
def get_shelves_folder():
|
||||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
shelves_path = prefs.global_shelves
|
shelves_path = prefs.global_shelves
|
||||||
additionnal_shelves_path = [s.path for s in prefs.additionnal_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):
|
||||||
def get_dirs(paths) :
|
if isinstance(paths, (tuple, list)):
|
||||||
if isinstance(paths,(tuple,list)) :
|
|
||||||
dirs = []
|
dirs = []
|
||||||
for dir in paths:
|
for dir in paths:
|
||||||
if not isinstance(dir, str) :
|
if not isinstance(dir, str):
|
||||||
dir = dir.path
|
dir = dir.path
|
||||||
dirs += filter_dir(scandir(dir))
|
dirs += filter_dir(scandir(dir))
|
||||||
return dirs
|
return dirs
|
||||||
else :
|
else:
|
||||||
return filter_dir(scandir(paths))
|
return filter_dir(scandir(paths))
|
||||||
|
|
||||||
|
|
||||||
def get_categories():
|
def get_categories():
|
||||||
return [d.name for d in get_dirs(get_shelves_folder())]
|
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()))]
|
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)]]
|
def get_category_path(category):
|
||||||
if category_dir :
|
category_dir = [
|
||||||
return join(category_dir[0],category)
|
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):
|
def get_category_tabs(category):
|
||||||
return [d.name for d in get_dirs(get_category_path(category))]
|
return [d.name for d in get_dirs(get_category_path(category))]
|
||||||
|
|
||||||
|
|
||||||
def read_shelves() :
|
def read_shelves():
|
||||||
tag_filter_items = []
|
tag_filter_items = []
|
||||||
|
|
||||||
# unregister panel :
|
# unregister panel :
|
||||||
for panel in CustomShelfSettings.panel_list:
|
for panel in CustomShelfSettings.panel_list:
|
||||||
print(panel)
|
print(panel)
|
||||||
if panel.__name__ not in get_tabs():
|
if panel.__name__ not in get_tabs():
|
||||||
try :
|
try:
|
||||||
bpy.utils.unregister_class(panel)
|
bpy.utils.unregister_class(panel)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
CustomShelfSettings.panel_list.remove(panel)
|
CustomShelfSettings.panel_list.remove(panel)
|
||||||
|
|
||||||
|
for cat in get_dirs(get_shelves_folder()):
|
||||||
for cat in get_dirs(get_shelves_folder()) :
|
cat_name = cat.name.replace("_", " ").title()
|
||||||
cat_name = cat.name.replace('_',' ').title()
|
|
||||||
|
|
||||||
header_info = {
|
header_info = {
|
||||||
"bl_region_type" : "UI",#petit ajout pour voir si foncitonne...
|
"bl_region_type": "UI", # petit ajout pour voir si foncitonne...
|
||||||
"bl_category" : cat_name,
|
"bl_category": cat_name,
|
||||||
"bl_idname" : "%s_PT_%s_header"%(__package__.upper(),cat.name),# -> "%s.%s_header" makes _PT_ warning
|
"bl_idname": "%s_PT_%s_header"
|
||||||
"cat" : cat.name,
|
% (__package__.upper(), cat.name), # -> "%s.%s_header" makes _PT_ warning
|
||||||
"path" : cat.path
|
"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)
|
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
|
# 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
|
## 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)}}
|
panel_props = {
|
||||||
PanelProps = type("CustomShelfPrefs",(PropertyGroup,),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)
|
bpy.utils.register_class(PanelProps)
|
||||||
|
|
||||||
setattr(CustomShelfPrefs, cat.name, PointerProperty(type=PanelProps))
|
setattr(CustomShelfPrefs, cat.name, PointerProperty(type=PanelProps))
|
||||||
|
|
||||||
#search and filter
|
# search and filter
|
||||||
props = {
|
props = {
|
||||||
"search" : StringProperty(options = {"TEXTEDIT_UPDATE"}),
|
"search": StringProperty(options={"TEXTEDIT_UPDATE"}),
|
||||||
"filter" : BoolProperty(default = True)
|
"filter": BoolProperty(default=True),
|
||||||
}
|
}
|
||||||
# Props = type("props",(PropertyGroup,), props)# annotation error
|
# Props = type("props",(PropertyGroup,), props)# annotation error
|
||||||
Props = type("props",(PropertyGroup,),{'__annotations__': props})
|
Props = type("props", (PropertyGroup,), {"__annotations__": props})
|
||||||
bpy.utils.register_class(Props)
|
bpy.utils.register_class(Props)
|
||||||
|
|
||||||
setattr(CustomShelfSettings,cat.name,PointerProperty(type = Props))
|
setattr(CustomShelfSettings, cat.name, PointerProperty(type=Props))
|
||||||
|
|
||||||
#enable bool prefs
|
# enable bool prefs
|
||||||
#Prefs = type("CustomShelfPrefs",(PropertyGroup,),{})
|
# Prefs = type("CustomShelfPrefs",(PropertyGroup,),{})
|
||||||
#bpy.utils.register_class(Prefs)
|
# 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) :
|
for tab in get_dirs(cat.path):
|
||||||
#get_settings
|
# get_settings
|
||||||
settings_json = join(tab.path,'settings.json')
|
settings_json = join(tab.path, "settings.json")
|
||||||
|
|
||||||
tab_settings = {}
|
tab_settings = {}
|
||||||
if exists(settings_json) :
|
if exists(settings_json):
|
||||||
tab_settings = read_json(settings_json)
|
tab_settings = read_json(settings_json)
|
||||||
if not tab_settings or not tab_settings.get('tags') : continue
|
if not tab_settings or not tab_settings.get("tags"):
|
||||||
for tag in tab_settings['tags'] :
|
continue
|
||||||
if tag not in tag_filter_items :
|
for tag in tab_settings["tags"]:
|
||||||
|
if tag not in tag_filter_items:
|
||||||
tag_filter_items.append(tag)
|
tag_filter_items.append(tag)
|
||||||
|
|
||||||
panel_info = {
|
panel_info = {
|
||||||
"bl_region_type" : "UI",#Added, maybe need it in 2.8+...
|
"bl_region_type": "UI", # Added, maybe need it in 2.8+...
|
||||||
"bl_category" : cat_name,
|
"bl_category": cat_name,
|
||||||
"bl_idname" : "%s_PT_%s_%s"%(__package__.upper(),cat.name,tab.name),#"%s.%s_%s" -> makes _PT_ warning
|
"bl_idname": "%s_PT_%s_%s"
|
||||||
"bl_label" : tab.name.replace('_',' ').title(),
|
% (
|
||||||
"cat" : cat.name,
|
__package__.upper(),
|
||||||
"settings" :tab_settings
|
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_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)
|
bpy.utils.register_class(panel)
|
||||||
|
|
||||||
CustomShelfSettings.panel_list.append(panel)
|
CustomShelfSettings.panel_list.append(panel)
|
||||||
|
|
||||||
scripts = []
|
scripts = []
|
||||||
for script in scandir(tab.path) :
|
for script in scandir(tab.path):
|
||||||
if not script.name.endswith('.py'):
|
if not script.name.endswith(".py"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(script.path)
|
print(script.path)
|
||||||
|
|
||||||
script_name = splitext(script.name)[0]
|
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,),
|
popup = type(
|
||||||
{"script": script.path,
|
script_name,
|
||||||
'bl_description': info["description"]
|
(CSHELF_OT_shelf_popup,),
|
||||||
})
|
{"script": script.path, "bl_description": info["description"]},
|
||||||
|
)
|
||||||
popup.initialyse(popup, script_name, info)
|
popup.initialyse(popup, script_name, info)
|
||||||
bpy.utils.register_class(popup)
|
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
|
# Register tag filter enum
|
||||||
#setattr(Pre, v)
|
# setattr(Pre, v)
|
||||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
tag_filter_items.sort()
|
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.unregister_class(CustomShelfPrefs)
|
||||||
#bpy.utils.register_class(CustomShelfPrefs)
|
# bpy.utils.register_class(CustomShelfPrefs)
|
||||||
#CustomShelfSettings.folders = list(get_shelves_folder().keys())
|
# CustomShelfSettings.folders = list(get_shelves_folder().keys())
|
||||||
|
|
||||||
#folder_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in CustomShelfSettings.folders])
|
# folder_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in CustomShelfSettings.folders])
|
||||||
#setattr(CustomShelfSettings,'folders_enum',folder_enum)
|
# 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):
|
class CSHELF_OT_refresh(Operator):
|
||||||
bl_idname = "customshelf.refresh"
|
bl_idname = "customshelf.refresh"
|
||||||
bl_label = 'Refresh Shelves'
|
bl_label = "Refresh Shelves"
|
||||||
|
|
||||||
def execute(self,context) :
|
def execute(self, context):
|
||||||
read_shelves()
|
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
|
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):
|
class CSHELF_OT_set_tag_filter(Operator):
|
||||||
bl_idname = "customshelf.set_tag_filter"
|
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):
|
def execute(self, context):
|
||||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
|
|
||||||
tag_filter = self.tag_filter
|
tag_filter = self.tag_filter
|
||||||
if tag_filter == '__clear__' :
|
if tag_filter == "__clear__":
|
||||||
tag_filter = ""
|
tag_filter = ""
|
||||||
|
|
||||||
prefs.tag_filter = tag_filter
|
prefs.tag_filter = tag_filter
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class CSHELF_OT_add_shelf_folder(Operator):
|
class CSHELF_OT_add_shelf_folder(Operator):
|
||||||
bl_idname = "customshelf.add_shelves_folder"
|
bl_idname = "customshelf.add_shelves_folder"
|
||||||
bl_label = 'Refresh Shelves'
|
bl_label = "Refresh Shelves"
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
path = prefs.additionnal_shelves.add()
|
path = prefs.additionnal_shelves.add()
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class CSHELF_OT_remove_shelf_folder(Operator):
|
class CSHELF_OT_remove_shelf_folder(Operator):
|
||||||
bl_idname = "customshelf.remove_shelves_folder"
|
bl_idname = "customshelf.remove_shelves_folder"
|
||||||
bl_label = 'Refresh Shelves'
|
bl_label = "Refresh Shelves"
|
||||||
|
|
||||||
index : IntProperty()
|
index: IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
prefs.additionnal_shelves.remove(self.index)
|
prefs.additionnal_shelves.remove(self.index)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CSHELF_OT_open_shelf_folder(Operator):
|
class CSHELF_OT_open_shelf_folder(Operator):
|
||||||
bl_idname = "customshelf.open_shelf_folder"
|
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)
|
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_idname = "customshelf.add_script"
|
||||||
bl_label = 'Add script to a shelf'
|
bl_label = "Add script to a shelf"
|
||||||
|
|
||||||
add_category : BoolProperty()
|
add_category: BoolProperty()
|
||||||
add_tab : BoolProperty()
|
add_tab: BoolProperty()
|
||||||
new_category : StringProperty()
|
new_category: StringProperty()
|
||||||
new_tab : StringProperty()
|
new_tab: StringProperty()
|
||||||
|
|
||||||
name : StringProperty()
|
name: StringProperty()
|
||||||
description : StringProperty()
|
description: StringProperty()
|
||||||
icon : StringProperty()
|
icon: StringProperty()
|
||||||
show_icons : BoolProperty()
|
show_icons: BoolProperty()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
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 = self.folder.add()
|
||||||
folder.name = self.name
|
folder.name = self.name
|
||||||
#CustomShelfSettings
|
# CustomShelfSettings
|
||||||
|
|
||||||
def remove_folder(self,context,op) :
|
def remove_folder(self, context, op):
|
||||||
bl_props = context.scene.CustomShelf
|
bl_props = context.scene.CustomShelf
|
||||||
index = self.folders.find(self.folders_enum)
|
index = self.folders.find(self.folders_enum)
|
||||||
self.folders.remove(index)
|
self.folders.remove(index)
|
||||||
|
|
||||||
def get_all_icons (self) :
|
def get_all_icons(self):
|
||||||
ui_layout = bpy.types.UILayout
|
ui_layout = bpy.types.UILayout
|
||||||
icons = ui_layout.bl_rna.functions["prop"].parameters["icon"].enum_items.keys()
|
icons = ui_layout.bl_rna.functions["prop"].parameters["icon"].enum_items.keys()
|
||||||
|
|
||||||
prefixes = ('BRUSH_','MATCAP_','COLORSET_')
|
prefixes = ("BRUSH_", "MATCAP_", "COLORSET_")
|
||||||
exception = ('BRUSH_DATA')
|
exception = "BRUSH_DATA"
|
||||||
|
|
||||||
return [i for i in icons if not i.startswith(prefixes) or i in exception]
|
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 = [
|
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",
|
"SCENE_DATA",
|
||||||
"ARMATURE_DATA","BONE_DATA","GROUP_BONE"],
|
"RENDERLAYERS",
|
||||||
["SEQUENCE","CAMERA_DATA","SCENE","BLANK1",
|
"MATERIAL_DATA",
|
||||||
"FILE_NEW","CONSOLE","BLENDER","APPEND_BLEND"],
|
"GROUP_UVS",
|
||||||
["GROUP","MESH_CUBE","MESH_PLANE","MESH_CIRCLE","MESH_UVSPHERE","MESH_GRID","EMPTY_DATA","OUTLINER_DATA_MESH",
|
"TEXTURE",
|
||||||
"LIGHT_SUN","LIGHT_SPOT","LIGHT"],
|
"WORLD",
|
||||||
["TRIA_RIGHT_BAR","REC","PLAY","PREV_KEYFRAME","NEXT_KEYFRAME","PAUSE","X","ADD","REMOVE","RESTRICT_VIEW_OFF","RESTRICT_VIEW_ON","RESTRICT_SELECT_OFF",],
|
"SPEAKER",
|
||||||
["BRUSH_DATA","GREASEPENCIL","LINE_DATA","PARTICLEMODE","SCULPTMODE_HLT","WPAINT_HLT","TPAINT_HLT","VIEWZOOM","HAND","KEY_HLT","KEY_DEHLT",],
|
"TEXT",
|
||||||
["PLUGIN","SCRIPT","PREFERENCES",
|
"NODETREE",
|
||||||
"ACTION","SOLO_OFF",
|
"NODE_INSERT_OFF",
|
||||||
"RNDCURVE","SNAP_ON",
|
"PARTICLES",
|
||||||
"FORCE_WIND","COPY_ID","EYEDROPPER","AUTO","UNLOCKED","LOCKED",
|
"SORTALPHA",
|
||||||
"UNPINNED","PINNED","PLUGIN","HELP","GHOST_ENABLED","GHOST_DISABLED","COLOR",
|
],
|
||||||
"LINKED","UNLINKED","LINKED","ZOOM_ALL",
|
[
|
||||||
"FREEZE","STYLUS_PRESSURE","FILE_TICK",
|
"MODIFIER",
|
||||||
"QUIT","RECOVER_LAST","TIME","PREVIEW_RANGE",
|
"MOD_WAVE",
|
||||||
"OUTLINER","NLA","EDITMODE_HLT",
|
"MOD_SUBSURF",
|
||||||
"BOIDS","RNA","CAMERA_STEREO"],
|
"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
|
self.icons = icons
|
||||||
|
|
||||||
|
def set_icon(self, context, op):
|
||||||
def set_icon(self,context,op) :
|
# bl_props = context.scene.CustomShelf
|
||||||
#bl_props = context.scene.CustomShelf
|
|
||||||
self.icon = op.icon
|
self.icon = op.icon
|
||||||
self.icons = []
|
self.icons = []
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
def draw(self,context) :
|
|
||||||
bl_props = context.scene.CustomShelf
|
bl_props = context.scene.CustomShelf
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator("customshelf.get_icons",text= '',icon = self.icon)
|
row.operator("customshelf.get_icons", text="", icon=self.icon)
|
||||||
row.prop(self,"name",text ="")
|
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 :
|
row.operator(
|
||||||
i=0
|
"customshelf.set_icon", icon=icon, emboss=False, text=""
|
||||||
for icon in icon_list :
|
).icon = icon
|
||||||
if not i%12 :
|
|
||||||
row = col.row(align= True)
|
|
||||||
|
|
||||||
row.operator("customshelf.set_icon", icon=icon, emboss=False, text="").icon=icon
|
|
||||||
i += 1
|
i += 1
|
||||||
row = col.row(align= True)
|
row = col.row(align=True)
|
||||||
|
|
||||||
layout.prop(self, "description", text="")
|
layout.prop(self, "description", text="")
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
#Category Row
|
# Category Row
|
||||||
folder_row = layout.row(align = True)
|
folder_row = layout.row(align=True)
|
||||||
folder_row.label(text="", icon='FILE_FOLDER')
|
folder_row.label(text="", icon="FILE_FOLDER")
|
||||||
folder_row.separator()
|
folder_row.separator()
|
||||||
if not self.add_category :
|
if not self.add_category:
|
||||||
folder_row.prop(bl_props,"category_enum",expand = True)
|
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
|
# Tabs row
|
||||||
tab_row = layout.row(align = True)
|
tab_row = layout.row(align=True)
|
||||||
tab_row.label(text='', icon='MENU_PANEL')
|
tab_row.label(text="", icon="MENU_PANEL")
|
||||||
tab_row.separator()
|
tab_row.separator()
|
||||||
if not self.add_tab :
|
if not self.add_tab:
|
||||||
category_tabs = get_category_tabs(bl_props.category_enum)
|
category_tabs = get_category_tabs(bl_props.category_enum)
|
||||||
for t in [t for t in category_tabs if t in self.tabs] :
|
for t in [t for t in category_tabs if t in self.tabs]:
|
||||||
tab_row.prop_enum(bl_props,"tab_enum",t)
|
tab_row.prop_enum(bl_props, "tab_enum", t)
|
||||||
|
|
||||||
else :
|
else:
|
||||||
tab_row.prop(self,"new_tab",text='')
|
tab_row.prop(self, "new_tab", text="")
|
||||||
|
|
||||||
tab_row.prop(self,"add_tab",icon = 'ADD',text='')
|
tab_row.prop(self, "add_tab", icon="ADD", text="")
|
||||||
#folder_row.operator("customshelf.remove_folder",icon = 'REMOVE',text='')
|
# folder_row.operator("customshelf.remove_folder",icon = 'REMOVE',text='')
|
||||||
|
|
||||||
def write_script(self,f) :
|
def write_script(self, f):
|
||||||
keys = ['icon','description']
|
keys = ["icon", "description"]
|
||||||
keys += [k for k in self.info if k not in keys]
|
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)
|
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
|
preferences = context.preferences
|
||||||
bl_props = context.scene.CustomShelf
|
bl_props = context.scene.CustomShelf
|
||||||
addon_prefs = preferences.addons[__package__].preferences
|
addon_prefs = preferences.addons[__package__].preferences
|
||||||
|
|
||||||
if self.new_category :
|
if self.new_category:
|
||||||
category_path = get_category_path(self.new_category)
|
category_path = get_category_path(self.new_category)
|
||||||
if not exists(category_path):
|
if not exists(category_path):
|
||||||
mkdir(new_category)
|
mkdir(new_category)
|
||||||
else :
|
else:
|
||||||
category_path = get_category_path(bl_props.category_enum)
|
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)
|
tab_path = join(category_path, self.new_tab)
|
||||||
if not exists(tab_path):
|
if not exists(tab_path):
|
||||||
mkdir(tab_path)
|
mkdir(tab_path)
|
||||||
else :
|
else:
|
||||||
tab_path = join(category_path,bl_props.tab_enum)
|
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):
|
if os.path.exists(script_path):
|
||||||
os.remove(script_path)
|
os.remove(script_path)
|
||||||
|
|
||||||
|
self.info["icon"] = self.icon
|
||||||
|
self.info["description"] = self.description
|
||||||
|
|
||||||
self.info['icon'] = self.icon
|
with open(script_path, "w") as f:
|
||||||
self.info['description'] = self.description
|
|
||||||
|
|
||||||
with open(script_path,"w") as f :
|
|
||||||
self.write_script(f)
|
self.write_script(f)
|
||||||
|
|
||||||
line_index = self.active_text.current_line_index
|
line_index = self.active_text.current_line_index
|
||||||
@ -246,21 +337,21 @@ class CSHELF_OT_add_script(Operator) :
|
|||||||
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def check(self,context) :
|
def check(self, context):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def invoke(self,context,event) :
|
def invoke(self, context, event):
|
||||||
bl_props = context.scene.CustomShelf
|
bl_props = context.scene.CustomShelf
|
||||||
self.active_text = context.space_data.text
|
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"
|
icon = "LONGDISPLAY"
|
||||||
if self.info.get('icon') :
|
if self.info.get("icon"):
|
||||||
icon = self.info["icon"]
|
icon = self.info["icon"]
|
||||||
|
|
||||||
description = "Some description"
|
description = "Some description"
|
||||||
if self.info.get('description') :
|
if self.info.get("description"):
|
||||||
description = self.info["description"]
|
description = self.info["description"]
|
||||||
|
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
@ -272,25 +363,32 @@ class CSHELF_OT_add_script(Operator) :
|
|||||||
self.new_shelf = ""
|
self.new_shelf = ""
|
||||||
self.icons = []
|
self.icons = []
|
||||||
|
|
||||||
operator("get_icons", {'execute': self.get_icons})
|
operator("get_icons", {"execute": self.get_icons})
|
||||||
operator("set_icon", {'execute': self.set_icon, '__annotations__': {'icon' : StringProperty()}})
|
operator(
|
||||||
operator("add_folder", {'execute': self.add_folder})
|
"set_icon",
|
||||||
#operator("remove_folder",{'execute':self.remove_folder})
|
{"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.tabs = get_tabs()
|
||||||
self.categories = get_categories()
|
self.categories = get_categories()
|
||||||
|
|
||||||
CustomShelfSettings.category_enum = EnumProperty(items=[(i,i,"") for i in self.categories])
|
CustomShelfSettings.category_enum = EnumProperty(
|
||||||
CustomShelfSettings.tab_enum = EnumProperty(items=[(i,i,"") for i in self.tabs])
|
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)
|
tab_path = dirname(self.active_text.filepath)
|
||||||
category = basename(dirname(tab_path))
|
category = basename(dirname(tab_path))
|
||||||
tab = basename(tab_path)
|
tab = basename(tab_path)
|
||||||
|
|
||||||
if category in self.categories :
|
if category in self.categories:
|
||||||
bl_props.category_enum = category
|
bl_props.category_enum = category
|
||||||
if tab in self.tabs :
|
if tab in self.tabs:
|
||||||
bl_props.tab_enum = tab
|
bl_props.tab_enum = tab
|
||||||
|
|
||||||
return context.window_manager.invoke_props_dialog(self, width=500)
|
return context.window_manager.invoke_props_dialog(self, width=500)
|
||||||
|
|||||||
@ -2,47 +2,53 @@ from .utils import *
|
|||||||
from bpy.props import *
|
from bpy.props import *
|
||||||
|
|
||||||
|
|
||||||
|
class CustomShelfSettings(bpy.types.PropertyGroup):
|
||||||
class CustomShelfSettings(bpy.types.PropertyGroup) :
|
|
||||||
panel_list = []
|
panel_list = []
|
||||||
#category_enum = EnumProperty(items = )
|
# category_enum = EnumProperty(items = )
|
||||||
#tab_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in s.tabs])
|
# tab_enum = EnumProperty(items = lambda s,c : [(f,f,"") for f in s.tabs])
|
||||||
|
|
||||||
#search = StringProperty(options = {"TEXTEDIT_UPDATE"})
|
# search = StringProperty(options = {"TEXTEDIT_UPDATE"})
|
||||||
#filter = BoolProperty(default = True)
|
# filter = BoolProperty(default = True)
|
||||||
#folders = PointerProperty(type= CustomShelfFolders)
|
# folders = PointerProperty(type= CustomShelfFolders)
|
||||||
#variables = bpy.props.PointerProperty(type= CustomShelfVariables)
|
# variables = bpy.props.PointerProperty(type= CustomShelfVariables)
|
||||||
|
|
||||||
class CustomShelfProps(bpy.types.PropertyGroup) :
|
|
||||||
|
class CustomShelfProps(bpy.types.PropertyGroup):
|
||||||
pass
|
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):
|
class CustomShelfPrefs(bpy.types.AddonPreferences):
|
||||||
bl_idname = __package__
|
bl_idname = __package__
|
||||||
|
|
||||||
global_path = join(dirname(__file__),'shelves')
|
global_path = join(dirname(__file__), "shelves")
|
||||||
global_shelves : StringProperty(name="Shelves Path",subtype = 'DIR_PATH',default =global_path)
|
global_shelves: StringProperty(
|
||||||
additionnal_shelves : CollectionProperty(type = AdditionnalShelves)
|
name="Shelves Path", subtype="DIR_PATH", default=global_path
|
||||||
tag_filter : StringProperty()
|
)
|
||||||
|
additionnal_shelves: CollectionProperty(type=AdditionnalShelves)
|
||||||
|
tag_filter: StringProperty()
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.prop(self, "global_shelves")
|
layout.prop(self, "global_shelves")
|
||||||
|
|
||||||
row = layout.row(align = True)
|
row = layout.row(align=True)
|
||||||
row.operator("customshelf.add_shelves_folder",icon="ADD",text="")
|
row.operator("customshelf.add_shelves_folder", icon="ADD", text="")
|
||||||
row.label(text='Additionnal Shelves folder')
|
row.label(text="Additionnal Shelves folder")
|
||||||
|
|
||||||
for i,shelf in enumerate(prefs.additionnal_shelves) :
|
for i, shelf in enumerate(prefs.additionnal_shelves):
|
||||||
row = layout.row(align = True)
|
row = layout.row(align=True)
|
||||||
row.prop(shelf, "path")
|
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.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
|
import bpy
|
||||||
|
|
||||||
|
|
||||||
@ -7,9 +6,7 @@ class CSHELF_MT_text_editor(bpy.types.Menu):
|
|||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
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 bpy
|
||||||
import os
|
import os
|
||||||
from os import listdir,mkdir,scandir
|
from os import listdir, mkdir, scandir
|
||||||
from os.path import join,dirname,splitext,isdir,exists,basename
|
from os.path import join, dirname, splitext, isdir, exists, basename
|
||||||
from bpy.types import Operator, Panel, PropertyGroup
|
from bpy.types import Operator, Panel, PropertyGroup
|
||||||
from bpy.props import *
|
from bpy.props import *
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
id_type = {"Action" : "actions", "Armature":"armatures", "Brush":"brushes", "CacheFile":"cache_files", "Camera":"cameras",
|
id_type = {
|
||||||
"Curve":"curves", "FreestyleLineStyle":"linestyles", "GreasePencil":"grease_pencil", "Group":"groups",
|
"Action": "actions",
|
||||||
"Image":"images", "Key":"shape_keys", "Light":"lights", "Lattice":"lattices", "Library":"librairies", "Mask":"masks",
|
"Armature": "armatures",
|
||||||
"Material":"materials", "Mesh":"meshes", "MetaBall":"metaballs", "MovieClip":"movieclips", "NodeTree":"node_groups",
|
"Brush": "brushes",
|
||||||
"Object":"objects", "PaintCurve":"paint_curves", "Palette":"palettes", "ParticleSettings":"particles",
|
"CacheFile": "cache_files",
|
||||||
"Scene":"scenes", "Screen":"screens", "Sound":"sounds", "Speaker":"speakers", "Text":"texts", "Texture":"textures",
|
"Camera": "cameras",
|
||||||
"Collection":"collections", "VectorFont":"fonts", "WindowManager":"window_managers", "World":"worlds"}
|
"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 locals()])
|
||||||
print([a for a in globals()])
|
print([a for a in globals()])
|
||||||
|
|
||||||
|
if "self" in var:
|
||||||
|
var["self"].report({type}, message)
|
||||||
|
|
||||||
if 'self' in var :
|
else:
|
||||||
var['self'].report({type}, message)
|
print("")
|
||||||
|
|
||||||
else :
|
|
||||||
print('')
|
|
||||||
print(type)
|
print(type)
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
|
|
||||||
def read_json(path):
|
def read_json(path):
|
||||||
jsonFile = path
|
jsonFile = path
|
||||||
if os.path.exists(jsonFile):
|
if os.path.exists(jsonFile):
|
||||||
try :
|
try:
|
||||||
with open(jsonFile) as data_file:
|
with open(jsonFile) as data_file:
|
||||||
return (json.load(data_file))
|
return json.load(data_file)
|
||||||
except :
|
except:
|
||||||
print("the file %s not json readable"%jsonFile)
|
print("the file %s not json readable" % jsonFile)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def search_filter(search, str):
|
||||||
def search_filter(search,str) :
|
|
||||||
return search.lower() in str.lower()
|
return search.lower() in str.lower()
|
||||||
|
|
||||||
def title(string) :
|
|
||||||
return string.replace('_',' ').replace('-',' ').title()
|
|
||||||
|
|
||||||
def arg_name(string) :
|
def title(string):
|
||||||
return string.replace(' ','_').replace('-','_').lower().strip('_')
|
return string.replace("_", " ").replace("-", " ").title()
|
||||||
|
|
||||||
def open_folder(path) :
|
|
||||||
|
def arg_name(string):
|
||||||
|
return string.replace(" ", "_").replace("-", "_").lower().strip("_")
|
||||||
|
|
||||||
|
|
||||||
|
def open_folder(path):
|
||||||
try:
|
try:
|
||||||
os.startfile(path)
|
os.startfile(path)
|
||||||
except:
|
except:
|
||||||
subprocess.Popen(['xdg-open', path])
|
subprocess.Popen(["xdg-open", path])
|
||||||
|
|
||||||
|
|
||||||
def dic_to_args(dic):
|
def dic_to_args(dic):
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
args = collections.OrderedDict()
|
args = collections.OrderedDict()
|
||||||
|
|
||||||
prop_type = {
|
prop_type = {
|
||||||
str: StringProperty,
|
str: StringProperty,
|
||||||
bool: BoolProperty,
|
bool: BoolProperty,
|
||||||
float: FloatProperty,
|
float: FloatProperty,
|
||||||
int : IntProperty
|
int: IntProperty,
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v in dic.items() :
|
for k, v in dic.items():
|
||||||
if k in ('icon','description') or not isinstance(k,str):
|
if k in ("icon", "description") or not isinstance(k, str):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(v,str) :
|
if isinstance(v, str):
|
||||||
if '/' in v or '\\' in v :
|
if "/" in v or "\\" in v:
|
||||||
args[k] = StringProperty(default=v,subtype = "FILE_PATH")
|
args[k] = StringProperty(default=v, subtype="FILE_PATH")
|
||||||
else :
|
else:
|
||||||
args[k] = StringProperty(default=v)
|
args[k] = StringProperty(default=v)
|
||||||
|
|
||||||
elif isinstance(v,bool) :
|
elif isinstance(v, bool):
|
||||||
args[k] = BoolProperty(default=v)
|
args[k] = BoolProperty(default=v)
|
||||||
|
|
||||||
elif isinstance(v, float) :
|
elif isinstance(v, float):
|
||||||
args[k] = FloatProperty(default=v,precision=3)
|
args[k] = FloatProperty(default=v, precision=3)
|
||||||
|
|
||||||
elif isinstance(v,int) :
|
elif isinstance(v, int):
|
||||||
args[k] = IntProperty(default=v)
|
args[k] = IntProperty(default=v)
|
||||||
|
|
||||||
elif isinstance(v, dict) :
|
elif isinstance(v, dict):
|
||||||
if v.get("items") and isinstance(v["items"],(tuple,list)) :
|
if v.get("items") and isinstance(v["items"], (tuple, list)):
|
||||||
args[k] = EnumProperty(items = [(i,i,"") for i in v["items"]])
|
args[k] = EnumProperty(items=[(i, i, "") for i in v["items"]])
|
||||||
|
|
||||||
elif v.get("collection") and isinstance(v["collection"],str) :
|
elif v.get("collection") and isinstance(v["collection"], str):
|
||||||
if v["collection"] not in id_type :
|
if v["collection"] not in id_type:
|
||||||
print("Collection %s not supported must be in %s"%(v["collection"],id_type))
|
print(
|
||||||
#args[k] = PointerProperty(type = getattr(bpy.types,v["collection"]))
|
"Collection %s not supported must be in %s"
|
||||||
else :
|
% (v["collection"], id_type)
|
||||||
args[k] = PointerProperty(type = getattr(bpy.types,v["collection"]),poll = v.get('poll'))
|
)
|
||||||
|
# args[k] = PointerProperty(type = getattr(bpy.types,v["collection"]))
|
||||||
|
else:
|
||||||
|
args[k] = PointerProperty(
|
||||||
|
type=getattr(bpy.types, v["collection"]), poll=v.get("poll")
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
args[k] = prop_type[type(v['default'])](**v)
|
args[k] = prop_type[type(v["default"])](**v)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
def read_info(script_path) :
|
def read_info(script_path):
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
if isinstance(script_path,list) :
|
if isinstance(script_path, list):
|
||||||
lines =script_path
|
lines = script_path
|
||||||
else :
|
else:
|
||||||
with open(script_path,encoding="utf-8") as f:
|
with open(script_path, encoding="utf-8") as f:
|
||||||
lines = f.read().splitlines()
|
lines = f.read().splitlines()
|
||||||
|
|
||||||
info = {}
|
info = {}
|
||||||
for i,l in enumerate(lines) :
|
for i, l in enumerate(lines):
|
||||||
if i >= 10 :
|
if i >= 10:
|
||||||
return info,lines
|
return info, lines
|
||||||
|
|
||||||
if l.startswith("info") :
|
if l.startswith("info"):
|
||||||
info_start = i
|
info_start = i
|
||||||
info_str = l
|
info_str = l
|
||||||
|
|
||||||
while info_str.endswith(',') or not info_str.endswith('}') or i == len(lines)-1:
|
while (
|
||||||
i+=1
|
info_str.endswith(",")
|
||||||
info_str+= lines[i]
|
or not info_str.endswith("}")
|
||||||
|
or i == len(lines) - 1
|
||||||
|
):
|
||||||
|
i += 1
|
||||||
|
info_str += lines[i]
|
||||||
|
|
||||||
info_end = 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:])
|
info = eval(info_str[opening_brace_index:])
|
||||||
except :
|
except:
|
||||||
print('The info header in the file %s cannot be read'%script_path)
|
print("The info header in the file %s cannot be read" % script_path)
|
||||||
break
|
break
|
||||||
|
|
||||||
info = [(k,v) for k,v in info.items()]
|
info = [(k, v) for k, v in info.items()]
|
||||||
info.sort(key = lambda x : info_str.find(x[0]))
|
info.sort(key=lambda x: info_str.find(x[0]))
|
||||||
|
|
||||||
info = collections.OrderedDict(info)
|
info = collections.OrderedDict(info)
|
||||||
|
|
||||||
del lines[info_start:info_end+1]
|
del lines[info_start : info_end + 1]
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# remove backspace
|
# remove backspace
|
||||||
for i in range(len(lines)) :
|
for i in range(len(lines)):
|
||||||
if lines[0] :
|
if lines[0]:
|
||||||
break
|
break
|
||||||
else :
|
else:
|
||||||
lines.pop(0)
|
lines.pop(0)
|
||||||
|
|
||||||
for i in range(len(lines)) :
|
for i in range(len(lines)):
|
||||||
if lines[-1] :
|
if lines[-1]:
|
||||||
break
|
break
|
||||||
else :
|
else:
|
||||||
lines.pop(-1)
|
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)
|
keys = sorted(dic)
|
||||||
|
|
||||||
line = '{\n'
|
line = "{\n"
|
||||||
for k in keys :
|
for k in keys:
|
||||||
v = dic[k]
|
v = dic[k]
|
||||||
|
|
||||||
line += ' '*spaces
|
line += " " * spaces
|
||||||
|
|
||||||
if isinstance(k,str) :
|
if isinstance(k, str):
|
||||||
line +="'%s'"%k
|
line += "'%s'" % k
|
||||||
else :
|
else:
|
||||||
line += "%s"%k
|
line += "%s" % k
|
||||||
|
|
||||||
line += ' : '
|
line += " : "
|
||||||
|
|
||||||
if isinstance(v,str) :
|
if isinstance(v, str):
|
||||||
line +="'%s'"%v
|
line += "'%s'" % v
|
||||||
else :
|
else:
|
||||||
line += "%s"%v
|
line += "%s" % v
|
||||||
|
|
||||||
line += ',\n'
|
line += ",\n"
|
||||||
|
|
||||||
line += '}\n\n'
|
line += "}\n\n"
|
||||||
|
|
||||||
return line
|
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