This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/release/scripts/modules/bpy_ops.py
Campbell Barton b06640c583 changed WM_OT_context_* operators to pass through if one of the members in the path is None, rather then raising an error.
This means if you refer to a member of an object it will fail silently if there is no active object, but if you use an invalid attribute of the object it raises an error.
The method to check this is not nice but works well enough.

also removed pageup/down keys for changing the active shape since listviews can do this now.
2009-10-22 16:21:06 +00:00

327 lines
9.2 KiB
Python

# for slightly faster access
from bpy.__ops__ import add as op_add
from bpy.__ops__ import remove as op_remove
from bpy.__ops__ import dir as op_dir
from bpy.__ops__ import call as op_call
from bpy.__ops__ import as_string as op_as_string
from bpy.__ops__ import get_rna as op_get_rna
# Keep in sync with WM_types.h
context_dict = {
'INVOKE_DEFAULT':0,
'INVOKE_REGION_WIN':1,
'INVOKE_AREA':2,
'INVOKE_SCREEN':3,
'EXEC_DEFAULT':4,
'EXEC_REGION_WIN':5,
'EXEC_AREA':6,
'EXEC_SCREEN':7,
}
class bpy_ops(object):
'''
Fake module like class.
bpy.ops
'''
def add(self, pyop):
op_add(pyop)
def remove(self, pyop):
op_remove(pyop)
def __getattr__(self, module):
'''
gets a bpy.ops submodule
'''
return bpy_ops_submodule(module)
def __dir__(self):
submodules = set()
# add this classes functions
for id_name in dir(self.__class__):
if not id_name.startswith('__'):
submodules.add(id_name)
for id_name in op_dir():
id_split = id_name.split('_OT_', 1)
if len(id_split) == 2:
submodules.add(id_split[0].lower())
else:
submodules.add(id_split[0])
return list(submodules)
def __repr__(self):
return "<module like class 'bpy.ops'>"
class bpy_ops_submodule(object):
'''
Utility class to fake submodules.
eg. bpy.ops.object
'''
__keys__ = ('module',)
def __init__(self, module):
self.module = module
def __getattr__(self, func):
'''
gets a bpy.ops.submodule function
'''
return bpy_ops_submodule_op(self.module, func)
def __dir__(self):
functions = set()
module_upper = self.module.upper()
for id_name in op_dir():
id_split = id_name.split('_OT_', 1)
if len(id_split) == 2 and module_upper == id_split[0]:
functions.add(id_split[1])
return list(functions)
def __repr__(self):
return "<module like class 'bpy.ops.%s'>" % self.module
class bpy_ops_submodule_op(object):
'''
Utility class to fake submodule operators.
eg. bpy.ops.object.somefunc
'''
__keys__ = ('module', 'func')
def __init__(self, module, func):
self.module = module
self.func = func
def idname(self):
# submod.foo -> SUBMOD_OT_foo
return self.module.upper() + '_OT_' + self.func
def __call__(self, *args, **kw):
# Get the operator from blender
if len(args) > 1:
raise ValueError("only one argument for the execution context is supported ")
if args:
try:
context = context_dict[args[0]]
except:
raise ValueError("Expected a single context argument in: " + str(list(context_dict.keys())))
return op_call(self.idname(), kw, context)
else:
return op_call(self.idname(), kw)
def get_rna(self):
'''
currently only used for '__rna__'
'''
return op_get_rna(self.idname())
def __repr__(self): # useful display, repr(op)
return op_as_string(self.idname())
def __str__(self): # used for print(...)
return "<function bpy.ops.%s.%s at 0x%x'>" % (self.module, self.func, id(self))
import bpy
bpy.ops = bpy_ops()
# TODO, C macro's cant define settings :|
class MESH_OT_delete_edgeloop(bpy.types.Operator):
'''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
__idname__ = "mesh.delete_edgeloop"
__label__ = "Delete Edge Loop"
def execute(self, context):
bpy.ops.tfm.edge_slide(value=1.0)
bpy.ops.mesh.select_more()
bpy.ops.mesh.remove_doubles()
return ('FINISHED',)
rna_path_prop = bpy.props.StringProperty(attr="path", name="Context Attributes", description="rna context string", maxlen= 1024, default= "")
rna_reverse_prop = bpy.props.BoolProperty(attr="reverse", name="Reverse", description="Cycle backwards", default= False)
class NullPathMember:
pass
def context_path_validate(context, path):
import sys
try:
value = eval("context.%s" % path)
except AttributeError:
if "'NoneType'" in str(sys.exc_info()[1]):
# One of the items in the rna path is None, just ignore this
value = NullPathMember
else:
# We have a real error in the rna path, dont ignore that
raise
return value
def execute_context_assign(self, context):
if context_path_validate(context, self.path) == NullPathMember:
return ('PASS_THROUGH',)
exec("context.%s=self.value" % self.path)
return ('FINISHED',)
class WM_OT_context_set_boolean(bpy.types.Operator):
'''Set a context value.'''
__idname__ = "wm.context_set_boolean"
__label__ = "Context Set"
__props__ = [rna_path_prop, bpy.props.BoolProperty(attr="value", name="Value", description="Assignment value", default= True)]
execute = execute_context_assign
class WM_OT_context_set_int(bpy.types.Operator): # same as enum
'''Set a context value.'''
__idname__ = "wm.context_set_int"
__label__ = "Context Set"
__props__ = [rna_path_prop, bpy.props.IntProperty(attr="value", name="Value", description="Assignment value", default= 0)]
execute = execute_context_assign
class WM_OT_context_set_float(bpy.types.Operator): # same as enum
'''Set a context value.'''
__idname__ = "wm.context_set_int"
__label__ = "Context Set"
__props__ = [rna_path_prop, bpy.props.FloatProperty(attr="value", name="Value", description="Assignment value", default= 0.0)]
execute = execute_context_assign
class WM_OT_context_set_string(bpy.types.Operator): # same as enum
'''Set a context value.'''
__idname__ = "wm.context_set_string"
__label__ = "Context Set"
__props__ = [rna_path_prop, bpy.props.StringProperty(attr="value", name="Value", description="Assignment value", maxlen= 1024, default= "")]
execute = execute_context_assign
class WM_OT_context_set_enum(bpy.types.Operator):
'''Set a context value.'''
__idname__ = "wm.context_set_enum"
__label__ = "Context Set"
__props__ = [rna_path_prop, bpy.props.StringProperty(attr="value", name="Value", description="Assignment value (as a string)", maxlen= 1024, default= "")]
execute = execute_context_assign
class WM_OT_context_toggle(bpy.types.Operator):
'''Toggle a context value.'''
__idname__ = "wm.context_toggle"
__label__ = "Context Toggle"
__props__ = [rna_path_prop]
def execute(self, context):
if context_path_validate(context, self.path) == NullPathMember:
return ('PASS_THROUGH',)
exec("context.%s=not (context.%s)" % (self.path, self.path)) # security nuts will complain.
return ('FINISHED',)
class WM_OT_context_toggle_enum(bpy.types.Operator):
'''Toggle a context value.'''
__idname__ = "wm.context_toggle_enum"
__label__ = "Context Toggle Values"
__props__ = [
rna_path_prop,
bpy.props.StringProperty(attr="value_1", name="Value", description="Toggle enum", maxlen= 1024, default= ""),
bpy.props.StringProperty(attr="value_2", name="Value", description="Toggle enum", maxlen= 1024, default= "")
]
def execute(self, context):
if context_path_validate(context, self.path) == NullPathMember:
return ('PASS_THROUGH',)
exec("context.%s = ['%s', '%s'][context.%s!='%s']" % (self.path, self.value_1, self.value_2, self.path, self.value_2)) # security nuts will complain.
return ('FINISHED',)
class WM_OT_context_cycle_int(bpy.types.Operator):
'''Set a context value. Useful for cycling active material, vertex keys, groups' etc.'''
__idname__ = "wm.context_cycle_int"
__label__ = "Context Int Cycle"
__props__ = [rna_path_prop, rna_reverse_prop]
def execute(self, context):
value = context_path_validate(context, self.path)
if value == NullPathMember:
return ('PASS_THROUGH',)
self.value = value
if self.reverse: self.value -= 1
else: self.value += 1
execute_context_assign(self, context)
if self.value != eval("context.%s" % self.path):
# relies on rna clamping int's out of the range
if self.reverse: self.value = (1<<32)
else: self.value = -(1<<32)
execute_context_assign(self, context)
return ('FINISHED',)
class WM_OT_context_cycle_enum(bpy.types.Operator):
'''Toggle a context value.'''
__idname__ = "wm.context_cycle_enum"
__label__ = "Context Enum Cycle"
__props__ = [rna_path_prop, rna_reverse_prop]
def execute(self, context):
value = context_path_validate(context, self.path)
if value == NullPathMember:
return ('PASS_THROUGH',)
orig_value = value
# Have to get rna enum values
rna_struct_str, rna_prop_str = self.path.rsplit('.', 1)
i = rna_prop_str.find('[')
if i != -1: rna_prop_str = rna_prop_str[0:i] # just incse we get "context.foo.bar[0]"
rna_struct = eval("context.%s.rna_type" % rna_struct_str)
rna_prop = rna_struct.properties[rna_prop_str]
if type(rna_prop) != bpy.types.EnumProperty:
raise Exception("expected an enum property")
enums = rna_struct.properties[rna_prop_str].items.keys()
orig_index = enums.index(orig_value)
# Have the info we need, advance to the next item
if self.reverse:
if orig_index==0: advance_enum = enums[-1]
else: advance_enum = enums[orig_index-1]
else:
if orig_index==len(enums)-1: advance_enum = enums[0]
else: advance_enum = enums[orig_index+1]
# set the new value
exec("context.%s=advance_enum" % self.path)
return ('FINISHED',)
bpy.ops.add(MESH_OT_delete_edgeloop)
bpy.ops.add(WM_OT_context_set_boolean)
bpy.ops.add(WM_OT_context_set_int)
bpy.ops.add(WM_OT_context_set_float)
bpy.ops.add(WM_OT_context_set_string)
bpy.ops.add(WM_OT_context_set_enum)
bpy.ops.add(WM_OT_context_toggle)
bpy.ops.add(WM_OT_context_toggle_enum)
bpy.ops.add(WM_OT_context_cycle_enum)
bpy.ops.add(WM_OT_context_cycle_int)