- new objects added from the rna api defaulted to quat rotation, not even using an...
[blender.git] / release / scripts / modules / bpy_types.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18 from _bpy import types as bpy_types
19
20 StructRNA = bpy_types.Struct.__bases__[0]
21 # StructRNA = bpy_types.Struct
22
23
24 class Context(StructRNA):
25
26     def copy(self):
27         new_context = {}
28         generic_keys = StructRNA.__dict__.keys()
29         for item in dir(self):
30             if item not in generic_keys:
31                 new_context[item] = getattr(self, item)
32
33         return new_context
34
35
36 class Object(bpy_types.ID):
37
38     @property
39     def children(self):
40         import bpy
41         return [child for child in bpy.data.objects if child.parent == self]
42
43
44 class _GenericBone:
45     '''
46     functions for bones, common between Armature/Pose/Edit bones.
47     internal subclassing use only.
48     '''
49     def parent_index(self, parent_test):
50         '''
51         The same as 'bone in other_bone.parent_recursive' but saved generating a list.
52         '''
53         # use the name so different types can be tested.
54         name = parent_test.name
55         
56         parent = self.parent
57         i = 1
58         while parent:
59             if parent.name == name:
60                 return i
61             parent = parent.parent
62             i += 1
63         
64         return 0
65
66     @property
67     def parent_recursive(self):
68         parent_list = []
69         parent = self.parent
70         
71         while parent:
72             if parent:
73                 parent_list.append(parent)
74             
75             parent = parent.parent
76         
77         return parent_list
78
79     @property
80     def length(self):
81         return (self.head - self.tail).length
82
83     @property
84     def children(self):
85         return [child for child in self._other_bones if child.parent == self]
86
87     @property
88     def children_recursive(self):
89         bones_children = []
90         for bone in self._other_bones:
91             index = bone.parent_index(self)
92             if index:
93                 bones_children.append((index, bone))
94         
95         # sort by distance to parent
96         bones_children.sort(key=lambda bone_pair: bone_pair[0])
97         return [bone for index, bone in bones_children]
98
99     @property
100     def _other_bones(self):
101         id_data = self.id_data
102         id_data_type = type(id_data)
103         
104         if id_data_type == bpy_types.Object:
105             bones = id_data.pose.bones
106         elif id_data_type == bpy_types.Armature:
107             bones = id_data.edit_bones
108             if not bones: # not in editmode
109                 bones = id_data.bones
110         
111         return bones
112
113
114 class PoseBone(StructRNA, _GenericBone):
115     pass
116
117
118 class Bone(StructRNA, _GenericBone):
119     pass
120
121
122 class EditBone(StructRNA, _GenericBone):
123     pass
124
125
126 def ord_ind(i1,i2):
127     if i1<i2: return i1,i2
128     return i2,i1
129
130 class Mesh(bpy_types.ID):
131     
132     def from_pydata(self, verts, edges, faces):
133         '''
134         Make a mesh from a list of verts/edges/faces
135         Until we have a nicer way to make geometry, use this.
136         '''
137         self.add_geometry(len(verts), len(edges), len(faces))
138         
139         verts_flat = [f for v in verts for f in v]
140         self.verts.foreach_set("co", verts_flat)
141         del verts_flat
142         
143         edges_flat = [i for e in edges for i in e]
144         self.edges.foreach_set("verts", edges_flat)
145         del edges_flat
146         
147         def treat_face(f):
148             if len(f) == 3:
149                 return f[0], f[1], f[2], 0
150             elif f[3] == 0:
151                 return f[3], f[0], f[1], f[2]
152             return f
153         
154         faces_flat = [v for f in faces for v in treat_face(f)]
155         self.faces.foreach_set("verts_raw", faces_flat)
156         del faces_flat
157
158     @property
159     def edge_keys(self):
160         return [edge_key for face in self.faces for edge_key in face.edge_keys]
161
162     @property
163     def edge_face_count_dict(self):
164         face_edge_keys = [face.edge_keys for face in self.faces]
165         face_edge_count = {}
166         for face_keys in face_edge_keys:
167             for key in face_keys:
168                 try:
169                     face_edge_count[key] += 1
170                 except:
171                     face_edge_count[key] = 1
172
173         return face_edge_count
174
175     @property
176     def edge_face_count(self):
177         edge_face_count_dict = self.edge_face_count_dict
178         return [edge_face_count_dict.get(ed.key, 0) for ed in mesh.edges]
179
180
181 class MeshEdge(StructRNA):
182
183     @property
184     def key(self):
185         return ord_ind(*tuple(self.verts))
186
187
188 class MeshFace(StructRNA):
189
190     @property
191     def edge_keys(self):
192         verts = tuple(self.verts)
193         if len(verts)==3:
194             return ord_ind(verts[0], verts[1]),  ord_ind(verts[1], verts[2]),  ord_ind(verts[2], verts[0])
195
196         return ord_ind(verts[0], verts[1]),  ord_ind(verts[1], verts[2]),  ord_ind(verts[2], verts[3]),  ord_ind(verts[3], verts[0])
197
198
199 import collections
200 class OrderedMeta(type):
201     def __init__(cls, name, bases, attributes):
202         super(OrderedMeta, cls).__init__(name, bases, attributes)
203         cls.order = list(attributes.keys())
204     def __prepare__(name, bases, **kwargs):
205         return collections.OrderedDict()
206
207
208 # Only defined so operators members can be used by accessing self.order
209 class Operator(StructRNA, metaclass=OrderedMeta):
210     pass
211
212
213 class Menu(StructRNA):
214     
215     def path_menu(self, searchpaths, operator):
216         layout = self.layout
217         # hard coded to set the operators 'path' to the filename.
218         
219         import os
220
221         def path_to_name(f):
222             ''' Only capitalize all lowercase names, mixed case use them as is.
223             '''
224             f_base = os.path.splitext(f)[0]
225             
226             # string replacements
227             f_base = f_base.replace("_colon_", ":")
228             
229             f_base = f_base.replace("_", " ")
230             
231             if f_base.lower() == f_base:
232                 return ' '.join([w[0].upper() + w[1:] for w in f_base.split()])
233             else:
234                 return f_base
235
236         layout = self.layout
237
238         # collect paths
239         files = []
240         for path in searchpaths:
241             files.extend([(f, os.path.join(path, f)) for f in os.listdir(path)])
242
243         files.sort()
244
245         for f, path in files:
246
247             if f.startswith("."):
248                 continue
249
250             layout.operator(operator, text=path_to_name(f)).path = path
251     
252     def draw_preset(self, context):
253         '''Define these on the subclass
254          - preset_operator
255          - preset_subdir
256         '''
257         import bpy
258         self.path_menu(bpy.utils.preset_paths(self.preset_subdir), self.preset_operator)