added new context operator WM_OT_context_cycle_int, use for switching between active...
[blender-staging.git] / release / scripts / modules / bpy_ops.py
1 # for slightly faster access
2 from bpy.__ops__ import add             as op_add
3 from bpy.__ops__ import remove          as op_remove
4 from bpy.__ops__ import dir             as op_dir
5 from bpy.__ops__ import call            as op_call
6 from bpy.__ops__ import as_string       as op_as_string
7 from bpy.__ops__ import get_rna as op_get_rna
8
9 # Keep in sync with WM_types.h
10 context_dict = {
11         'INVOKE_DEFAULT':0,
12         'INVOKE_REGION_WIN':1,
13         'INVOKE_AREA':2,
14         'INVOKE_SCREEN':3,
15         'EXEC_DEFAULT':4,
16         'EXEC_REGION_WIN':5,
17         'EXEC_AREA':6,
18         'EXEC_SCREEN':7,
19 }
20
21 class bpy_ops(object):
22         '''
23         Fake module like class.
24         
25          bpy.ops
26         '''
27         def add(self, pyop):
28                 op_add(pyop)
29         
30         def remove(self, pyop):
31                 op_remove(pyop)
32         
33         def __getattr__(self, module):
34                 '''
35                 gets a bpy.ops submodule
36                 '''
37                 return bpy_ops_submodule(module)
38                 
39         def __dir__(self):
40                 
41                 submodules = set()
42                 
43                 # add this classes functions
44                 for id_name in dir(self.__class__):
45                         if not id_name.startswith('__'):
46                                 submodules.add(id_name)
47                 
48                 for id_name in op_dir():
49                         id_split = id_name.split('_OT_', 1)
50                         
51                         if len(id_split) == 2:
52                                 submodules.add(id_split[0].lower())
53                         else:
54                                 submodules.add(id_split[0])
55                 
56                 return list(submodules)
57                 
58         def __repr__(self):
59                 return "<module like class 'bpy.ops'>"
60
61
62 class bpy_ops_submodule(object):
63         '''
64         Utility class to fake submodules.
65         
66         eg. bpy.ops.object
67         '''
68         __keys__ = ('module',)
69         
70         def __init__(self, module):
71                 self.module = module
72                 
73         def __getattr__(self, func):
74                 '''
75                 gets a bpy.ops.submodule function
76                 '''
77                 return bpy_ops_submodule_op(self.module, func)
78                 
79         def __dir__(self):
80                 
81                 functions = set()
82                 
83                 module_upper = self.module.upper()
84                 
85                 for id_name in op_dir():
86                         id_split = id_name.split('_OT_', 1)
87                         if len(id_split) == 2 and module_upper == id_split[0]:
88                                 functions.add(id_split[1])
89                 
90                 return list(functions)
91         
92         def __repr__(self):
93                 return "<module like class 'bpy.ops.%s'>" % self.module
94
95 class bpy_ops_submodule_op(object):
96         '''
97         Utility class to fake submodule operators.
98         
99         eg. bpy.ops.object.somefunc
100         '''
101         __keys__ = ('module', 'func')
102         def __init__(self, module, func):
103                 self.module = module
104                 self.func = func
105         
106         def idname(self):
107                 # submod.foo -> SUBMOD_OT_foo
108                 return self.module.upper() + '_OT_' + self.func
109         
110         def __call__(self, *args, **kw):
111                 
112                 # Get the operator from blender
113                 if len(args) > 1:
114                         raise ValueError("only one argument for the execution context is supported ")
115                 
116                 if args:
117                         try:
118                                 context = context_dict[args[0]]
119                         except:
120                                 raise ValueError("Expected a single context argument in: " + str(list(context_dict.keys())))
121                         
122                         return op_call(self.idname(), kw, context)
123                 
124                 else:
125                         return op_call(self.idname(), kw)
126         
127         def get_rna(self):
128                 '''
129                 currently only used for '__rna__'
130                 '''
131                 return op_get_rna(self.idname())
132                         
133         
134         def __repr__(self): # useful display, repr(op)
135                 return op_as_string(self.idname())
136         
137         def __str__(self): # used for print(...)
138                 return "<function bpy.ops.%s.%s at 0x%x'>" % (self.module, self.func, id(self))
139
140 import bpy
141 bpy.ops = bpy_ops()
142
143 # TODO, C macro's cant define settings :|
144
145 class MESH_OT_delete_edgeloop(bpy.types.Operator):
146         '''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
147         __idname__ = "mesh.delete_edgeloop"
148         __label__ = "Delete Edge Loop"
149         
150         def execute(self, context):
151                 bpy.ops.tfm.edge_slide(value=1.0)
152                 bpy.ops.mesh.select_more()
153                 bpy.ops.mesh.remove_doubles()
154                 return ('FINISHED',)
155
156 rna_path_prop = bpy.props.StringProperty(attr="path", name="Context Attributes", description="rna context string", maxlen= 1024, default= "")
157 rna_reverse_prop = bpy.props.BoolProperty(attr="reverse", name="Reverse", description="Cycle backwards", default= False)
158
159 def execute_context_assign(self, context):
160         exec("context.%s=self.value" % self.path)
161         return ('FINISHED',)
162
163 class WM_OT_context_set_boolean(bpy.types.Operator):
164         '''Set a context value.'''
165         __idname__ = "wm.context_set_boolean"
166         __label__ = "Context Set"
167         __props__ = [rna_path_prop, bpy.props.BoolProperty(attr="value", name="Value", description="Assignment value", default= True)]
168         execute = execute_context_assign
169
170 class WM_OT_context_set_int(bpy.types.Operator): # same as enum
171         '''Set a context value.'''
172         __idname__ = "wm.context_set_int"
173         __label__ = "Context Set"
174         __props__ = [rna_path_prop, bpy.props.IntProperty(attr="value", name="Value", description="Assignment value", default= 0)]
175         execute = execute_context_assign
176                 
177 class WM_OT_context_set_float(bpy.types.Operator): # same as enum
178         '''Set a context value.'''
179         __idname__ = "wm.context_set_int"
180         __label__ = "Context Set"
181         __props__ = [rna_path_prop, bpy.props.FloatProperty(attr="value", name="Value", description="Assignment value", default= 0.0)]
182         execute = execute_context_assign
183
184 class WM_OT_context_set_string(bpy.types.Operator): # same as enum
185         '''Set a context value.'''
186         __idname__ = "wm.context_set_string"
187         __label__ = "Context Set"
188         __props__ = [rna_path_prop, bpy.props.StringProperty(attr="value", name="Value", description="Assignment value", maxlen= 1024, default= "")]
189         execute = execute_context_assign
190
191 class WM_OT_context_set_enum(bpy.types.Operator):
192         '''Set a context value.'''
193         __idname__ = "wm.context_set_enum"
194         __label__ = "Context Set"
195         __props__ = [rna_path_prop, bpy.props.StringProperty(attr="value", name="Value", description="Assignment value (as a string)", maxlen= 1024, default= "")]
196         execute = execute_context_assign
197
198 class WM_OT_context_toggle(bpy.types.Operator):
199         '''Toggle a context value.'''
200         __idname__ = "wm.context_toggle"
201         __label__ = "Context Toggle"
202         __props__ = [rna_path_prop]
203         def execute(self, context):
204                 exec("context.%s=not (context.%s)" % (self.path, self.path)) # security nuts will complain.
205                 return ('FINISHED',)
206
207 class WM_OT_context_toggle_enum(bpy.types.Operator):
208         '''Toggle a context value.'''
209         __idname__ = "wm.context_toggle_enum"
210         __label__ = "Context Toggle Values"
211         __props__ = [
212                 rna_path_prop,
213                 bpy.props.StringProperty(attr="value_1", name="Value", description="Toggle enum", maxlen= 1024, default= ""),
214                 bpy.props.StringProperty(attr="value_2", name="Value", description="Toggle enum", maxlen= 1024, default= "")
215         ]
216         def execute(self, context):
217                 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.
218                 return ('FINISHED',)
219
220 class WM_OT_context_cycle_int(bpy.types.Operator):
221         '''Set a context value. Useful for cycling active material, vertex keys, groups' etc.'''
222         __idname__ = "wm.context_cycle_int"
223         __label__ = "Context Int Cycle"
224         __props__ = [rna_path_prop, rna_reverse_prop]
225         def execute(self, context):
226                 self.value = eval("context.%s" % self.path)
227                 if self.reverse:        self.value -= 1
228                 else:           self.value += 1
229                 execute_context_assign(self, context)
230                 
231                 if self.value != eval("context.%s" % self.path):
232                         # relies on rna clamping int's out of the range
233                         if self.reverse:        self.value =  (1<<32)
234                         else:           self.value = -(1<<32)
235                         execute_context_assign(self, context)
236                         
237                 return ('FINISHED',)
238
239 class WM_OT_context_cycle_enum(bpy.types.Operator):
240         '''Toggle a context value.'''
241         __idname__ = "wm.context_cycle_enum"
242         __label__ = "Context Enum Cycle"
243         __props__ = [rna_path_prop, rna_reverse_prop]
244         def execute(self, context):
245                 orig_value = eval("context.%s" % self.path) # security nuts will complain.
246                 
247                 # Have to get rna enum values
248                 rna_struct_str, rna_prop_str =  self.path.rsplit('.', 1)
249                 i = rna_prop_str.find('[')
250                 if i != -1: rna_prop_str = rna_prop_str[0:i] # just incse we get "context.foo.bar[0]"
251                 
252                 rna_struct = eval("context.%s.rna_type" % rna_struct_str)
253                 
254                 rna_prop = rna_struct.properties[rna_prop_str]
255                 
256                 if type(rna_prop) != bpy.types.EnumProperty:
257                         raise Exception("expected an enum property")
258                 
259                 enums = rna_struct.properties[rna_prop_str].items.keys()
260                 orig_index = enums.index(orig_value)
261                 
262                 # Have the info we need, advance to the next item
263                 if self.reverse:
264                         if orig_index==0:                       advance_enum = enums[-1]
265                         else:                                   advance_enum = enums[orig_index-1]
266                 else:
267                         if orig_index==len(enums)-1:    advance_enum = enums[0]
268                         else:                                   advance_enum = enums[orig_index+1]
269                 
270                 # set the new value
271                 exec("context.%s=advance_enum" % self.path)
272                 return ('FINISHED',)
273
274
275 bpy.ops.add(MESH_OT_delete_edgeloop)
276
277 bpy.ops.add(WM_OT_context_set_boolean)
278 bpy.ops.add(WM_OT_context_set_int)
279 bpy.ops.add(WM_OT_context_set_float)
280 bpy.ops.add(WM_OT_context_set_string)
281 bpy.ops.add(WM_OT_context_set_enum)
282 bpy.ops.add(WM_OT_context_toggle)
283 bpy.ops.add(WM_OT_context_toggle_enum)
284 bpy.ops.add(WM_OT_context_cycle_enum)
285 bpy.ops.add(WM_OT_context_cycle_int)
286