Bugfix T42774: BSurface addon doesn't work on new builds
[blender.git] / release / scripts / startup / bl_ui / properties_grease_pencil_common.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
22 import bpy
23 from bpy.types import Menu, UIList
24
25
26 def gpencil_stroke_placement_settings(context, layout, gpd):
27     col = layout.column(align=True)
28
29     col.label(text="Stroke Placement:")
30
31     row = col.row(align=True)
32     row.prop_enum(gpd, "draw_mode", 'VIEW')
33     row.prop_enum(gpd, "draw_mode", 'CURSOR')
34
35     if context.space_data.type == 'VIEW_3D':
36         row = col.row(align=True)
37         row.prop_enum(gpd, "draw_mode", 'SURFACE')
38         row.prop_enum(gpd, "draw_mode", 'STROKE')
39
40         row = col.row(align=False)
41         row.active = gpd.draw_mode in ('SURFACE', 'STROKE')
42         row.prop(gpd, "use_stroke_endpoints")
43
44
45 class GreasePencilDrawingToolsPanel():
46     # subclass must set
47     # bl_space_type = 'IMAGE_EDITOR'
48     bl_label = "Grease Pencil"
49     bl_category = "Grease Pencil"
50     bl_region_type = 'TOOLS'
51
52     @staticmethod
53     def draw(self, context):
54         layout = self.layout
55
56         col = layout.column(align=True)
57
58         col.label(text="Draw:")
59         row = col.row(align=True)
60         row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
61         row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
62
63         row = col.row(align=True)
64         row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
65         row.operator("gpencil.draw", text="Poly").mode = 'DRAW_POLY'
66
67
68         row = col.row(align=True)
69         row.prop(context.tool_settings, "use_grease_pencil_sessions", text="Continuous Drawing")
70
71                 
72         if context.space_data.type in ('VIEW_3D', 'CLIP_EDITOR'):
73             col.separator()
74             col.label("Data Source:")
75             row = col.row(align=True)
76             if context.space_data.type == 'VIEW_3D':
77                 row.prop(context.tool_settings, "grease_pencil_source", expand=True)
78             elif context.space_data.type == 'CLIP_EDITOR':
79                 row.prop(context.space_data, "grease_pencil_source", expand=True)
80
81
82         gpd = context.gpencil_data
83         if gpd:
84             col.separator()
85             gpencil_stroke_placement_settings(context, col, gpd)
86
87
88         if context.space_data.type == 'VIEW_3D':
89             col.separator()
90             col.separator()
91
92             col.label(text="Tools:")
93             col.operator("gpencil.convert", text="Convert...")
94             col.operator("view3d.ruler")
95
96
97 class GreasePencilStrokeEditPanel():
98     # subclass must set
99     # bl_space_type = 'IMAGE_EDITOR'
100     bl_label = "Edit Strokes"
101     bl_category = "Grease Pencil"
102     bl_region_type = 'TOOLS'
103
104     @classmethod
105     def poll(cls, context):
106         return (context.gpencil_data is not None)
107
108     @staticmethod
109     def draw(self, context):
110         layout = self.layout
111
112         gpd = context.gpencil_data
113         edit_ok = bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
114
115         col = layout.column(align=True)
116         col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
117
118         col.separator()
119
120         col.label(text="Select:")
121         subcol = col.column(align=True)
122         subcol.active = edit_ok
123         subcol.operator("gpencil.select_all", text="Select All")
124         subcol.operator("gpencil.select_border")
125         subcol.operator("gpencil.select_circle")
126
127         col.separator()
128
129         subcol = col.column(align=True)
130         subcol.active = edit_ok
131         subcol.operator("gpencil.select_linked")
132         subcol.operator("gpencil.select_more")
133         subcol.operator("gpencil.select_less")
134
135         col.separator()
136
137         col.label(text="Edit:")
138         subcol = col.column(align=True)
139         subcol.active = edit_ok
140         subcol.operator("gpencil.delete", text="Delete")
141         subcol.operator("gpencil.duplicate_move", text="Duplicate")
142         subcol.operator("transform.mirror", text="Mirror").gpencil_strokes = True
143
144         col.separator()
145
146         subcol = col.column(align=True)
147         subcol.active = edit_ok
148         subcol.operator("transform.translate").gpencil_strokes = True   # icon='MAN_TRANS'
149         subcol.operator("transform.rotate").gpencil_strokes = True      # icon='MAN_ROT'
150         subcol.operator("transform.resize", text="Scale").gpencil_strokes = True      # icon='MAN_SCALE'
151
152         col.separator()
153
154         subcol = col.column(align=True)
155         subcol.active = edit_ok
156         subcol.operator("transform.bend", text="Bend").gpencil_strokes = True
157         subcol.operator("transform.shear", text="Shear").gpencil_strokes = True
158         subcol.operator("transform.tosphere", text="To Sphere").gpencil_strokes = True
159
160
161 ###############################
162
163 class GPENCIL_PIE_tool_palette(Menu):
164     """A pie menu for quick access to Grease Pencil tools"""
165     bl_label = "Grease Pencil Tools"
166
167     def draw(self, context):
168         layout = self.layout
169
170         pie = layout.menu_pie()
171         gpd = context.gpencil_data
172
173         # W - Drawing Types
174         col = pie.column()
175         col.operator("gpencil.draw", text="Draw", icon='GREASEPENCIL').mode = 'DRAW'
176         col.operator("gpencil.draw", text="Straight Lines", icon='LINE_DATA').mode = 'DRAW_STRAIGHT'
177         col.operator("gpencil.draw", text="Poly", icon='MESH_DATA').mode = 'DRAW_POLY'
178
179         # E - Eraser
180         # XXX: needs a dedicated icon...
181         col = pie.column()
182         col.operator("gpencil.draw", text="Eraser", icon='FORCE_CURVE').mode = 'ERASER'
183
184         # E - "Settings" Palette is included here too, since it needs to be in a stable position...
185         if gpd and gpd.layers.active:
186             col.separator()
187             col.operator("wm.call_menu_pie", text="Settings...", icon='SCRIPTWIN').name = "GPENCIL_PIE_settings_palette"
188
189         # Editing tools
190         if gpd:
191             if gpd.use_stroke_edit_mode and context.editable_gpencil_strokes:
192                 # S - Exit Edit Mode
193                 pie.prop(gpd, "use_stroke_edit_mode", text="Exit Edit Mode", icon='EDIT')
194
195                 # N - Transforms
196                 col = pie.column()
197                 row = col.row(align=True)
198                 row.operator("transform.translate", icon='MAN_TRANS').gpencil_strokes = True
199                 row.operator("transform.rotate",    icon='MAN_ROT').gpencil_strokes = True
200                 row.operator("transform.resize",    text="Scale", icon='MAN_SCALE').gpencil_strokes = True
201                 row = col.row(align=True)
202                 row.label("Proportional Edit:")
203                 row.prop(context.tool_settings, "proportional_edit", text="", icon_only=True)
204                 row.prop(context.tool_settings, "proportional_edit_falloff", text="", icon_only=True)
205
206                 # NW - Select (Non-Modal)
207                 col = pie.column()
208                 col.operator("gpencil.select_all", text="Select All", icon='PARTICLE_POINT')
209                 col.operator("gpencil.select_all", text="Select Inverse", icon='BLANK1')
210                 col.operator("gpencil.select_linked", text="Select Linked", icon='LINKED')
211
212                 # NE - Select (Modal)
213                 col = pie.column()
214                 col.operator("gpencil.select_border", text="Border Select", icon='BORDER_RECT')
215                 col.operator("gpencil.select_circle", text="Circle Select", icon='META_EMPTY')
216                 col.operator("gpencil.select_lasso", text="Lasso Select", icon='BORDER_LASSO')
217
218                 # SW - Edit Tools
219                 col = pie.column()
220                 col.operator("gpencil.duplicate_move", icon='PARTICLE_PATH', text="Duplicate")
221                 col.operator("gpencil.delete", icon='X', text="Delete...")
222
223                 # SE - More Tools
224                 pie.operator("wm.call_menu_pie", text="More...").name = "GPENCIL_PIE_tools_more"
225             else:
226                 # Toggle Edit Mode
227                 pie.prop(gpd, "use_stroke_edit_mode", text="Enable Stroke Editing", icon='EDIT')
228
229
230 class GPENCIL_PIE_settings_palette(Menu):
231     """A pie menu for quick access to Grease Pencil settings"""
232     bl_label = "Grease Pencil Settings"
233
234     @classmethod
235     def poll(cls, context):
236         return bool(context.gpencil_data and context.active_gpencil_layer)
237
238     def draw(self, context):
239         layout = self.layout
240
241         pie = layout.menu_pie()
242         gpd = context.gpencil_data
243         gpl = context.active_gpencil_layer
244
245         # W - Stroke draw settings
246         col = pie.column(align=True)
247         col.label(text="Stroke")
248         col.prop(gpl, "color", text="")
249         col.prop(gpl, "alpha", text="", slider=True)
250
251         # E - Fill draw settings
252         col = pie.column(align=True)
253         col.label(text="Fill")
254         col.prop(gpl, "fill_color", text="")
255         col.prop(gpl, "fill_alpha", text="", slider=True)
256
257         # S - Layer settings
258         col = pie.column()
259         col.prop(gpl, "line_width", slider=True)
260         #col.prop(gpl, "use_volumetric_strokes")
261         col.prop(gpl, "use_onion_skinning")
262
263         # N - Active Layer
264         # XXX: this should show an operator to change the active layer instead
265         col = pie.column()
266         col.label("Active Layer:      ")
267         col.prop(gpl, "info", text="")
268         #col.prop(gpd, "layers")
269         row = col.row()
270         row.prop(gpl, "lock")
271         row.prop(gpl, "hide")
272
273         
274 class GPENCIL_PIE_tools_more(Menu):
275     """A pie menu for accessing more Grease Pencil tools"""
276     bl_label = "More Grease Pencil Tools"
277
278     @classmethod
279     def poll(cls, context):
280         gpd = context.gpencil_data
281         return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
282
283     def draw(self, context):
284         layout = self.layout
285
286         pie = layout.menu_pie()
287         gpd = context.gpencil_data
288         
289         pie.operator("gpencil.select_more", icon='ZOOMIN')
290         pie.operator("gpencil.select_less", icon='ZOOMOUT')
291                 
292         pie.operator("transform.mirror", icon='MOD_MIRROR').gpencil_strokes = True
293         pie.operator("transform.bend", icon='MOD_SIMPLEDEFORM').gpencil_strokes = True
294         pie.operator("transform.shear", icon='MOD_TRIANGULATE').gpencil_strokes = True
295         pie.operator("transform.tosphere", icon='MOD_MULTIRES').gpencil_strokes = True
296                 
297         pie.operator("gpencil.convert", icon='OUTLINER_OB_CURVE')
298         pie.operator("wm.call_menu_pie", text="Back to Main Palette...").name = "GPENCIL_PIE_tool_palette"
299
300 ###############################
301
302 class GPENCIL_UL_layer(UIList):
303     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
304         # assert(isinstance(item, bpy.types.GPencilLayer)
305         gpl = item
306
307         if self.layout_type in {'DEFAULT', 'COMPACT'}:
308             if gpl.lock:
309                 layout.active = False
310
311             split = layout.split(percentage=0.2)
312             split.prop(gpl, "color", text="")
313             split.prop(gpl, "info", text="", emboss=False)
314
315             row = layout.row(align=True)
316             row.prop(gpl, "lock", text="", emboss=False)
317             row.prop(gpl, "hide", text="", emboss=False)
318         elif self.layout_type in {'GRID'}:
319             layout.alignment = 'CENTER'
320             layout.label(text="", icon_value=icon)
321
322
323 class GreasePencilDataPanel():
324     # subclass must set
325     # bl_space_type = 'IMAGE_EDITOR'
326     bl_label = "Grease Pencil"
327     bl_region_type = 'UI'
328
329     @staticmethod
330     def draw_header(self, context):
331         self.layout.prop(context.space_data, "show_grease_pencil", text="")
332
333     @staticmethod
334     def draw(self, context):
335         layout = self.layout
336
337         # owner of Grease Pencil data
338         gpd_owner = context.gpencil_data_owner
339         gpd = context.gpencil_data
340
341         # Owner Selector
342         if context.space_data.type == 'VIEW_3D':
343             layout.prop(context.tool_settings, "grease_pencil_source", expand=True)
344         elif context.space_data.type == 'CLIP_EDITOR':
345             layout.prop(context.space_data, "grease_pencil_source", expand=True)
346
347         # Grease Pencil data selector
348         layout.template_ID(gpd_owner, "grease_pencil", new="gpencil.data_add", unlink="gpencil.data_unlink")
349
350         # Grease Pencil data...
351         if gpd:
352             self.draw_layers(context, layout, gpd)
353
354     def draw_layers(self, context, layout, gpd):
355         row = layout.row()
356
357         col = row.column()
358         col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=5)
359
360         col = row.column()
361
362         sub = col.column(align=True)
363         sub.operator("gpencil.layer_add", icon='ZOOMIN', text="")
364         sub.operator("gpencil.layer_remove", icon='ZOOMOUT', text="")
365
366         gpl = context.active_gpencil_layer
367         if gpl:
368             col.separator()
369
370             sub = col.column(align=True)
371             sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
372             sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
373
374         if gpl:
375             self.draw_layer(layout, gpl)
376
377     def draw_layer(self, layout, gpl):
378         # layer settings
379         split = layout.split(percentage=0.5)
380         split.active = not gpl.lock
381
382         # Column 1 - Stroke
383         col = split.column(align=True)
384         col.label(text="Stroke:")
385         col.prop(gpl, "color", text="")
386         col.prop(gpl, "alpha", slider=True)
387
388         # Column 2 - Fill
389         col = split.column(align=True)
390         col.label(text="Fill:")
391         col.prop(gpl, "fill_color", text="")
392         col.prop(gpl, "fill_alpha", text="Opacity", slider=True)
393
394         # Options
395         split = layout.split(percentage=0.5)
396         split.active = not gpl.lock
397
398         col = split.column(align=True)
399         col.prop(gpl, "line_width", slider=True)
400         col.prop(gpl, "use_volumetric_strokes")
401
402         col = split.column(align=True)
403         col.prop(gpl, "show_x_ray")
404
405         #if debug:
406         #   layout.prop(gpl, "show_points")
407
408         layout.separator()
409
410         # Full-Row - Frame Locking (and Delete Frame)
411         row = layout.row(align=True)
412         row.active = not gpl.lock
413
414         if gpl.active_frame:
415             lock_status = "Locked" if gpl.lock_frame else "Unlocked"
416             lock_label = "Frame: %d (%s)" % (gpl.active_frame.frame_number, lock_status)
417         else:
418             lock_label = "Lock Frame"
419         row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
420         row.operator("gpencil.active_frame_delete", text="", icon='X')
421
422         layout.separator()
423
424         # Onion skinning
425         col = layout.column(align=True)
426         col.active = not gpl.lock
427
428         row = col.row()
429         row.prop(gpl, "use_onion_skinning")
430         row.prop(gpl, "use_ghost_custom_colors", text="", icon='COLOR')
431
432         split = col.split(percentage = 0.5)
433         split.active = gpl.use_onion_skinning
434
435         # - Before Frames
436         sub = split.column(align=True)
437         row = sub.row(align=True)
438         row.active = gpl.use_ghost_custom_colors
439         row.prop(gpl, "before_color", text="")
440         sub.prop(gpl, "ghost_before_range", text="Before")
441
442
443         # - After Frames
444         sub = split.column(align=True)
445         row = sub.row(align=True)
446         row.active = gpl.use_ghost_custom_colors
447         row.prop(gpl, "after_color", text="")
448         sub.prop(gpl, "ghost_after_range", text="After")
449
450
451 class GreasePencilToolsPanel():
452     # subclass must set
453     # bl_space_type = 'IMAGE_EDITOR'
454     # bl_options = {'DEFAULT_CLOSED'}
455     bl_label = "Grease Pencil Settings"
456     bl_region_type = 'UI'
457
458     @classmethod
459     def poll(cls, context):
460         return (context.gpencil_data is not None)
461
462     @staticmethod
463     def draw(self, context):
464         layout = self.layout
465
466         gpd_owner = context.gpencil_data_owner
467         gpd = context.gpencil_data
468
469         layout.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
470
471         layout.separator()
472
473         layout.label("Proportional Edit:")
474         row = layout.row()
475         row.prop(context.tool_settings, "proportional_edit", text="")
476         row.prop(context.tool_settings, "proportional_edit_falloff", text="")
477
478         layout.separator()
479         layout.separator()
480
481         gpencil_stroke_placement_settings(context, layout, gpd)