replace dynamic_menu.py with Menu classmethods much less complicated.

access append/prepend eg.

bpy.types.INFO_MT_file_import.append(lambda self, context: self.layout.operator("import_some.format"))
This commit is contained in:
Campbell Barton 2009-12-25 22:16:19 +00:00
parent 695677914a
commit 5afd084513
21 changed files with 54 additions and 203 deletions

@ -1139,10 +1139,8 @@ class Export3DS(bpy.types.Operator):
bpy.types.register(Export3DS)
# Add to a menu
import dynamic_menu
def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".3ds")
self.layout.operator(Export3DS.bl_idname, text="Autodesk 3DS...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
bpy.types.INFO_MT_file_export.append(menu_func)

@ -3462,13 +3462,9 @@ bpy.types.register(ExportFBX)
# SMALL or COSMETICAL
# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
# Add to a menu
import dynamic_menu
def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".fbx")
self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
menu_item = bpy.types.INFO_MT_file_export.append(menu_func)

@ -183,14 +183,11 @@ class ExportMDD(bpy.types.Operator):
bpy.types.register(ExportMDD)
# Add to a menu
import dynamic_menu
def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".mdd")
self.layout.operator(ExportMDD.bl_idname, text="Vertex Keyframe Animation (.mdd)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
bpy.types.INFO_MT_file_export.append(menu_func)
if __name__ == '__main__':
bpy.ops.export.mdd(path="/tmp/test.mdd")

@ -987,19 +987,13 @@ class ExportOBJ(bpy.types.Operator):
wm.add_fileselect(self)
return {'RUNNING_MODAL'}
bpy.types.register(ExportOBJ)
import dynamic_menu
def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".obj")
self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
menu_item = bpy.types.INFO_MT_file_export.append(menu_func)
if __name__ == "__main__":
bpy.ops.EXPORT_OT_obj(filename="/tmp/test.obj")

@ -318,14 +318,11 @@ class ExportPLY(bpy.types.Operator):
bpy.types.register(ExportPLY)
import dynamic_menu
def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".ply")
self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
bpy.types.INFO_MT_file_export.append(menu_func)
if __name__ == "__main__":
bpy.ops.export.ply(path="/tmp/test.ply")

@ -1242,13 +1242,12 @@ class ExportX3D(bpy.types.Operator):
bpy.types.register(ExportX3D)
import dynamic_menu
def menu_func(self, context):
default_path = bpy.data.filename.replace(".blend", ".x3d")
self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)...").path = default_path
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
bpy.types.INFO_MT_file_export.append(menu_func)
# NOTES
# - blender version is hardcoded

@ -897,7 +897,5 @@ class BvhImporter(bpy.types.Operator):
bpy.types.register(BvhImporter)
import dynamic_menu
menu_func = lambda self, context: self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func)
bpy.types.INFO_MT_file_import.append(menu_func)

@ -1168,10 +1168,9 @@ class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
bpy.types.register(IMPORT_OT_autodesk_3ds)
import dynamic_menu
menu_func = lambda self, context: self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func)
bpy.types.INFO_MT_file_import.append(menu_func)
# NOTES:
# why add 1 extra vertex? and remove it when done?
# why add 1 extra vertex? and remove it when done? - "Answer - eekadoodle - would need to re-order UV's without this since face order isnt always what we give blender, BMesh will solve :D"
# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)

@ -1627,9 +1627,8 @@ class IMPORT_OT_obj(bpy.types.Operator):
bpy.types.register(IMPORT_OT_obj)
import dynamic_menu
menu_func = lambda self, context: self.layout.operator(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_import, menu_func)
menu_item = bpy.types.INFO_MT_file_import.append(menu_func)
# NOTES (all line numbers refer to 2.4x import_obj.py, not this file)

