e9c96d59eaedd6bcec3223785ae0d82bc2c66694
[blender.git] / release / scripts / modules / rna_prop_ui.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 import bpy
22
23
24 def rna_idprop_ui_get(item, create=True):
25     try:
26         return item['_RNA_UI']
27     except:
28         if create:
29             item['_RNA_UI'] = {}
30             return item['_RNA_UI']
31         else:
32             return None
33
34
35 def rna_idprop_ui_prop_get(item, prop, create=True):
36
37     rna_ui = rna_idprop_ui_get(item, create)
38
39     if rna_ui is None:
40         return None
41
42     try:
43         return rna_ui[prop]
44     except:
45         rna_ui[prop] = {}
46         return rna_ui[prop]
47
48
49 def rna_idprop_ui_prop_clear(item, prop):
50     rna_ui = rna_idprop_ui_get(item, False)
51
52     if rna_ui is None:
53         return
54
55     try:
56         del rna_ui[prop]
57     except:
58         pass
59
60 def rna_idprop_context_value(context, context_member, property_type):
61     space = context.space_data
62
63     if space is None or isinstance(space, bpy.types.SpaceProperties):
64         pin_id = space.pin_id
65     else:
66         pin_id = None
67
68     if pin_id and isinstance(pin_id, property_type):
69         rna_item = pin_id
70         context_member = "space_data.pin_id"
71     else:
72         rna_item = eval("context." + context_member)
73
74     return rna_item, context_member
75
76 def rna_idprop_has_properties(rna_item):
77     keys = rna_item.keys()
78     nbr_props = len(keys)
79     return (nbr_props > 1) or (nbr_props and '_RNA_UI' not in keys)
80
81 def draw(layout, context, context_member, property_type, use_edit=True):
82
83     def assign_props(prop, val, key):
84         prop.data_path = context_member
85         prop.property = key
86
87         try:
88             prop.value = str(val)
89         except:
90             pass
91
92     rna_item, context_member = rna_idprop_context_value(context, context_member, property_type)
93
94     # poll should really get this...
95     if not rna_item:
96         return
97
98     from bpy.utils import escape_identifier
99
100     if rna_item.id_data.library is not None:
101         use_edit = False
102
103     assert(isinstance(rna_item, property_type))
104
105     items = rna_item.items()
106     items.sort()
107
108     if use_edit:
109         row = layout.row()
110         props = row.operator("wm.properties_add", text="Add")
111         props.data_path = context_member
112         del row
113
114     rna_properties = {prop.identifier for prop in rna_item.bl_rna.properties if prop.is_runtime} if items else None
115
116     for key, val in items:
117
118         if key == '_RNA_UI':
119             continue
120
121         row = layout.row()
122         to_dict = getattr(val, "to_dict", None)
123         to_list = getattr(val, "to_list", None)
124
125         # val_orig = val  # UNUSED
126         if to_dict:
127             val = to_dict()
128             val_draw = str(val)
129         elif to_list:
130             val = to_list()
131             val_draw = str(val)
132         else:
133             val_draw = val
134
135         box = row.box()
136
137         if use_edit:
138             split = box.split(percentage=0.75)
139             row = split.row()
140         else:
141             row = box.row()
142
143         row.label(text=key, translate=False)
144
145         # explicit exception for arrays
146         is_rna = (key in rna_properties)
147
148         if to_dict or to_list:
149             row.label(text=val_draw, translate=False)
150         else:
151             if is_rna:
152                 row.prop(rna_item, key, text="")
153             else:
154                 row.prop(rna_item, '["%s"]' % escape_identifier(key), text="")
155
156         if use_edit:
157             row = split.row(align=True)
158             if not is_rna:
159                 props = row.operator("wm.properties_edit", text="Edit")
160                 assign_props(props, val_draw, key)
161             else:
162                 row.label(text="API Defined")
163
164             props = row.operator("wm.properties_remove", text="", icon='ZOOMOUT')
165             assign_props(props, val_draw, key)
166
167
168 class PropertyPanel():
169     """
170     The subclass should have its own poll function
171     and the variable '_context_path' MUST be set.
172     """
173     bl_label = "Custom Properties"
174     bl_options = {'DEFAULT_CLOSED'}
175
176     @classmethod
177     def poll(cls, context):
178         rna_item, context_member = rna_idprop_context_value(context, cls._context_path, cls._property_type)
179         return bool(rna_item)
180
181     """
182     def draw_header(self, context):
183         rna_item, context_member = rna_idprop_context_value(context, self._context_path, self._property_type)
184         tot = len(rna_item.keys())
185         if tot:
186             self.layout().label("%d:" % tot)
187     """
188
189     def draw(self, context):
190         draw(self.layout, context, self._context_path, self._property_type)