RNA Types metaclass registration
See mailing list posts for details [1][2][3] Addons still need to be fixed; Campbell said he'd do it today. See any of the py files (outside netrender) in this commit for how to do it (it's rather simple). [1] http://lists.blender.org/pipermail/bf-committers/2010-February/026328.html [2] http://lists.blender.org/pipermail/bf-committers/2010-August/028311.html [3] http://lists.blender.org/pipermail/bf-committers/2010-August/028321.html
This commit is contained in:
@@ -29,6 +29,7 @@ import sys as _sys
|
||||
|
||||
from _bpy import blend_paths
|
||||
from _bpy import script_paths as _bpy_script_paths
|
||||
from _bpy import LoadModule, UnloadModule
|
||||
|
||||
|
||||
def _test_import(module_name, loaded_modules):
|
||||
@@ -84,7 +85,7 @@ def modules_from_path(path, loaded_modules):
|
||||
modules.append(mod)
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
_loaded = [] # store loaded modules for reloading.
|
||||
_bpy_types = __import__("bpy_types") # keep for comparisons, never ever reload this.
|
||||
|
||||
@@ -108,6 +109,15 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
|
||||
if refresh_scripts:
|
||||
original_modules = _sys.modules.values()
|
||||
|
||||
def unload_module(mod):
|
||||
UnloadModule(mod.__name__)
|
||||
unregister = getattr(mod, "unregister", None)
|
||||
if unregister:
|
||||
try:
|
||||
unregister()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def sys_path_ensure(path):
|
||||
if path not in _sys.path: # reloading would add twice
|
||||
_sys.path.insert(0, path)
|
||||
@@ -134,6 +144,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
|
||||
mod = test_reload(mod)
|
||||
|
||||
if mod:
|
||||
LoadModule(mod.__name__, reload_scripts)
|
||||
register = getattr(mod, "register", None)
|
||||
if register:
|
||||
try:
|
||||
@@ -165,12 +176,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
|
||||
# loop over and unload all scripts
|
||||
_loaded.reverse()
|
||||
for mod in _loaded:
|
||||
unregister = getattr(mod, "unregister", None)
|
||||
if unregister:
|
||||
try:
|
||||
unregister()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
unload_module(mod)
|
||||
|
||||
for mod in _loaded:
|
||||
reload(mod)
|
||||
@@ -336,7 +342,7 @@ _presets = _os.path.join(_scripts[0], "presets") # FIXME - multiple paths
|
||||
|
||||
def preset_paths(subdir):
|
||||
'''
|
||||
Returns a list of paths for a spesific preset.
|
||||
Returns a list of paths for a specific preset.
|
||||
'''
|
||||
|
||||
return (_os.path.join(_presets, subdir), )
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
# <pep8 compliant>
|
||||
|
||||
from _bpy import types as bpy_types
|
||||
import _bpy
|
||||
from mathutils import Vector
|
||||
|
||||
StructRNA = bpy_types.Struct.__bases__[0]
|
||||
@@ -539,8 +540,64 @@ class Text(bpy_types.ID):
|
||||
|
||||
import collections
|
||||
|
||||
TypeMap = {}
|
||||
# Properties (IDPropertyGroup) are different from types because they need to be registered
|
||||
# before adding sub properties to them, so they are registered on definition
|
||||
# and unregistered on unload
|
||||
PropertiesMap = {}
|
||||
|
||||
class OrderedMeta(type):
|
||||
def UnloadModule(module):
|
||||
global TypeMap, PropertiesMap
|
||||
for t in TypeMap.get(module, []):
|
||||
bpy_types.unregister(t)
|
||||
|
||||
TypeMap = {}
|
||||
|
||||
for t in PropertiesMap.get(module, []):
|
||||
bpy_types.unregister(t)
|
||||
|
||||
PropertiesMap = {}
|
||||
|
||||
def LoadModule(module, force=False):
|
||||
for t in TypeMap.get(module, []):
|
||||
bpy_types.register(t)
|
||||
|
||||
_bpy.LoadModule = LoadModule
|
||||
_bpy.UnloadModule = UnloadModule
|
||||
|
||||
class RNAMeta(type):
|
||||
@classmethod
|
||||
def _immediate(cls):
|
||||
return bpy_types.immediate();
|
||||
|
||||
def __new__(cls, name, bases, classdict, **args):
|
||||
result = type.__new__(cls, name, bases, classdict)
|
||||
if bases and bases[0] != StructRNA:
|
||||
module = result.__module__
|
||||
|
||||
ClassMap = TypeMap
|
||||
|
||||
# Register right away if needed
|
||||
if cls._immediate():
|
||||
bpy_types.register(result)
|
||||
ClassMap = PropertiesMap
|
||||
|
||||
# first part of packages only
|
||||
if "." in module:
|
||||
module = module[:module.index(".")]
|
||||
|
||||
if not module in ClassMap:
|
||||
ClassMap[module] = []
|
||||
|
||||
ClassMap[module].append(result)
|
||||
return result
|
||||
|
||||
class RNAMetaRegister(RNAMeta):
|
||||
@classmethod
|
||||
def _immediate(cls):
|
||||
return True;
|
||||
|
||||
class OrderedMeta(RNAMeta):
|
||||
|
||||
def __init__(cls, name, bases, attributes):
|
||||
super(OrderedMeta, cls).__init__(name, bases, attributes)
|
||||
@@ -549,7 +606,6 @@ class OrderedMeta(type):
|
||||
def __prepare__(name, bases, **kwargs):
|
||||
return collections.OrderedDict()
|
||||
|
||||
|
||||
# Only defined so operators members can be used by accessing self.order
|
||||
class Operator(StructRNA, metaclass=OrderedMeta):
|
||||
__slots__ = ()
|
||||
@@ -564,7 +620,12 @@ class Macro(StructRNA, metaclass=OrderedMeta):
|
||||
def define(self, opname):
|
||||
from _bpy import ops
|
||||
return ops.macro_define(self, opname)
|
||||
|
||||
class IDPropertyGroup(StructRNA, metaclass=RNAMetaRegister):
|
||||
__slots__ = ()
|
||||
|
||||
class RenderEngine(StructRNA, metaclass=RNAMeta):
|
||||
__slots__ = ()
|
||||
|
||||
class _GenericUI:
|
||||
__slots__ = ()
|
||||
@@ -606,15 +667,15 @@ class _GenericUI:
|
||||
pass
|
||||
|
||||
|
||||
class Panel(StructRNA, _GenericUI):
|
||||
class Panel(StructRNA, _GenericUI, metaclass=RNAMeta):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
class Header(StructRNA, _GenericUI):
|
||||
class Header(StructRNA, _GenericUI, metaclass=RNAMeta):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
class Menu(StructRNA, _GenericUI):
|
||||
class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
|
||||
__slots__ = ()
|
||||
|
||||
def path_menu(self, searchpaths, operator, props_default={}):
|
||||
|
||||
@@ -124,7 +124,7 @@ def draw(layout, context, context_member, use_edit=True):
|
||||
assign_props(prop, val_draw, key)
|
||||
|
||||
|
||||
class PropertyPanel(bpy.types.Panel):
|
||||
class PropertyPanel():
|
||||
"""
|
||||
The subclass should have its own poll function
|
||||
and the variable '_context_path' MUST be set.
|
||||
@@ -135,130 +135,3 @@ class PropertyPanel(bpy.types.Panel):
|
||||
def draw(self, context):
|
||||
draw(self.layout, context, self._context_path)
|
||||
|
||||
|
||||
from bpy.props import *
|
||||
|
||||
|
||||
rna_path = StringProperty(name="Property Edit",
|
||||
description="Property data_path edit", maxlen=1024, default="", options={'HIDDEN'})
|
||||
|
||||
rna_value = StringProperty(name="Property Value",
|
||||
description="Property value edit", maxlen=1024, default="")
|
||||
|
||||
rna_property = StringProperty(name="Property Name",
|
||||
description="Property name edit", maxlen=1024, default="")
|
||||
|
||||
rna_min = FloatProperty(name="Min", default=0.0, precision=3)
|
||||
rna_max = FloatProperty(name="Max", default=1.0, precision=3)
|
||||
|
||||
|
||||
class WM_OT_properties_edit(bpy.types.Operator):
|
||||
'''Internal use (edit a property data_path)'''
|
||||
bl_idname = "wm.properties_edit"
|
||||
bl_label = "Edit Property"
|
||||
|
||||
data_path = rna_path
|
||||
property = rna_property
|
||||
value = rna_value
|
||||
min = rna_min
|
||||
max = rna_max
|
||||
description = StringProperty(name="Tip", default="")
|
||||
|
||||
def execute(self, context):
|
||||
data_path = self.properties.data_path
|
||||
value = self.properties.value
|
||||
prop = self.properties.property
|
||||
prop_old = self._last_prop[0]
|
||||
|
||||
try:
|
||||
value_eval = eval(value)
|
||||
except:
|
||||
value_eval = value
|
||||
|
||||
# First remove
|
||||
item = eval("context.%s" % data_path)
|
||||
|
||||
rna_idprop_ui_prop_clear(item, prop_old)
|
||||
exec_str = "del item['%s']" % prop_old
|
||||
# print(exec_str)
|
||||
exec(exec_str)
|
||||
|
||||
|
||||
# Reassign
|
||||
exec_str = "item['%s'] = %s" % (prop, repr(value_eval))
|
||||
# print(exec_str)
|
||||
exec(exec_str)
|
||||
self._last_prop[:] = [prop]
|
||||
|
||||
prop_type = type(item[prop])
|
||||
|
||||
prop_ui = rna_idprop_ui_prop_get(item, prop)
|
||||
|
||||
if prop_type in (float, int):
|
||||
|
||||
prop_ui['soft_min'] = prop_ui['min'] = prop_type(self.properties.min)
|
||||
prop_ui['soft_max'] = prop_ui['max'] = prop_type(self.properties.max)
|
||||
|
||||
prop_ui['description'] = self.properties.description
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
|
||||
self._last_prop = [self.properties.property]
|
||||
|
||||
item = eval("context.%s" % self.properties.data_path)
|
||||
|
||||
# setup defaults
|
||||
prop_ui = rna_idprop_ui_prop_get(item, self.properties.property, False) # dont create
|
||||
if prop_ui:
|
||||
self.properties.min = prop_ui.get("min", -1000000000)
|
||||
self.properties.max = prop_ui.get("max", 1000000000)
|
||||
self.properties.description = prop_ui.get("description", "")
|
||||
|
||||
wm = context.manager
|
||||
# This crashes, TODO - fix
|
||||
#return wm.invoke_props_popup(self, event)
|
||||
|
||||
wm.invoke_props_popup(self, event)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
|
||||
class WM_OT_properties_add(bpy.types.Operator):
|
||||
'''Internal use (edit a property data_path)'''
|
||||
bl_idname = "wm.properties_add"
|
||||
bl_label = "Add Property"
|
||||
|
||||
data_path = rna_path
|
||||
|
||||
def execute(self, context):
|
||||
item = eval("context.%s" % self.properties.data_path)
|
||||
|
||||
def unique_name(names):
|
||||
prop = 'prop'
|
||||
prop_new = prop
|
||||
i = 1
|
||||
while prop_new in names:
|
||||
prop_new = prop + str(i)
|
||||
i += 1
|
||||
|
||||
return prop_new
|
||||
|
||||
property = unique_name(item.keys())
|
||||
|
||||
item[property] = 1.0
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class WM_OT_properties_remove(bpy.types.Operator):
|
||||
'''Internal use (edit a property data_path)'''
|
||||
bl_idname = "wm.properties_remove"
|
||||
bl_label = "Remove Property"
|
||||
|
||||
data_path = rna_path
|
||||
property = rna_property
|
||||
|
||||
def execute(self, context):
|
||||
item = eval("context.%s" % self.properties.data_path)
|
||||
del item[self.properties.property]
|
||||
return {'FINISHED'}
|
||||
|
||||
Reference in New Issue
Block a user