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