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 #####
22 "name": "Property Chart",
23 "author": "Campbell Barton (ideasman42)",
25 "blender": (2, 57, 0),
26 "location": "Tool Shelf",
27 "description": ("Edit arbitrary selected properties for "
28 "objects/sequence strips of the same type"),
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"),
36 """List properties of selected objects"""
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"
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"]
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"
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
)
84 # eg. context.selected_objects[:]
85 selected_objects
= eval("context.%s" % self
.context_data_path_selected
)[:]
87 if not selected_objects
:
90 return obj
, selected_objects
93 def _property_chart_draw(self
, context
):
95 This function can run for different types.
97 obj
, selected_objects
= _property_chart_data_get(self
, context
)
104 active_index
= selected_objects
.index(obj
)
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
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(".")
124 for i
, attr
in enumerate(attrs
):
126 val_new
= getattr(val_old
, attr
, Ellipsis)
128 if val_new
== Ellipsis:
130 return val_old
, attrs
[-1]
132 strings
= strings
.split()
136 for obj
in selected_objects
:
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):
145 prop_all
.append((obj
, prop_pairs
))
147 row
= layout
.row(align
=True)
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
)):
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
]
168 col
.prop(data
, attr
, text
="") # , emboss=obj==active_object
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
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
)
228 data_path
= self
.data_path
230 # quick & nasty method!
231 for obj_iter
in selected_objects
:
234 exec("obj_iter.%s = obj.%s" % (data_path
, data_path
))
236 # just in case we need to know what went wrong!
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
)
263 bpy
.utils
.register_module(__name__
)
265 Scene
= bpy
.types
.Scene
267 for cls
in View3DEditProps
, SequencerEditProps
:
269 cls
._PROP
_STORAGE
_ID
,
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),
279 bpy
.utils
.unregister_module(__name__
)
281 Scene
= bpy
.types
.Scene
283 for cls
in View3DEditProps
, SequencerEditProps
:
285 cls
._PROP
_STORAGE
_ID
,
289 if __name__
== "__main__":