Merge branch 'master' into blender2.8
[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 import bpy
22 from bpy.types import Menu, UIList
23 from bpy.app.translations import pgettext_iface as iface_
24
25
26 def gpencil_stroke_placement_settings(context, layout):
27     if context.space_data.type == 'VIEW_3D':
28         propname = "annotation_stroke_placement_view3d"
29     elif context.space_data.type == 'SEQUENCE_EDITOR':
30         propname = "annotation_stroke_placement_sequencer_preview"
31     elif context.space_data.type == 'IMAGE_EDITOR':
32         propname = "annotation_stroke_placement_image_editor"
33     else:
34         propname = "annotation_stroke_placement_view2d"
35
36     ts = context.tool_settings
37
38     col = layout.column(align=True)
39
40     if context.space_data.type != 'VIEW_3D':
41         col.label(text="Stroke Placement:")
42         row = col.row(align=True)
43         row.prop_enum(ts, propname, 'VIEW')
44         row.prop_enum(ts, propname, 'CURSOR', text="Cursor")
45
46
47 def gpencil_active_brush_settings_simple(context, layout):
48     brush = context.active_gpencil_brush
49     if brush is None:
50         layout.label(text="No Active Brush")
51         return
52
53     col = layout.column()
54     col.label(text="Active Brush:      ")
55
56     row = col.row(align=True)
57     row.operator_context = 'EXEC_REGION_WIN'
58     row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA')
59     row.prop(brush, "name", text="")
60
61     col.prop(brush, "size", slider=True)
62     row = col.row(align=True)
63     row.prop(brush, "use_random_pressure", text="", icon='RNDCURVE')
64     row.prop(brush, "pen_sensitivity_factor", slider=True)
65     row.prop(brush, "use_pressure", text="", icon='STYLUS_PRESSURE')
66     row = col.row(align=True)
67     row.prop(brush, "use_random_strength", text="", icon='RNDCURVE')
68     row.prop(brush, "strength", slider=True)
69     row.prop(brush, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
70     row = col.row(align=True)
71     row.prop(brush, "jitter", slider=True)
72     row.prop(brush, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
73     row = col.row()
74     row.prop(brush, "angle", slider=True)
75     row.prop(brush, "angle_factor", text="Factor", slider=True)
76
77
78 # XXX: To be replaced with active tools
79 class AnnotationDrawingToolsPanel:
80     # subclass must set
81     # bl_space_type = 'IMAGE_EDITOR'
82     bl_label = "Annotation"
83     bl_category = "Annotation"
84     bl_region_type = 'TOOLS'
85
86     @classmethod
87     def poll(cls, context):
88         return True
89
90     @staticmethod
91     def draw(self, context):
92         layout = self.layout
93
94         is_3d_view = context.space_data.type == 'VIEW_3D'
95         is_clip_editor = context.space_data.type == 'CLIP_EDITOR'
96
97         col = layout.column(align=True)
98
99         col.label(text="Draw:")
100         row = col.row(align=True)
101         row.operator("gpencil.annotate", icon='GREASEPENCIL', text="Draw").mode = 'DRAW'
102         row.operator("gpencil.annotate", icon='FORCE_CURVE', text="Erase").mode = 'ERASER'  # XXX: Needs a dedicated icon
103
104         row = col.row(align=True)
105         row.operator("gpencil.annotate", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT'
106         row.operator("gpencil.annotate", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY'
107
108         col.separator()
109
110         sub = col.column(align=True)
111         sub.operator("gpencil.blank_frame_add", icon='NEW')
112         sub.operator("gpencil.active_frames_delete_all", icon='X', text="Delete Frame(s)")
113
114         #sub = col.column(align=True)
115         #sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing")
116         #sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
117         #sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back")
118
119         col.separator()
120         col.separator()
121
122         if context.space_data.type in {'CLIP_EDITOR'}:
123             col.separator()
124             col.label(text="Data Source:")
125             row = col.row(align=True)
126             if is_3d_view:
127                 row.prop(context.tool_settings, "grease_pencil_source", expand=True)
128             elif is_clip_editor:
129                 row.prop(context.space_data, "grease_pencil_source", expand=True)
130
131         # col.separator()
132         # col.separator()
133
134         gpencil_stroke_placement_settings(context, col)
135
136         gpd = context.gpencil_data
137
138         if gpd and not is_3d_view:
139             layout.separator()
140             layout.separator()
141
142             col = layout.column(align=True)
143             col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
144
145
146 class GreasePencilStrokeEditPanel:
147     # subclass must set
148     # bl_space_type = 'IMAGE_EDITOR'
149     bl_label = "Edit Strokes"
150     bl_category = "Tools"
151     bl_region_type = 'TOOLS'
152
153     @classmethod
154     def poll(cls, context):
155         if context.gpencil_data is None:
156             return False
157
158         gpd = context.gpencil_data
159         return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
160
161     @staticmethod
162     def draw(self, context):
163         layout = self.layout
164
165         is_3d_view = context.space_data.type == 'VIEW_3D'
166
167         if not is_3d_view:
168             layout.label(text="Select:")
169             col = layout.column(align=True)
170             col.operator("gpencil.select_all", text="Select All")
171             col.operator("gpencil.select_border")
172             col.operator("gpencil.select_circle")
173
174             layout.separator()
175
176             col = layout.column(align=True)
177             col.operator("gpencil.select_linked")
178             col.operator("gpencil.select_more")
179             col.operator("gpencil.select_less")
180             col.operator("gpencil.select_alternate")
181
182         layout.label(text="Edit:")
183         row = layout.row(align=True)
184         row.operator("gpencil.copy", text="Copy")
185         row.operator("gpencil.paste", text="Paste").type = 'COPY'
186         row.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
187
188         col = layout.column(align=True)
189         col.operator("gpencil.delete")
190         col.operator("gpencil.duplicate_move", text="Duplicate")
191         if is_3d_view:
192             col.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
193
194         layout.separator()
195
196         if not is_3d_view:
197             col = layout.column(align=True)
198             col.operator("transform.translate")                # icon='MAN_TRANS'
199             col.operator("transform.rotate")                   # icon='MAN_ROT'
200             col.operator("transform.resize", text="Scale")     # icon='MAN_SCALE'
201
202             layout.separator()
203
204         layout.separator()
205         col = layout.column(align=True)
206         col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction")
207         col.operator("gpencil.stroke_change_color", text="Assign Material")
208
209         layout.separator()
210         col = layout.column(align=True)
211         col.operator("gpencil.stroke_subdivide", text="Subdivide")
212         row = col.row(align=True)
213         row.operator("gpencil.stroke_simplify_fixed", text="Simplify")
214         row.operator("gpencil.stroke_simplify", text="Adaptative")
215
216         col.separator()
217
218         row = col.row(align=True)
219         row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
220         row.operator("gpencil.stroke_join", text="& Copy").type = 'JOINCOPY'
221
222         col.operator("gpencil.stroke_flip", text="Flip Direction")
223
224         if is_3d_view:
225             layout.separator()
226
227             col = layout.column(align=True)
228             col.operator_menu_enum("gpencil.stroke_separate", text="Separate...", property="mode")
229             col.operator("gpencil.stroke_split", text="Split")
230
231             col = layout.column(align=True)
232             col.label(text="Cleanup:")
233             col.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type")
234             col.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode")
235
236
237 class GreasePencilStrokeSculptPanel:
238     # subclass must set
239     # bl_space_type = 'IMAGE_EDITOR'
240     bl_label = "Sculpt Strokes"
241     bl_category = "Tools"
242
243     @staticmethod
244     def draw(self, context):
245         layout = self.layout
246         layout.use_property_split = True
247         layout.use_property_decorate = False
248
249         settings = context.tool_settings.gpencil_sculpt
250         tool = settings.tool
251         brush = settings.brush
252
253         layout.template_icon_view(settings, "tool", show_labels=True)
254
255         layout.prop(brush, "size", slider=True)
256         row = layout.row(align=True)
257         row.prop(brush, "strength", slider=True)
258         row.prop(brush, "use_pressure_strength", text="")
259
260         layout.prop(brush, "use_falloff")
261
262         if tool in {'SMOOTH', 'RANDOMIZE'}:
263             layout.prop(settings, "affect_position", text="Affect Position")
264             layout.prop(settings, "affect_strength", text="Affect Strength")
265             layout.prop(settings, "affect_thickness", text="Affect Thickness")
266
267             if tool == 'SMOOTH':
268                 layout.prop(brush, "affect_pressure")
269
270             layout.prop(settings, "affect_uv", text="Affect UV")
271
272         if tool in {'THICKNESS', 'PINCH', 'TWIST'}:
273             layout.prop(brush, "direction", expand=True)
274
275
276 # GP Object Tool Settings
277 class GreasePencilAppearancePanel:
278     bl_label = "Brush Appearance"
279     bl_options = {'DEFAULT_CLOSED'}
280
281     @classmethod
282     def poll(cls, context):
283         ob = context.active_object
284         return ob and ob.type == 'GPENCIL'
285
286     @staticmethod
287     def draw(self, context):
288         layout = self.layout
289         layout.use_property_split = True
290         layout.use_property_decorate = False
291
292         ob = context.active_object
293
294         if ob.mode == 'GPENCIL_PAINT':
295             brush = context.active_gpencil_brush
296             gp_settings = brush.gpencil_settings
297
298             layout.prop(gp_settings, "gpencil_brush_type", text="Brush Type")
299
300             sub = layout.column(align=True)
301             sub.enabled = not brush.use_custom_icon
302             sub.prop(gp_settings, "gp_icon", text="Icon")
303
304             layout.prop(brush, "use_custom_icon")
305             sub = layout.column()
306             sub.active = brush.use_custom_icon
307             sub.prop(brush, "icon_filepath", text="")
308
309             layout.prop(gp_settings, "use_cursor", text="Show Brush")
310
311             if gp_settings.gpencil_brush_type == 'FILL':
312                 layout.prop(brush, "cursor_color_add", text="Color")
313
314         elif ob.mode in ('GPENCIL_SCULPT', 'GPENCIL_WEIGHT'):
315             settings = context.tool_settings.gpencil_sculpt
316             brush = settings.brush
317
318             col = layout.column(align=True)
319             col.prop(brush, "use_cursor", text="Show Brush")
320             col.row().prop(brush, "cursor_color_add", text="Add")
321             col.row().prop(brush, "cursor_color_sub", text="Subtract")
322
323
324 class GPENCIL_MT_pie_tool_palette(Menu):
325     """A pie menu for quick access to Grease Pencil tools"""
326     bl_label = "Grease Pencil Tools"
327
328     def draw(self, context):
329         layout = self.layout
330
331         pie = layout.menu_pie()
332         gpd = context.gpencil_data
333
334         # W - Drawing Types
335         col = pie.column()
336         col.operator("gpencil.draw", text="Draw", icon='GREASEPENCIL').mode = 'DRAW'
337         col.operator("gpencil.draw", text="Straight Lines", icon='LINE_DATA').mode = 'DRAW_STRAIGHT'
338         col.operator("gpencil.draw", text="Poly", icon='MESH_DATA').mode = 'DRAW_POLY'
339
340         # E - Eraser
341         # XXX: needs a dedicated icon...
342         col = pie.column()
343         col.operator("gpencil.draw", text="Eraser", icon='FORCE_CURVE').mode = 'ERASER'
344
345         # E - "Settings" Palette is included here too, since it needs to be in a stable position...
346         if gpd and gpd.layers.active:
347             col.separator()
348             col.operator("wm.call_menu_pie", text="Settings...", icon='SCRIPTWIN').name = "GPENCIL_MT_pie_settings_palette"
349
350         # Editing tools
351         if gpd:
352             if gpd.use_stroke_edit_mode and context.editable_gpencil_strokes:
353                 # S - Exit Edit Mode
354                 pie.operator("gpencil.editmode_toggle", text="Exit Edit Mode", icon='EDIT')
355
356                 # N - Transforms
357                 col = pie.column()
358                 row = col.row(align=True)
359                 row.operator("transform.translate", icon='MAN_TRANS')
360                 row.operator("transform.rotate", icon='MAN_ROT')
361                 row.operator("transform.resize", text="Scale", icon='MAN_SCALE')
362                 row = col.row(align=True)
363                 row.label(text="Proportional Edit:")
364                 row.prop(context.tool_settings, "proportional_edit", text="", icon_only=True)
365                 row.prop(context.tool_settings, "proportional_edit_falloff", text="", icon_only=True)
366
367                 # NW - Select (Non-Modal)
368                 col = pie.column()
369                 col.operator("gpencil.select_all", text="Select All", icon='PARTICLE_POINT')
370                 col.operator("gpencil.select_all", text="Select Inverse", icon='BLANK1')
371                 col.operator("gpencil.select_linked", text="Select Linked", icon='LINKED')
372                 col.operator("gpencil.palettecolor_select", text="Select Color", icon='COLOR')
373
374                 # NE - Select (Modal)
375                 col = pie.column()
376                 col.operator("gpencil.select_border", text="Border Select", icon='BORDER_RECT')
377                 col.operator("gpencil.select_circle", text="Circle Select", icon='META_EMPTY')
378                 col.operator("gpencil.select_lasso", text="Lasso Select", icon='BORDER_LASSO')
379                 col.operator("gpencil.select_alternate", text="Alternate Select", icon='BORDER_LASSO')
380
381                 # SW - Edit Tools
382                 col = pie.column()
383                 col.operator("gpencil.duplicate_move", icon='PARTICLE_PATH', text="Duplicate")
384                 col.operator("gpencil.delete", icon='X', text="Delete...")
385
386                 # SE - More Tools
387                 pie.operator("wm.call_menu_pie", text="More...").name = "GPENCIL_MT_pie_tools_more"
388             else:
389                 # Toggle Edit Mode
390                 pie.operator("gpencil.editmode_toggle", text="Enable Stroke Editing", icon='EDIT')
391
392
393 class GPENCIL_MT_pie_settings_palette(Menu):
394     """A pie menu for quick access to Grease Pencil settings"""
395     bl_label = "Grease Pencil Settings"
396
397     @classmethod
398     def poll(cls, context):
399         return bool(context.gpencil_data and context.active_gpencil_layer)
400
401     def draw(self, context):
402         layout = self.layout
403
404         pie = layout.menu_pie()
405         gpd = context.gpencil_data
406         gpl = context.active_gpencil_layer
407 <<<<<<< HEAD
408         palcolor = None  # context.active_gpencil_palettecolor
409         brush = context.active_gpencil_brush
410 =======
411         palcolor = context.active_gpencil_palettecolor
412         # brush = context.active_gpencil_brush
413 >>>>>>> master
414
415         is_editmode = bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
416
417         # W - Stroke draw settings
418         col = pie.column(align=True)
419         if palcolor is not None:
420             col.enabled = not palcolor.lock
421             col.label(text="Stroke")
422             col.prop(palcolor, "color", text="")
423             col.prop(palcolor, "alpha", text="", slider=True)
424
425         # E - Fill draw settings
426         col = pie.column(align=True)
427         if palcolor is not None:
428             col.enabled = not palcolor.lock
429             col.label(text="Fill")
430             col.prop(palcolor, "fill_color", text="")
431             col.prop(palcolor, "fill_alpha", text="", slider=True)
432
433         # S Brush settings
434         gpencil_active_brush_settings_simple(context, pie)
435
436         # N - Active Layer
437         col = pie.column()
438         col.label(text="Active Layer:      ")
439
440         row = col.row()
441         row.operator_context = 'EXEC_REGION_WIN'
442         row.operator_menu_enum("gpencil.layer_change", "layer", text="", icon='GREASEPENCIL')
443         row.prop(gpl, "info", text="")
444         row.operator("gpencil.layer_remove", text="", icon='X')
445
446         row = col.row()
447         row.prop(gpl, "lock")
448         row.prop(gpl, "hide")
449         col.prop(gpl, "use_onion_skinning")
450
451         # NW/NE/SW/SE - These operators are only available in editmode
452         # as they require strokes to be selected to work
453         if is_editmode:
454             # NW - Move stroke Down
455             col = pie.column(align=True)
456             col.label(text="Arrange Strokes")
457             col.operator("gpencil.stroke_arrange", text="Send to Back").direction = 'BOTTOM'
458             col.operator("gpencil.stroke_arrange", text="Send Backward").direction = 'DOWN'
459
460             # NE - Move stroke Up
461             col = pie.column(align=True)
462             col.label(text="Arrange Strokes")
463             col.operator("gpencil.stroke_arrange", text="Bring to Front").direction = 'TOP'
464             col.operator("gpencil.stroke_arrange", text="Bring Forward").direction = 'UP'
465
466             # SW - Move stroke to color
467             col = pie.column(align=True)
468             col.operator("gpencil.stroke_change_color", text="Move to Color")
469
470             # SE - Join strokes
471             col = pie.column(align=True)
472             col.label(text="Join Strokes")
473             row = col.row()
474             row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
475             row.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
476             col.operator("gpencil.stroke_flip", text="Flip Direction")
477
478             col.prop(gpd, "show_stroke_direction", text="Show Drawing Direction")
479
480
481 class GPENCIL_MT_pie_tools_more(Menu):
482     """A pie menu for accessing more Grease Pencil tools"""
483     bl_label = "More Grease Pencil Tools"
484
485     @classmethod
486     def poll(cls, context):
487         gpd = context.gpencil_data
488         return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
489
490     def draw(self, context):
491         layout = self.layout
492
493         pie = layout.menu_pie()
494         # gpd = context.gpencil_data
495
496         col = pie.column(align=True)
497         col.operator("gpencil.copy", icon='COPYDOWN', text="Copy")
498         col.operator("gpencil.paste", icon='PASTEDOWN', text="Paste")
499
500         col = pie.column(align=True)
501         col.operator("gpencil.select_more", icon='ZOOMIN')
502         col.operator("gpencil.select_less", icon='ZOOMOUT')
503
504         pie.operator("transform.mirror", icon='MOD_MIRROR')
505         pie.operator("transform.bend", icon='MOD_SIMPLEDEFORM')
506         pie.operator("transform.shear", icon='MOD_TRIANGULATE')
507         pie.operator("transform.tosphere", icon='MOD_MULTIRES')
508
509         pie.operator("gpencil.convert", icon='OUTLINER_OB_CURVE', text="Convert...")
510         pie.operator("wm.call_menu_pie", text="Back to Main Palette...").name = "GPENCIL_MT_pie_tool_palette"
511
512
513 class GPENCIL_MT_pie_sculpt(Menu):
514     """A pie menu for accessing Grease Pencil stroke sculpt settings"""
515     bl_label = "Grease Pencil Sculpt"
516
517     @classmethod
518     def poll(cls, context):
519         gpd = context.gpencil_data
520         return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
521
522     def draw(self, context):
523         layout = self.layout
524
525         pie = layout.menu_pie()
526
527         settings = context.tool_settings.gpencil_sculpt
528         brush = settings.brush
529
530         # W - Launch Sculpt Mode
531         col = pie.column()
532         # col.label(text="Tool:")
533         col.prop(settings, "tool", text="")
534         col.operator("gpencil.brush_paint", text="Sculpt", icon='SCULPTMODE_HLT')
535
536         # E - Common Settings
537         col = pie.column(align=True)
538         col.prop(brush, "size", slider=True)
539         row = col.row(align=True)
540         row.prop(brush, "strength", slider=True)
541         # row.prop(brush, "use_pressure_strength", text="", icon_only=True)
542         col.prop(brush, "use_falloff")
543         if settings.tool in {'SMOOTH', 'RANDOMIZE'}:
544             row = col.row(align=True)
545             row.prop(settings, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
546             row.prop(settings, "affect_strength", text="Strength", icon='COLOR', toggle=True)
547             row.prop(settings, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
548
549         # S - Change Brush Type Shortcuts
550         row = pie.row()
551         row.prop_enum(settings, "tool", value='GRAB')
552         row.prop_enum(settings, "tool", value='PUSH')
553         row.prop_enum(settings, "tool", value='CLONE')
554
555         # N - Change Brush Type Shortcuts
556         row = pie.row()
557         row.prop_enum(settings, "tool", value='SMOOTH')
558         row.prop_enum(settings, "tool", value='THICKNESS')
559         row.prop_enum(settings, "tool", value='STRENGTH')
560         row.prop_enum(settings, "tool", value='RANDOMIZE')
561
562
563 class GPENCIL_MT_snap(Menu):
564     bl_label = "Snap"
565
566     def draw(self, context):
567         layout = self.layout
568
569         layout.operator("gpencil.snap_to_grid", text="Selection to Grid")
570         layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor").use_offset = False
571         layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor (Keep Offset)").use_offset = True
572
573         layout.separator()
574
575         layout.operator("gpencil.snap_cursor_to_selected", text="Cursor to Selected")
576         layout.operator("view3d.snap_cursor_to_center", text="Cursor to Center")
577         layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
578
579
580 class GPENCIL_MT_separate(Menu):
581     bl_label = "Separate"
582
583     def draw(self, context):
584         layout = self.layout
585         layout.operator("gpencil.stroke_separate", text="Selected Points").mode = 'POINT'
586         layout.operator("gpencil.stroke_separate", text="Selected Strokes").mode = 'STROKE'
587         layout.operator("gpencil.stroke_separate", text="Active Layer").mode = 'LAYER'
588
589
590 class GPENCIL_MT_gpencil_draw_specials(Menu):
591     bl_label = "GPencil Draw Specials"
592
593     def draw(self, context):
594         layout = self.layout
595         is_3d_view = context.space_data.type == 'VIEW_3D'
596
597         layout.operator_context = 'INVOKE_REGION_WIN'
598
599         layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
600         layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame All Layers").mode = 'ALL'
601
602         layout.separator()
603         layout.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE'
604         layout.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX'
605         layout.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE'
606
607
608 class GPENCIL_MT_gpencil_draw_delete(Menu):
609     bl_label = "GPencil Draw Delete"
610
611     def draw(self, context):
612         layout = self.layout
613         is_3d_view = context.space_data.type == 'VIEW_3D'
614
615         layout.operator_context = 'INVOKE_REGION_WIN'
616
617         layout.operator("gpencil.active_frames_delete_all", text="Delete Frame")
618
619
620 class GPENCIL_MT_cleanup(Menu):
621     bl_label = "Clean Up"
622
623     def draw(self, context):
624         layout = self.layout
625         layout.operator("gpencil.frame_clean_loose", text="Loose Points")
626         layout.separator()
627
628         layout.operator("gpencil.frame_clean_fill", text="Boundary Strokes").mode = 'ACTIVE'
629         layout.operator("gpencil.frame_clean_fill", text="Boundary Strokes all Frames").mode = 'ALL'
630         layout.separator()
631
632         layout.operator("gpencil.reproject")
633
634
635 class GPENCIL_UL_annotation_layer(UIList):
636     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
637         # assert(isinstance(item, bpy.types.GPencilLayer)
638         gpl = item
639         gpd = context.gpencil_data
640
641         if self.layout_type in {'DEFAULT', 'COMPACT'}:
642             if gpl.lock:
643                 layout.active = False
644
645             split = layout.split(factor=0.2)
646             split.prop(gpl, "color", text="", emboss=True)
647             split.prop(gpl, "info", text="", emboss=False)
648
649             row = layout.row(align=True)
650             # row.prop(gpl, "lock", text="", emboss=False)
651             row.prop(gpl, "hide", text="", emboss=False)
652         elif self.layout_type == 'GRID':
653             layout.alignment = 'CENTER'
654             layout.label(text="", icon_value=icon)
655
656
657 class AnnotationDataPanel:
658     bl_label = "Annotations"
659     bl_region_type = 'UI'
660     bl_options = {'DEFAULT_CLOSED'}
661
662     @classmethod
663     def poll(cls, context):
664         # Show this panel as long as someone that might own this exists
665         # AND the owner isn't an object (e.g. GP Object)
666         if context.gpencil_data_owner is None:
667             return False
668         elif type(context.gpencil_data_owner) is bpy.types.Object:
669             return False
670         else:
671             return True
672
673     @staticmethod
674     def draw_header(self, context):
675         if context.space_data.type != 'VIEW_3D':
676             self.layout.prop(context.space_data, "show_annotation", text="")
677
678     @staticmethod
679     def draw(self, context):
680         layout = self.layout
681         layout.use_property_decorate = False
682
683         # Grease Pencil owner.
684         gpd_owner = context.gpencil_data_owner
685         gpd = context.gpencil_data
686
687         # Owner selector.
688         if context.space_data.type == 'CLIP_EDITOR':
689             layout.row().prop(context.space_data, "grease_pencil_source", expand=True)
690
691         layout.template_ID(gpd_owner, "grease_pencil", new="gpencil.data_add", unlink="gpencil.data_unlink")
692
693         # List of layers/notes.
694         if gpd and gpd.layers:
695             self.draw_layers(context, layout, gpd)
696
697     def draw_layers(self, context, layout, gpd):
698         row = layout.row()
699
700         col = row.column()
701         if len(gpd.layers) >= 2:
702             layer_rows = 5
703         else:
704             layer_rows = 2
705         col.template_list("GPENCIL_UL_annotation_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows)
706
707         col = row.column()
708
709         sub = col.column(align=True)
710         sub.operator("gpencil.layer_add", icon='ZOOMIN', text="")
711         sub.operator("gpencil.layer_remove", icon='ZOOMOUT', text="")
712
713         gpl = context.active_gpencil_layer
714         if gpl:
715             if len(gpd.layers) > 1:
716                 col.separator()
717
718                 sub = col.column(align=True)
719                 sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
720                 sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
721
722         tool_settings = context.tool_settings
723         if gpd and gpl:
724             layout.prop(gpl, "thickness")
725         else:
726             layout.prop(tool_settings, "annotation_thickness", text="Thickness")
727
728         if gpl:
729             # layout.prop(gpl, "opacity", text="Opacity", slider=True)
730             # Full-Row - Frame Locking (and Delete Frame)
731             row = layout.row(align=True)
732             row.active = not gpl.lock
733
734             if gpl.active_frame:
735                 lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked")
736                 lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status)
737             else:
738                 lock_label = iface_("Lock Frame")
739             row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
740             row.operator("gpencil.active_frame_delete", text="", icon='X')
741
742
743 class GreasePencilOnionPanel:
744     @staticmethod
745     def draw_settings(layout, gp):
746         col = layout.column()
747         col.prop(gp, "onion_mode")
748         col.prop(gp, "onion_factor", text="Opacity", slider=True)
749
750         if gp.onion_mode in ('ABSOLUTE', 'RELATIVE'):
751             col = layout.column(align=True)
752             col.prop(gp, "ghost_before_range", text="Frames Before")
753             col.prop(gp, "ghost_after_range", text="After")
754
755         layout.prop(gp, "use_ghost_custom_colors", text="Use Custom Colors")
756
757         if gp.use_ghost_custom_colors:
758             col = layout.column(align=True)
759             col.active = gp.use_ghost_custom_colors
760             col.prop(gp, "before_color", text="Color Before")
761             col.prop(gp, "after_color", text="After")
762
763         layout.prop(gp, "use_ghosts_always", text="View In Render")
764
765         col = layout.column(align=True)
766         col.active = gp.use_onion_skinning
767         col.prop(gp, "use_onion_fade", text="Fade")
768         if hasattr(gp, "use_onion_loop"):  # XXX
769             sub = layout.column()
770             sub.active = gp.onion_mode in ('RELATIVE', 'SELECTED')
771             sub.prop(gp, "use_onion_loop", text="Loop")
772
773
774 class GreasePencilToolsPanel:
775     # For use in "2D" Editors without their own toolbar
776     # subclass must set
777     # bl_space_type = 'IMAGE_EDITOR'
778     bl_label = "Grease Pencil Settings"
779     bl_region_type = 'UI'
780     bl_options = {'DEFAULT_CLOSED'}
781
782     @classmethod
783     def poll(cls, context):
784         # XXX - disabled in 2.8 branch.
785         return False
786
787         return (context.gpencil_data is not None)
788
789     @staticmethod
790     def draw(self, context):
791         layout = self.layout
792
793         # gpd_owner = context.gpencil_data_owner
794         gpd = context.gpencil_data
795
796         layout.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
797
798         layout.separator()
799
800         layout.label(text="Proportional Edit:")
801         row = layout.row()
802         row.prop(context.tool_settings, "proportional_edit", text="")
803         row.prop(context.tool_settings, "proportional_edit_falloff", text="")
804
805         layout.separator()
806         layout.separator()
807
808         gpencil_active_brush_settings_simple(context, layout)
809
810         layout.separator()
811
812         gpencil_stroke_placement_settings(context, layout)
813
814
815 classes = (
816     GPENCIL_MT_pie_tool_palette,
817     GPENCIL_MT_pie_settings_palette,
818     GPENCIL_MT_pie_tools_more,
819     GPENCIL_MT_pie_sculpt,
820
821     GPENCIL_MT_snap,
822     GPENCIL_MT_separate,
823     GPENCIL_MT_cleanup,
824
825     GPENCIL_MT_gpencil_draw_specials,
826     GPENCIL_MT_gpencil_draw_delete,
827
828     GPENCIL_UL_annotation_layer,
829 )
830
831 if __name__ == "__main__":  # only for live edit.
832     from bpy.utils import register_class
833     for cls in classes:
834         register_class(cls)