627d9c4349f6237d54e2ae1dc9a83acaf0fb2da7
[blender.git] / release / scripts / startup / bl_ui / properties_data_gpencil.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 import bpy
21 from bpy.types import Menu, Panel, UIList
22 from rna_prop_ui import PropertyPanel
23 from .properties_grease_pencil_common import (
24     GreasePencilOnionPanel,
25     GPENCIL_UL_layer,
26 )
27
28 ###############################
29 # Base-Classes (for shared stuff - e.g. poll, attributes, etc.)
30
31
32 class DataButtonsPanel:
33     bl_space_type = 'PROPERTIES'
34     bl_region_type = 'WINDOW'
35     bl_context = "data"
36
37     @classmethod
38     def poll(cls, context):
39         return context.object and context.object.type == 'GPENCIL'
40
41
42 class LayerDataButtonsPanel:
43     bl_space_type = 'PROPERTIES'
44     bl_region_type = 'WINDOW'
45     bl_context = "data"
46
47     @classmethod
48     def poll(cls, context):
49         return (context.object and
50                 context.object.type == 'GPENCIL' and
51                 context.active_gpencil_layer)
52
53
54 ###############################
55 # GP Object Properties Panels and Helper Classes
56
57 class DATA_PT_gpencil(DataButtonsPanel, Panel):
58     bl_label = ""
59     bl_options = {'HIDE_HEADER'}
60
61     def draw(self, context):
62         layout = self.layout
63
64         # Grease Pencil data selector
65         gpd_owner = context.gpencil_data_owner
66
67         layout.template_ID(gpd_owner, "data")
68
69
70 class GPENCIL_MT_layer_specials(Menu):
71     bl_label = "Layer"
72
73     def draw(self, context):
74         layout = self.layout
75
76         layout.operator("gpencil.layer_duplicate", icon='ADD')  # XXX: needs a dedicated icon
77
78         layout.separator()
79
80         layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
81         layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
82
83         layout.separator()
84
85         layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
86         layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
87
88         layout.separator()
89
90         layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down")
91
92         layout.separator()
93         layout.menu("VIEW3D_MT_gpencil_copy_layer")
94
95
96 class DATA_PT_gpencil_datapanel(Panel):
97     bl_space_type = 'PROPERTIES'
98     bl_region_type = 'WINDOW'
99     bl_context = "data"
100     bl_label = "Layers"
101
102     @classmethod
103     def poll(cls, context):
104         if context.gpencil_data is None:
105             return False
106
107         ob = context.object
108         if ob is not None and ob.type == 'GPENCIL':
109             return True
110
111         return False
112
113     @staticmethod
114     def draw(self, context):
115         layout = self.layout
116         #layout.use_property_split = True
117         layout.use_property_decorate = False
118
119         gpd = context.gpencil_data
120
121         # Grease Pencil data...
122         if (gpd is None) or (not gpd.layers):
123             layout.operator("gpencil.layer_add", text="New Layer")
124         else:
125             self.draw_layers(context, layout, gpd)
126
127     def draw_layers(self, context, layout, gpd):
128         row = layout.row()
129
130         col = row.column()
131         layer_rows = 7
132         col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows)
133
134         col = row.column()
135
136         sub = col.column(align=True)
137         sub.operator("gpencil.layer_add", icon='ADD', text="")
138         sub.operator("gpencil.layer_remove", icon='REMOVE', text="")
139
140         gpl = context.active_gpencil_layer
141         if gpl:
142             sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="")
143
144             if len(gpd.layers) > 1:
145                 col.separator()
146
147                 sub = col.column(align=True)
148                 sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
149                 sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
150
151                 col.separator()
152
153                 sub = col.column(align=True)
154                 sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
155                 sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
156
157         row = layout.row(align=True)
158         if gpl:
159             row.prop(gpl, "opacity", text="Opacity", slider=True)
160
161
162 class DATA_PT_gpencil_layer_optionpanel(LayerDataButtonsPanel, Panel):
163     bl_space_type = 'PROPERTIES'
164     bl_region_type = 'WINDOW'
165     bl_context = "data"
166     bl_label = "Adjustments"
167     bl_parent_id = 'DATA_PT_gpencil_datapanel'
168     bl_options = {'DEFAULT_CLOSED'}
169
170     def draw(self, context):
171         layout = self.layout
172         layout.use_property_split = True
173
174         gpl = context.active_gpencil_layer
175         layout.active = not gpl.lock
176
177         # Layer options
178         # Offsets - Color Tint
179         layout.enabled = not gpl.lock
180         col = layout.column(align=True)
181         col.prop(gpl, "tint_color")
182         col.prop(gpl, "tint_factor", text="Factor", slider=True)
183
184         # Offsets - Thickness
185         col = layout.row(align=True)
186         col.prop(gpl, "line_change", text="Stroke Thickness")
187
188         col = layout.row(align=True)
189         col.prop(gpl, "lock_material")
190
191
192 class DATA_PT_gpencil_parentpanel(LayerDataButtonsPanel, Panel):
193     bl_space_type = 'PROPERTIES'
194     bl_region_type = 'WINDOW'
195     bl_context = "data"
196     bl_label = "Relations"
197     bl_parent_id = 'DATA_PT_gpencil_datapanel'
198     bl_options = {'DEFAULT_CLOSED'}
199
200     def draw(self, context):
201         layout = self.layout
202         layout.use_property_split = True
203         layout.use_property_decorate = False
204
205         gpl = context.active_gpencil_layer
206         col = layout.column()
207         col.active = not gpl.lock
208         col.prop(gpl, "parent")
209         col.prop(gpl, "parent_type", text="Type")
210         parent = gpl.parent
211
212         if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
213             col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone")
214
215
216 class DATA_PT_gpencil_onionpanel(Panel):
217     bl_space_type = 'PROPERTIES'
218     bl_region_type = 'WINDOW'
219     bl_context = "data"
220     bl_label = "Onion Skinning"
221     bl_options = {'DEFAULT_CLOSED'}
222
223     @classmethod
224     def poll(cls, context):
225         return bool(context.active_gpencil_layer)
226
227     @staticmethod
228     def draw_header(self, context):
229         self.layout.prop(context.gpencil_data, "use_onion_skinning", text="")
230
231     def draw(self, context):
232         gpd = context.gpencil_data
233
234         layout = self.layout
235         layout.use_property_split = True
236         layout.enabled = gpd.use_onion_skinning and gpd.users <= 1
237
238         if gpd.use_onion_skinning and gpd.users > 1:
239             layout.label(text="Multiuser datablock not supported", icon='ERROR')
240
241         GreasePencilOnionPanel.draw_settings(layout, gpd)
242
243
244 class GPENCIL_MT_gpencil_vertex_group(Menu):
245     bl_label = "GP Vertex Groups"
246
247     def draw(self, context):
248         layout = self.layout
249
250         layout.operator_context = 'EXEC_AREA'
251         layout.operator("object.vertex_group_add")
252
253         ob = context.active_object
254         if ob.vertex_groups.active:
255             layout.separator()
256
257             layout.operator("gpencil.vertex_group_assign", text="Assign to Active Group")
258             layout.operator("gpencil.vertex_group_remove_from", text="Remove from Active Group")
259
260             layout.separator()
261             layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group")
262             layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False
263             layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True
264
265             layout.separator()
266             layout.operator("gpencil.vertex_group_select", text="Select Points")
267             layout.operator("gpencil.vertex_group_deselect", text="Deselect Points")
268
269
270 class GPENCIL_UL_vgroups(UIList):
271     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
272         vgroup = item
273         if self.layout_type in {'DEFAULT', 'COMPACT'}:
274             layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon)
275             # icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
276             # layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
277         elif self.layout_type == 'GRID':
278             layout.alignment = 'CENTER'
279             layout.label(text="", icon_value=icon)
280
281
282 class DATA_PT_gpencil_vertexpanel(DataButtonsPanel, Panel):
283     bl_space_type = 'PROPERTIES'
284     bl_region_type = 'WINDOW'
285     bl_context = "data"
286     bl_label = "Vertex Groups"
287     bl_options = {'DEFAULT_CLOSED'}
288
289     def draw(self, context):
290         layout = self.layout
291
292         ob = context.object
293         group = ob.vertex_groups.active
294
295         rows = 2
296         if group:
297             rows = 4
298
299         row = layout.row()
300         row.template_list("GPENCIL_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows)
301
302         col = row.column(align=True)
303         col.operator("object.vertex_group_add", icon='ADD', text="")
304         col.operator("object.vertex_group_remove", icon='REMOVE', text="").all = False
305
306         if ob.vertex_groups:
307             row = layout.row()
308
309             sub = row.row(align=True)
310             sub.operator("gpencil.vertex_group_assign", text="Assign")
311             sub.operator("gpencil.vertex_group_remove_from", text="Remove")
312
313             sub = row.row(align=True)
314             sub.operator("gpencil.vertex_group_select", text="Select")
315             sub.operator("gpencil.vertex_group_deselect", text="Deselect")
316
317             layout.prop(context.tool_settings, "vertex_group_weight", text="Weight")
318
319
320 class DATA_PT_gpencil_display(DataButtonsPanel, Panel):
321     bl_label = "Viewport Display"
322     bl_options = {'DEFAULT_CLOSED'}
323
324     def draw(self, context):
325         layout = self.layout
326         layout.use_property_split = True
327         layout.use_property_decorate = False
328
329         ob = context.object
330
331         gpd = context.gpencil_data
332         gpl = context.active_gpencil_layer
333
334         layout.prop(gpd, "xray_mode", text="Depth Ordering")
335         layout.prop(ob, "empty_display_size", text="Marker Size")
336
337         col = layout.column(align=True)
338         col.prop(gpd, "show_constant_thickness")
339         sub = col.column()
340         sub.active = not gpd.show_constant_thickness
341         sub.prop(gpd, "pixel_factor", text="Thickness Scale")
342
343         layout.prop(gpd, "edit_line_color", text="Edit Line Color")
344         if gpl:
345             layout.prop(gpd, "show_stroke_direction", text="Show Stroke Directions")
346
347         layout.prop(gpd, "use_force_fill_recalc", text="Force Fill Update")
348         layout.prop(gpd, "use_adaptative_uv", text="Adaptative UVs")
349         layout.prop(gpd, "zdepth_offset", text="Surface Offset")
350
351
352 class DATA_PT_gpencil_canvas(DataButtonsPanel, Panel):
353     bl_label = "Canvas"
354     bl_parent_id = 'DATA_PT_gpencil_display'
355     bl_options = {'DEFAULT_CLOSED'}
356
357     def draw(self, context):
358         layout = self.layout
359         layout.use_property_split = True
360         layout.use_property_decorate = False
361         gpd = context.gpencil_data
362         grid = gpd.grid
363
364         row = layout.row(align=True)
365         col = row.column()
366         col.prop(grid, "color")
367         col.prop(grid, "scale")
368         row = layout.row(align=True)
369         col = row.column()
370         col.prop(grid, "lines", text="Subdivisions")
371         col.prop(grid, "axis", text="Plane")
372
373
374 class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel):
375     _context_path = "object.data"
376     _property_type = bpy.types.GreasePencil
377
378 ###############################
379
380
381 classes = (
382     DATA_PT_gpencil,
383     DATA_PT_gpencil_datapanel,
384     DATA_PT_gpencil_onionpanel,
385     DATA_PT_gpencil_layer_optionpanel,
386     DATA_PT_gpencil_parentpanel,
387     DATA_PT_gpencil_vertexpanel,
388     DATA_PT_gpencil_display,
389     DATA_PT_gpencil_canvas,
390     DATA_PT_custom_props_gpencil,
391
392     GPENCIL_UL_vgroups,
393
394     GPENCIL_MT_layer_specials,
395     GPENCIL_MT_gpencil_vertex_group,
396 )
397
398 if __name__ == "__main__":  # only for live edit.
399     from bpy.utils import register_class
400     for cls in classes:
401         register_class(cls)