load objects before linking materials (minor change)
[blender-addons.git] / system_property_chart.py
blob4ed289055bdb2bd8fea5f6de38e054dbb955f0fb
1 # ##### BEGIN GPL LICENSE BLOCK #####
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # <pep8 compliant>
21 bl_info = {
22 "name": "Property Chart",
23 "author": "Campbell Barton (ideasman42)",
24 "version": (0, 1),
25 "blender": (2, 57, 0),
26 "location": "Tool Shelf",
27 "description": ("Edit arbitrary selected properties for "
28 "objects/sequence strips of the same type"),
29 "warning": "",
30 "wiki_url": ("http://wiki.blender.org/index.php/Extensions:2.6/Py/"
31 "Scripts/System/Object Property Chart"),
32 "tracker_url": ("https://projects.blender.org/tracker/index.php?"
33 "func=detail&aid=22701"),
34 "category": "System"}
36 """List properties of selected objects"""
38 import bpy
39 from bl_operators.presets import AddPresetBase
42 class AddPresetProperties(AddPresetBase, bpy.types.Operator):
43 """Add an properties preset"""
44 bl_idname = "scene.properties_preset_add"
45 bl_label = "Add Properties Preset"
46 preset_menu = "SCENE_MT_properties_presets"
48 preset_defines = [
49 "scene = bpy.context.scene",
52 def pre_cb(self, context):
53 space_type = context.space_data.type
54 if space_type == 'VIEW_3D':
55 self.preset_subdir = "system_property_chart_view3d"
56 self.preset_values = ["scene.view3d_edit_props"]
57 else:
58 self.preset_subdir = "system_property_chart_sequencer"
59 self.preset_values = ["scene.sequencer_edit_props"]
62 class SCENE_MT_properties_presets(bpy.types.Menu):
63 bl_label = "Properties Presets"
64 preset_operator = "script.execute_preset"
66 def draw(self, context):
67 space_type = context.space_data.type
69 if space_type == 'VIEW_3D':
70 self.preset_subdir = "system_property_chart_view3d"
71 else:
72 self.preset_subdir = "system_property_chart_sequencer"
74 bpy.types.Menu.draw_preset(self, context)
77 def _property_chart_data_get(self, context):
78 # eg. context.active_object
79 obj = eval("context.%s" % self.context_data_path_active)
81 if obj is None:
82 return None, None
84 # eg. context.selected_objects[:]
85 selected_objects = eval("context.%s" % self.context_data_path_selected)[:]
87 if not selected_objects:
88 return None, None
90 return obj, selected_objects
93 def _property_chart_draw(self, context):
94 """
95 This function can run for different types.
96 """
97 obj, selected_objects = _property_chart_data_get(self, context)
99 if not obj:
100 return
102 # active first
103 try:
104 active_index = selected_objects.index(obj)
105 except ValueError:
106 active_index = -1
108 if active_index > 0: # not the first already
109 selected_objects[0], selected_objects[active_index] = selected_objects[active_index], selected_objects[0]
111 id_storage = context.scene
113 strings = getattr(id_storage, self._PROP_STORAGE_ID)
115 # Collected all props, now display them all
116 layout = self.layout
118 if strings:
120 def obj_prop_get(obj, attr_string):
121 """return a pair (rna_base, "rna_property") to give to the rna UI property function"""
122 attrs = attr_string.split(".")
123 val_new = obj
124 for i, attr in enumerate(attrs):
125 val_old = val_new
126 val_new = getattr(val_old, attr, Ellipsis)
128 if val_new == Ellipsis:
129 return None, None
130 return val_old, attrs[-1]
132 strings = strings.split()
134 prop_all = []
136 for obj in selected_objects:
137 prop_pairs = []
138 prop_found = False
139 for attr_string in strings:
140 prop_pairs.append(obj_prop_get(obj, attr_string))
141 if prop_found is False and prop_pairs[-1] != (None, None):
142 prop_found = True
144 if prop_found:
145 prop_all.append((obj, prop_pairs))
147 row = layout.row(align=True)
149 col = row.column()
150 col.label(text="name")
151 for obj, prop_pairs in prop_all:
152 col.prop(obj, "name", text="")
154 for i in range(len(strings)):
155 col = row.column()
157 # name and copy button
158 rowsub = col.row(align=False)
159 rowsub.label(text=strings[i].rsplit(".", 1)[-1])
160 props = rowsub.operator("wm.chart_copy", text="", icon='PASTEDOWN', emboss=False)
161 props.data_path_active = self.context_data_path_active
162 props.data_path_selected = self.context_data_path_selected
163 props.data_path = strings[i]
165 for obj, prop_pairs in prop_all:
166 data, attr = prop_pairs[i]
167 if data:
168 col.prop(data, attr, text="") # , emboss=obj==active_object
169 else:
170 col.label(text="<missing>")
172 # Presets for properties
173 col = layout.column()
174 col.label(text="Properties")
175 row = col.row(align=True)
176 row.menu("SCENE_MT_properties_presets", text=bpy.types.SCENE_MT_properties_presets.bl_label)
177 row.operator("scene.properties_preset_add", text="", icon="ZOOMIN")
178 row.operator("scene.properties_preset_add", text="", icon="ZOOMOUT").remove_active = True
179 # edit the display props
180 col.prop(id_storage, self._PROP_STORAGE_ID, text="")
183 class View3DEditProps(bpy.types.Panel):
184 bl_space_type = 'VIEW_3D'
185 bl_region_type = 'UI'
187 bl_label = "Property Chart"
188 bl_context = "objectmode"
190 _PROP_STORAGE_ID = "view3d_edit_props"
191 _PROP_STORAGE_DEFAULT = "data data.name"
193 # _property_chart_draw needs these
194 context_data_path_active = "active_object"
195 context_data_path_selected = "selected_objects"
197 draw = _property_chart_draw
200 class SequencerEditProps(bpy.types.Panel):
201 bl_space_type = 'SEQUENCE_EDITOR'
202 bl_region_type = 'UI'
204 bl_label = "Property Chart"
206 _PROP_STORAGE_ID = "sequencer_edit_props"
207 _PROP_STORAGE_DEFAULT = "blend_type blend_alpha"
209 # _property_chart_draw needs these
210 context_data_path_active = "scene.sequence_editor.active_strip"
211 context_data_path_selected = "selected_sequences"
213 draw = _property_chart_draw
215 @classmethod
216 def poll(cls, context):
217 return context.scene.sequence_editor is not None
219 # Operator to copy properties
222 def _property_chart_copy(self, context):
223 obj, selected_objects = _property_chart_data_get(self, context)
225 if not obj:
226 return
228 data_path = self.data_path
230 # quick & nasty method!
231 for obj_iter in selected_objects:
232 if obj != obj_iter:
233 try:
234 exec("obj_iter.%s = obj.%s" % (data_path, data_path))
235 except:
236 # just in case we need to know what went wrong!
237 import traceback
238 traceback.print_exc()
240 from bpy.props import StringProperty
243 class CopyPropertyChart(bpy.types.Operator):
244 "Open a path in a file browser"
245 bl_idname = "wm.chart_copy"
246 bl_label = "Copy properties from active to selected"
248 data_path_active = StringProperty()
249 data_path_selected = StringProperty()
250 data_path = StringProperty()
252 def execute(self, context):
253 # so attributes are found for '_property_chart_data_get()'
254 self.context_data_path_active = self.data_path_active
255 self.context_data_path_selected = self.data_path_selected
257 _property_chart_copy(self, context)
259 return {'FINISHED'}
262 def register():
263 bpy.utils.register_module(__name__)
265 Scene = bpy.types.Scene
267 for cls in View3DEditProps, SequencerEditProps:
268 setattr(Scene,
269 cls._PROP_STORAGE_ID,
270 StringProperty(
271 name="Scene Name",
272 description="Name of POV-Ray scene to create. Empty " \
273 "name will use the name of the blend file",
274 default=cls._PROP_STORAGE_DEFAULT, maxlen=1024),
278 def unregister():
279 bpy.utils.unregister_module(__name__)
281 Scene = bpy.types.Scene
283 for cls in View3DEditProps, SequencerEditProps:
284 delattr(Scene,
285 cls._PROP_STORAGE_ID,
289 if __name__ == "__main__":
290 register()