@ -379,6 +379,32 @@ class Macro(StructRNA, metaclass=OrderedMeta):
class Menu(StructRNA):
__slots__ = ()
@classmethod
def _dyn_menu_initialize(cls):
draw_funcs = getattr(cls.draw, "_draw_funcs", None)
if draw_funcs is None:
def draw_ls(*args):
for func in draw_ls._draw_funcs:
func(*args)
draw_funcs = draw_ls._draw_funcs = [cls.draw]
cls.draw = draw_ls
return draw_funcs
@classmethod
def append(cls, draw_func):
"""Prepend an draw function to this menu, takes the same arguments as the menus draw function."""
draw_funcs = cls._dyn_menu_initialize()
draw_funcs.append(draw_func)
@classmethod
def prepend(cls, draw_func):
"""Prepend a draw function to this menu, takes the same arguments as the menus draw function."""
draw_funcs = cls._dyn_menu_initialize()
draw_funcs.insert(0, draw_func)
def path_menu(self, searchpaths, operator):
layout = self.layout
@ -410,3 +436,4 @@ class Menu(StructRNA):
"""
import bpy
self.path_menu(bpy.utils.preset_paths(self.preset_subdir), self.preset_operator)

@ -1,118 +0,0 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
def collect_baseclasses(_class, bases):
if _class is type or _class is object:
return bases
bases.append(_class)
for _superclass in _class.__bases__:
collect_baseclasses(_superclass, bases)
return bases
def collect_subclasses(_class, subs):
if _class is type or _class is object:
return subs
subs.append(_class)
for _subclass in _class.__subclasses__():
collect_subclasses(_subclass, subs)
return subs
class DynMenu(bpy.types.Menu):
def draw(self, context):
'''
This is a draw function that is used to call all subclasses draw functions
starting from the registered classes draw function and working down.
DynMenu.setup() must be called first.
Sort/group classes could be nice
'''
subclass_ls = []
collect_subclasses(self.__class__, subclass_ls)
# print(subclass_ls)
for subclass in subclass_ls:
# print("drawwing", subclass) # , dir(subclass))
subclass.internal_draw(self, context)
# print("subclass.internal_draw", subclass.internal_draw)
def setup(menu_class):
'''
Setup subclasses (not needed when self.add() is used)
'''
bases = collect_baseclasses(menu_class, [])
# Incase 'DynMenu' isnt last
while bases[-1] is not DynMenu:
bases.pop()
bases.pop() # remove 'DynMenu'
root_class = bases[-1] # this is the registered class
for subclass in collect_subclasses(root_class, []):
#print(subclass)
draw = getattr(subclass, 'draw', None)
if draw and not hasattr(subclass, 'internal_draw'):
# print("replace", subclass, draw)
try:
del subclass.draw
except:
pass
subclass.internal_draw = draw
root_class.draw = DynMenu.draw
def add(menu_class, func):
'''
Add a single function directly without having to make a class
important that the returned value should be stored in the module that called it.
'''
newclass = type('<menuclass>', (menu_class,), {})
newclass.internal_draw = func
setup(menu_class)
return newclass
'''
# so we dont need to import this module
DynMenu.setup = setup
DynMenu.add = add
# Only so we can access as bpy.types.
# dont ever use this directly!
bpy.types.register(DynMenu)
'''

@ -613,11 +613,9 @@ class AddHuman(bpy.types.Operator):
bpy.types.register(AddHuman)
# Add to a menu
import dynamic_menu
menu_func = (lambda self, context: self.layout.operator(AddHuman.bl_idname, icon='OUTLINER_OB_ARMATURE', text="Human (Meta-Rig)"))
menu_item = dynamic_menu.add(bpy.types.INFO_MT_armature_add, menu_func)
bpy.types.INFO_MT_armature_add.append(menu_func)
if __name__ == "__main__":
bpy.ops.mesh.armature_human_advanced_add()

@ -127,13 +127,11 @@ class AddTorus(bpy.types.Operator):
# Register the operator
bpy.types.register(AddTorus)
# Add to a menu
import dynamic_menu
# Add to the menu
menu_func = (lambda self, context: self.layout.operator(AddTorus.bl_idname,
text="Torus", icon='MESH_DONUT'))
menu_item = dynamic_menu.add(bpy.types.INFO_MT_mesh_add, menu_func)
bpy.types.INFO_MT_mesh_add.append(menu_func)
if __name__ == "__main__":
bpy.ops.mesh.primitive_torus_add()

@ -650,8 +650,7 @@ class MESH_OT_skin(bpy.types.Operator):
bpy.types.register(MESH_OT_skin)
# Add to a menu
import dynamic_menu
menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_edit_mesh_faces, (lambda self, context: self.layout.operator("mesh.skin", text="Bridge Faces")) )
bpy.types.VIEW3D_MT_edit_mesh_faces.append((lambda self, context: self.layout.operator("mesh.skin", text="Bridge Faces")))
if __name__ == "__main__":
bpy.ops.mesh.skin()

@ -262,11 +262,8 @@ class FollowActiveQuads(bpy.types.Operator):
bpy.types.register(FollowActiveQuads)
# Add to a menu
import dynamic_menu
menu_func = (lambda self, context: self.layout.operator(FollowActiveQuads.bl_idname))
menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_uv_map, menu_func)
bpy.types.VIEW3D_MT_uv_map.append(menu_func)
if __name__ == '__main__':
bpy.ops.uv.follow_active_quads()

@ -1135,13 +1135,10 @@ class SmartProject(bpy.types.Operator):
bpy.types.register(SmartProject)
# Add to a menu
import dynamic_menu
menu_func = (lambda self, context: self.layout.operator(SmartProject.bl_idname,
text="Smart Project"))
menu_item = dynamic_menu.add(bpy.types.VIEW3D_MT_uv_map, menu_func)
bpy.types.VIEW3D_MT_uv_map.append(menu_func)
if __name__ == '__main__':
bpy.ops.uv.smart_project()

@ -49,10 +49,8 @@ class ExportSomeData(bpy.types.Operator):
bpy.types.register(ExportSomeData)
# Only needed if you want to add into a dynamic menu
import dynamic_menu
menu_func = lambda self, context: self.layout.operator("export.some_data", text="Example Exporter...")
menu_item = dynamic_menu.add(bpy.types.INFO_MT_file_export, menu_func)
bpy.types.INFO_MT_file_export.append(menu_func)
# Use for running this script directly
if __name__ == "__main__":
bpy.ops.export.some_data(path="/tmp/test.ply")

@ -313,11 +313,7 @@ class ActiveClear(bpy.types.Operator):
return {'FINISHED'}
import space_info
import dynamic_menu
class INFO_MT_armature_metarig_add(dynamic_menu.DynMenu):
class INFO_MT_armature_metarig_add(bpy.types.Menu):
bl_idname = "INFO_MT_armature_metarig_add"
bl_label = "Meta-Rig"
@ -349,5 +345,6 @@ bpy.types.register(ActiveClear)
bpy.types.register(INFO_MT_armature_metarig_add)
import space_info
menu_func = (lambda self, context: self.layout.menu("INFO_MT_armature_metarig_add", icon='OUTLINER_OB_ARMATURE'))
menu_item = dynamic_menu.add(bpy.types.INFO_MT_armature_add, menu_func)
space_info.INFO_MT_armature_add.append(menu_func)

@ -19,9 +19,6 @@
# <pep8 compliant>
import bpy
import dynamic_menu
# reload(dynamic_menu)
class INFO_HT_header(bpy.types.Header):
bl_space_type = 'INFO'
@ -115,21 +112,8 @@ class INFO_MT_file(bpy.types.Menu):
layout.operator_context = 'EXEC_AREA'
layout.operator("wm.exit_blender", text="Quit", icon='QUIT')
# test for expanding menus
'''
class INFO_MT_file_more(INFO_MT_file):
bl_label = "File"
def draw(self, context):
layout = self.layout
layout.operator("wm.read_homefile", text="TESTING ")
dynamic_menu.setup(INFO_MT_file_more)
'''
class INFO_MT_file_import(dynamic_menu.DynMenu):
class INFO_MT_file_import(bpy.types.Menu):
bl_idname = "INFO_MT_file_import"
bl_label = "Import"
@ -138,7 +122,7 @@ class INFO_MT_file_import(dynamic_menu.DynMenu):
self.layout.operator("wm.collada_import", text="COLLADA (.dae)...")
class INFO_MT_file_export(dynamic_menu.DynMenu):
class INFO_MT_file_export(bpy.types.Menu):
bl_idname = "INFO_MT_file_export"
bl_label = "Export"
@ -164,7 +148,7 @@ class INFO_MT_file_external_data(bpy.types.Menu):
layout.operator("file.find_missing_files")
class INFO_MT_mesh_add(dynamic_menu.DynMenu):
class INFO_MT_mesh_add(bpy.types.Menu):
bl_idname = "INFO_MT_mesh_add"
bl_label = "Mesh"
@ -183,7 +167,7 @@ class INFO_MT_mesh_add(dynamic_menu.DynMenu):
layout.operator("mesh.primitive_monkey_add", icon='MESH_MONKEY', text="Monkey")
class INFO_MT_armature_add(dynamic_menu.DynMenu):
class INFO_MT_armature_add(bpy.types.Menu):
bl_idname = "INFO_MT_armature_add"
bl_label = "Armature"

@ -18,7 +18,6 @@
# <pep8 compliant>
import bpy
import dynamic_menu
class VIEW3D_HT_header(bpy.types.Header):
@ -205,7 +204,7 @@ class VIEW3D_MT_snap(bpy.types.Menu):
layout.operator("view3d.snap_cursor_to_active", text="Cursor to Active")
class VIEW3D_MT_uv_map(dynamic_menu.DynMenu):
class VIEW3D_MT_uv_map(bpy.types.Menu):
bl_label = "UV Mapping"
def draw(self, context):
@ -1231,7 +1230,7 @@ class VIEW3D_MT_edit_mesh_edges(bpy.types.Menu):
layout.operator("mesh.region_to_loop")
class VIEW3D_MT_edit_mesh_faces(dynamic_menu.DynMenu):
class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu):
bl_label = "Faces"
bl_idname = "VIEW3D_MT_edit_mesh_faces"

@ -27,8 +27,6 @@ This will generate python files in "./source/blender/python/doc/bpy/sphinx-in"
Generate html docs by running...
sphinx-build source/blender/python/doc/bpy/sphinx-in source/blender/python/doc/bpy/sphinx-out
'''
# if you dont have graphvis installed ommit the --graph arg.
@ -75,7 +73,7 @@ def py_function_args(func):
INVALID = py_function_args
defaults = ([INVALID] * (len(names) - len(defaults))) + defaults
if names[0] == "self":
if names[0] in ("self", "cls"): # normal class function or classmethod
del names[0]
del defaults[0]