1b5d78f093c91deac7574011dd19234f1b40f6db
[blender.git] / release / scripts / startup / bl_ui / space_view3d_toolbar.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 .properties_grease_pencil_common import (
23     GreasePencilStrokeEditPanel,
24     GreasePencilStrokeSculptPanel,
25     GreasePencilSculptOptionsPanel,
26     GreasePencilAppearancePanel,
27 )
28 from .properties_paint_common import (
29     UnifiedPaintPanel,
30     brush_texture_settings,
31     brush_texpaint_common,
32     brush_mask_texture_settings,
33 )
34 from bl_operators.presets import PresetMenu
35
36
37 class View3DPanel:
38     bl_space_type = 'PROPERTIES'
39     bl_region_type = 'WINDOW'
40
41
42 # **************** standard tool clusters ******************
43
44 # Keyframing tools
45 def draw_keyframing_tools(context, layout):
46     col = layout.column(align=True)
47     col.label(text="Keyframes:")
48     row = col.row(align=True)
49     row.operator("anim.keyframe_insert_menu", text="Insert")
50     row.operator("anim.keyframe_delete_v3d", text="Remove")
51
52
53 # Used by vertex & weight paint
54 def draw_vpaint_symmetry(layout, vpaint):
55
56     split = layout.split()
57
58     col = split.column()
59     col.alignment = 'RIGHT'
60     col.label(text="Mirror")
61
62     col = split.column()
63     row = col.row(align=True)
64     row.prop(vpaint, "use_symmetry_x", text="X", toggle=True)
65     row.prop(vpaint, "use_symmetry_y", text="Y", toggle=True)
66     row.prop(vpaint, "use_symmetry_z", text="Z", toggle=True)
67
68     col = layout.column()
69     col.use_property_split = True
70     col.use_property_decorate = False
71     col.prop(vpaint, "radial_symmetry", text="Radial")
72
73 # Most of these panels should not be visible in GP edit modes
74
75
76 def is_not_gpencil_edit_mode(context):
77     is_gpmode = (
78         context.active_object and
79         context.active_object.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}
80     )
81     return not is_gpmode
82
83
84 # ********** default tools for editmode_mesh ****************
85
86
87 class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
88     bl_category = "Options"
89     bl_context = ".mesh_edit"  # dot on purpose (access from topbar)
90     bl_label = "Mesh Options"
91
92     @classmethod
93     def poll(cls, context):
94         return context.active_object
95
96     def draw(self, context):
97         layout = self.layout
98
99         layout.use_property_split = True
100         layout.use_property_decorate = False
101
102         ob = context.active_object
103
104         tool_settings = context.tool_settings
105         mesh = ob.data
106
107         col = layout.column(align=True)
108         col.prop(mesh, "use_mirror_x")
109
110         row = col.row(align=True)
111         row.active = ob.data.use_mirror_x
112         row.prop(mesh, "use_mirror_topology")
113
114         layout.prop(tool_settings, "edge_path_mode")
115         layout.prop(tool_settings, "edge_path_live_unwrap")
116         layout.prop(tool_settings, "double_threshold")
117         layout.prop(tool_settings, "use_mesh_automerge")  # , icon='AUTOMERGE_ON'
118
119
120 # ********** default tools for editmode_curve ****************
121
122
123 class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
124     bl_category = "Options"
125     bl_context = ".curve_edit"  # dot on purpose (access from topbar)
126     bl_label = "Curve Stroke"
127
128     def draw(self, context):
129         layout = self.layout
130
131         tool_settings = context.tool_settings
132         cps = tool_settings.curve_paint_settings
133
134         col = layout.column()
135
136         col.prop(cps, "curve_type")
137
138         if cps.curve_type == 'BEZIER':
139             col.label(text="Bezier Options:")
140             col.prop(cps, "error_threshold")
141             col.prop(cps, "fit_method")
142             col.prop(cps, "use_corners_detect")
143
144             col = layout.column()
145             col.active = cps.use_corners_detect
146             col.prop(cps, "corner_angle")
147
148         col.label(text="Pressure Radius:")
149         row = layout.row(align=True)
150         rowsub = row.row(align=True)
151         rowsub.prop(cps, "radius_min", text="Min")
152         rowsub.prop(cps, "radius_max", text="Max")
153
154         row.prop(cps, "use_pressure_radius", text="", icon_only=True)
155
156         col = layout.column()
157         col.label(text="Taper Radius:")
158         row = layout.row(align=True)
159         row.prop(cps, "radius_taper_start", text="Start")
160         row.prop(cps, "radius_taper_end", text="End")
161
162         col = layout.column()
163         col.label(text="Projection Depth:")
164         row = layout.row(align=True)
165         row.prop(cps, "depth_mode", expand=True)
166
167         col = layout.column()
168         if cps.depth_mode == 'SURFACE':
169             col.prop(cps, "surface_offset")
170             col.prop(cps, "use_offset_absolute")
171             col.prop(cps, "use_stroke_endpoints")
172             if cps.use_stroke_endpoints:
173                 colsub = layout.column(align=True)
174                 colsub.prop(cps, "surface_plane", expand=True)
175
176
177 # ********** default tools for editmode_armature ****************
178
179
180 class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel):
181     bl_category = "Options"
182     bl_context = ".armature_edit"  # dot on purpose (access from topbar)
183     bl_label = "Armature Options"
184
185     def draw(self, context):
186         arm = context.active_object.data
187
188         self.layout.prop(arm, "use_mirror_x")
189
190
191 # ********** default tools for pose-mode ****************
192
193 class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
194     bl_category = "Options"
195     bl_context = ".posemode"  # dot on purpose (access from topbar)
196     bl_label = "Pose Options"
197
198     def draw(self, context):
199         arm = context.active_object.data
200
201         self.layout.prop(arm, "use_auto_ik")
202         self.layout.prop(arm, "use_mirror_x")
203
204 # ********** default tools for paint modes ****************
205
206
207 class View3DPaintPanel(UnifiedPaintPanel):
208     bl_space_type = 'PROPERTIES'
209     bl_region_type = 'WINDOW'
210
211
212 # TODO, move to space_view3d.py
213 class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
214     bl_context = ".paint_common"  # dot on purpose (access from topbar)
215     bl_label = "Brush"
216
217     @classmethod
218     def poll(cls, context):
219         return cls.paint_settings(context)
220
221     def draw(self, context):
222         layout = self.layout
223
224         toolsettings = context.tool_settings
225         settings = self.paint_settings(context)
226         brush = settings.brush
227
228         if not context.particle_edit_object:
229             col = layout.split().column()
230             col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
231
232         # Particle Mode #
233         if context.particle_edit_object:
234             tool = settings.tool
235
236             if tool != 'NONE':
237                 layout.column().prop(settings, "tool")
238                 col = layout.column()
239                 col.prop(brush, "size", slider=True)
240                 if tool == 'ADD':
241                     col.prop(brush, "count")
242
243                     col = layout.column()
244                     col.prop(settings, "use_default_interpolate")
245                     col.prop(brush, "steps", slider=True)
246                     col.prop(settings, "default_key_count", slider=True)
247                 else:
248                     col.prop(brush, "strength", slider=True)
249
250                     if tool == 'LENGTH':
251                         layout.row().prop(brush, "length_mode", expand=True)
252                     elif tool == 'PUFF':
253                         layout.row().prop(brush, "puff_mode", expand=True)
254                         layout.prop(brush, "use_puff_volume")
255
256         # Sculpt Mode #
257
258         elif context.sculpt_object and brush:
259             capabilities = brush.sculpt_capabilities
260
261             col = layout.column()
262
263             col.separator()
264
265             row = col.row(align=True)
266
267             ups = toolsettings.unified_paint_settings
268             if ((ups.use_unified_size and ups.use_locked_size) or
269                     ((not ups.use_unified_size) and brush.use_locked_size)):
270                 self.prop_unified_size(row, context, brush, "use_locked_size", icon='LOCKED')
271                 self.prop_unified_size(row, context, brush, "unprojected_radius", slider=True, text="Radius")
272             else:
273                 self.prop_unified_size(row, context, brush, "use_locked_size", icon='UNLOCKED')
274                 self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
275
276             self.prop_unified_size(row, context, brush, "use_pressure_size")
277
278             # strength, use_strength_pressure, and use_strength_attenuation
279             col.separator()
280             row = col.row(align=True)
281
282             if capabilities.has_space_attenuation:
283                 row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
284
285             self.prop_unified_strength(row, context, brush, "strength", text="Strength")
286
287             if capabilities.has_strength_pressure:
288                 self.prop_unified_strength(row, context, brush, "use_pressure_strength")
289
290             # auto_smooth_factor and use_inverse_smooth_pressure
291             if capabilities.has_auto_smooth:
292                 col.separator()
293
294                 row = col.row(align=True)
295                 row.prop(brush, "auto_smooth_factor", slider=True)
296                 row.prop(brush, "use_inverse_smooth_pressure", toggle=True, text="")
297
298             # normal_weight
299             if capabilities.has_normal_weight:
300                 col.separator()
301                 row = col.row(align=True)
302                 row.prop(brush, "normal_weight", slider=True)
303
304             # crease_pinch_factor
305             if capabilities.has_pinch_factor:
306                 col.separator()
307                 row = col.row(align=True)
308                 row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
309
310             # rake_factor
311             if capabilities.has_rake_factor:
312                 col.separator()
313                 row = col.row(align=True)
314                 row.prop(brush, "rake_factor", slider=True)
315
316             # use_original_normal and sculpt_plane
317             if capabilities.has_sculpt_plane:
318                 col.separator()
319                 row = col.row(align=True)
320
321                 row.prop(brush, "use_original_normal", toggle=True, icon_only=True)
322
323                 row.prop(brush, "sculpt_plane", text="")
324
325             if brush.sculpt_tool == 'MASK':
326                 col.prop(brush, "mask_tool", text="")
327
328             # plane_offset, use_offset_pressure, use_plane_trim, plane_trim
329             if capabilities.has_plane_offset:
330                 row = col.row(align=True)
331                 row.prop(brush, "plane_offset", slider=True)
332                 row.prop(brush, "use_offset_pressure", text="")
333
334                 col.separator()
335
336                 row = col.row()
337                 row.prop(brush, "use_plane_trim", text="Trim")
338                 row = col.row()
339                 row.active = brush.use_plane_trim
340                 row.prop(brush, "plane_trim", slider=True, text="Distance")
341
342             # height
343             if capabilities.has_height:
344                 row = col.row()
345                 row.prop(brush, "height", slider=True, text="Height")
346
347             # use_frontface
348             col.separator()
349             col.prop(brush, "use_frontface", text="Front Faces Only")
350             col.prop(brush, "use_projected")
351
352             # direction
353             col.separator()
354             col.row().prop(brush, "direction", expand=True)
355
356             # use_accumulate
357             if capabilities.has_accumulate:
358                 col.separator()
359
360                 col.prop(brush, "use_accumulate")
361
362             # use_persistent, set_persistent_base
363             if capabilities.has_persistence:
364                 col.separator()
365
366                 ob = context.sculpt_object
367                 do_persistent = True
368
369                 # not supported yet for this case
370                 for md in ob.modifiers:
371                     if md.type == 'MULTIRES':
372                         do_persistent = False
373                         break
374
375                 if do_persistent:
376                     col.prop(brush, "use_persistent")
377                     col.operator("sculpt.set_persistent_base")
378
379         # Texture Paint Mode #
380
381         elif context.image_paint_object and brush:
382             brush_texpaint_common(self, context, layout, brush, settings, True)
383
384         # Weight Paint Mode #
385         elif context.weight_paint_object and brush:
386
387             col = layout.column()
388
389             row = col.row(align=True)
390             self.prop_unified_weight(row, context, brush, "weight", slider=True, text="Weight")
391
392             row = col.row(align=True)
393             self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
394             self.prop_unified_size(row, context, brush, "use_pressure_size")
395
396             row = col.row(align=True)
397             self.prop_unified_strength(row, context, brush, "strength", text="Strength")
398             self.prop_unified_strength(row, context, brush, "use_pressure_strength")
399
400             col.separator()
401             col.prop(brush, "vertex_tool", text="Blend")
402
403             if brush.vertex_tool != 'SMEAR':
404                 col.prop(brush, "use_accumulate")
405                 col.separator()
406
407             col.prop(brush, "use_frontface", text="Front Faces Only")
408             row = col.row()
409             row.prop(brush, "use_frontface_falloff", text="Falloff Angle")
410             sub = row.row()
411             sub.active = brush.use_frontface_falloff
412             sub.prop(brush, "falloff_angle", text="")
413
414             col.prop(brush, "use_projected")
415
416             col = layout.column()
417             col.prop(toolsettings, "use_auto_normalize", text="Auto Normalize")
418             col.prop(toolsettings, "use_multipaint", text="Multi-Paint")
419
420         # Vertex Paint Mode #
421         elif context.vertex_paint_object and brush:
422             col = layout.column()
423             self.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
424             if settings.palette:
425                 col.template_palette(settings, "palette", color=True)
426             row = col.row(align=True)
427             self.prop_unified_color(row, context, brush, "color", text="")
428             self.prop_unified_color(row, context, brush, "secondary_color", text="")
429             row.separator()
430             row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
431
432             col.separator()
433             row = col.row(align=True)
434             self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
435             self.prop_unified_size(row, context, brush, "use_pressure_size")
436
437             row = col.row(align=True)
438             self.prop_unified_strength(row, context, brush, "strength", text="Strength")
439             self.prop_unified_strength(row, context, brush, "use_pressure_strength")
440
441             col.separator()
442             col.prop(brush, "vertex_tool", text="Blend")
443             col.prop(brush, "use_alpha")
444
445             if brush.vertex_tool != 'SMEAR':
446                 col.prop(brush, "use_accumulate")
447                 col.separator()
448
449             col.prop(brush, "use_frontface", text="Front Faces Only")
450             row = col.row()
451             row.prop(brush, "use_frontface_falloff", text="Falloff Angle")
452             sub = row.row()
453             sub.active = brush.use_frontface_falloff
454             sub.prop(brush, "falloff_angle", text="")
455
456             col.prop(brush, "use_projected")
457
458             col.separator()
459             col.template_ID(settings, "palette", new="palette.new")
460
461
462 class TEXTURE_UL_texpaintslots(UIList):
463     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
464         # mat = data
465
466         if self.layout_type in {'DEFAULT', 'COMPACT'}:
467             layout.prop(item, "name", text="", emboss=False, icon_value=icon)
468         elif self.layout_type == 'GRID':
469             layout.alignment = 'CENTER'
470             layout.label(text="")
471
472
473 class VIEW3D_MT_tools_projectpaint_uvlayer(Menu):
474     bl_label = "Clone Layer"
475
476     def draw(self, context):
477         layout = self.layout
478
479         for i, uv_layer in enumerate(context.active_object.data.uv_layers):
480             props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
481             props.data_path = "active_object.data.uv_layers.active_index"
482             props.value = i
483
484
485 class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
486     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
487     bl_label = "Texture Slots"
488
489     @classmethod
490     def poll(cls, context):
491         brush = context.tool_settings.image_paint.brush
492         ob = context.active_object
493         return (brush is not None and ob is not None)
494
495     def draw(self, context):
496         layout = self.layout
497         layout.use_property_split = True
498         layout.use_property_decorate = False
499
500         settings = context.tool_settings.image_paint
501
502         ob = context.active_object
503
504         layout.prop(settings, "mode", text="Mode")
505         layout.separator()
506
507         if settings.mode == 'MATERIAL':
508             if len(ob.material_slots) > 1:
509                 layout.template_list("MATERIAL_UL_matslots", "layers",
510                                      ob, "material_slots",
511                                      ob, "active_material_index", rows=2)
512             mat = ob.active_material
513             if mat and mat.texture_paint_images:
514                 row = layout.row()
515                 row.template_list("TEXTURE_UL_texpaintslots", "",
516                                   mat, "texture_paint_images",
517                                   mat, "paint_active_slot", rows=2)
518
519                 if mat.texture_paint_slots:
520                     slot = mat.texture_paint_slots[mat.paint_active_slot]
521                 else:
522                     slot = None
523
524                 have_image = slot is not None
525             else:
526                 row = layout.row()
527
528                 box = row.box()
529                 box.label(text="No Textures")
530                 have_image = False
531
532             sub = row.column(align=True)
533             sub.operator_menu_enum("paint.add_texture_paint_slot", "type", icon='ADD', text="")
534
535         elif settings.mode == 'IMAGE':
536             mesh = ob.data
537             uv_text = mesh.uv_layers.active.name if mesh.uv_layers.active else ""
538             layout.template_ID(settings, "canvas", new="image.new", open="image.open")
539             if settings.missing_uvs:
540                 layout.operator("paint.add_simple_uvs", icon='ADD', text="Add UVs")
541             else:
542                 layout.menu("VIEW3D_MT_tools_projectpaint_uvlayer", text=uv_text, translate=False)
543             have_image = settings.canvas is not None
544
545         if settings.missing_uvs:
546             layout.separator()
547             split = layout.split()
548             split.label(text="UV Map Needed", icon='INFO')
549             split.operator("paint.add_simple_uvs", icon='ADD', text="Add Simple UVs")
550         elif have_image:
551             layout.separator()
552             layout.operator("image.save_dirty", text="Save All Images", icon='FILE_TICK')
553
554 # TODO, move to space_view3d.py
555
556
557 class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
558     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
559     bl_label = "Mask"
560     bl_options = {'DEFAULT_CLOSED'}
561
562     @classmethod
563     def poll(cls, context):
564         brush = context.tool_settings.image_paint.brush
565         ob = context.active_object
566         return (brush is not None and ob is not None)
567
568     def draw_header(self, context):
569         ipaint = context.tool_settings.image_paint
570         self.layout.prop(ipaint, "use_stencil_layer", text="")
571
572     def draw(self, context):
573         layout = self.layout
574         layout.use_property_split = True
575         layout.use_property_decorate = False
576
577         toolsettings = context.tool_settings
578         ipaint = toolsettings.image_paint
579         ob = context.active_object
580         mesh = ob.data
581
582         col = layout.column()
583         col.active = ipaint.use_stencil_layer
584
585         stencil_text = mesh.uv_layer_stencil.name if mesh.uv_layer_stencil else ""
586         split = col.split(factor=0.5)
587         colsub = split.column()
588         colsub.alignment = 'RIGHT'
589         colsub.label(text="UV Layer")
590         split.column().menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False)
591
592         # todo this should be combinded into a single row
593         split = col.split(factor=0.5)
594         colsub = split.column()
595         colsub.alignment = 'RIGHT'
596         colsub.label(text="Stencil Image")
597         colsub = split.column()
598         colsub.template_ID(ipaint, "stencil_image", new="image.new", open="image.open")
599
600         row = col.row(align=True)
601         row.prop(ipaint, "stencil_color", text="Display Color")
602         row.prop(ipaint, "invert_stencil", text="", icon='IMAGE_ALPHA')
603
604
605 # TODO, move to space_view3d.py
606 class VIEW3D_PT_tools_brush_overlay(Panel, View3DPaintPanel):
607     bl_context = ".paint_common"  # dot on purpose (access from topbar)
608     bl_label = "Overlay"
609     bl_options = {'DEFAULT_CLOSED'}
610
611     @classmethod
612     def poll(cls, context):
613         settings = cls.paint_settings(context)
614         return (settings and
615                 settings.brush and
616                 (context.sculpt_object or
617                  context.vertex_paint_object or
618                  context.weight_paint_object or
619                  context.image_paint_object))
620
621     def draw(self, context):
622         layout = self.layout
623
624         settings = self.paint_settings(context)
625         brush = settings.brush
626         tex_slot = brush.texture_slot
627         tex_slot_mask = brush.mask_texture_slot
628
629         col = layout.column()
630
631         col.label(text="Curve:")
632
633         row = col.row(align=True)
634         row.prop(
635             brush,
636             "use_cursor_overlay",
637             text="",
638             toggle=True,
639             icon='RESTRICT_VIEW_OFF' if brush.use_cursor_overlay else 'RESTRICT_VIEW_ON',
640         )
641         sub = row.row(align=True)
642         sub.prop(brush, "cursor_overlay_alpha", text="Alpha")
643         sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
644
645         col.active = brush.brush_capabilities.has_overlay
646
647         if context.image_paint_object or context.sculpt_object or context.vertex_paint_object:
648             col.label(text="Texture:")
649             row = col.row(align=True)
650             if tex_slot.map_mode != 'STENCIL':
651                 row.prop(
652                     brush,
653                     "use_primary_overlay",
654                     text="",
655                     toggle=True,
656                     icon='RESTRICT_VIEW_OFF' if brush.use_primary_overlay else 'RESTRICT_VIEW_ON',
657                 )
658
659             sub = row.row(align=True)
660             sub.prop(brush, "texture_overlay_alpha", text="Alpha")
661             sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
662
663         if context.image_paint_object:
664             col.label(text="Mask Texture:")
665
666             row = col.row(align=True)
667             if tex_slot_mask.map_mode != 'STENCIL':
668                 row.prop(
669                     brush,
670                     "use_secondary_overlay",
671                     text="",
672                     toggle=True,
673                     icon='RESTRICT_VIEW_OFF' if brush.use_secondary_overlay else 'RESTRICT_VIEW_ON',
674                 )
675
676             sub = row.row(align=True)
677             sub.prop(brush, "mask_overlay_alpha", text="Alpha")
678             sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
679
680
681 # TODO, move to space_view3d.py
682 class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
683     bl_context = ".paint_common"  # dot on purpose (access from topbar)
684     bl_label = "Texture"
685     bl_options = {'DEFAULT_CLOSED'}
686
687     @classmethod
688     def poll(cls, context):
689         settings = cls.paint_settings(context)
690         return (settings and settings.brush and
691                 (context.sculpt_object or context.image_paint_object or context.vertex_paint_object))
692
693     def draw(self, context):
694         layout = self.layout
695
696         settings = self.paint_settings(context)
697         brush = settings.brush
698
699         col = layout.column()
700
701         col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
702
703         brush_texture_settings(col, brush, context.sculpt_object)
704
705
706 # TODO, move to space_view3d.py
707 class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel):
708     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
709     bl_label = "Texture Mask"
710     bl_options = {'DEFAULT_CLOSED'}
711
712     @classmethod
713     def poll(cls, context):
714         settings = cls.paint_settings(context)
715         return (settings and settings.brush and context.image_paint_object)
716
717     def draw(self, context):
718         layout = self.layout
719
720         brush = context.tool_settings.image_paint.brush
721
722         col = layout.column()
723
724         col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
725
726         brush_mask_texture_settings(col, brush)
727
728
729 # TODO, move to space_view3d.py
730 class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
731     bl_context = ".paint_common"  # dot on purpose (access from topbar)
732     bl_label = "Stroke"
733     bl_options = {'DEFAULT_CLOSED'}
734
735     @classmethod
736     def poll(cls, context):
737         settings = cls.paint_settings(context)
738         return (settings and
739                 settings.brush and
740                 (context.sculpt_object or
741                  context.vertex_paint_object or
742                  context.weight_paint_object or
743                  context.image_paint_object))
744
745     def draw(self, context):
746         layout = self.layout
747
748         settings = self.paint_settings(context)
749         brush = settings.brush
750         layout.use_property_split = True
751         layout.use_property_decorate = False
752
753         col = layout.column()
754
755         col.prop(brush, "stroke_method")
756
757         if brush.use_anchor:
758             col.separator()
759             col.prop(brush, "use_edge_to_edge", text="Edge To Edge")
760
761         if brush.use_airbrush:
762             col.separator()
763             col.prop(brush, "rate", text="Rate", slider=True)
764
765         if brush.use_space:
766             col.separator()
767             row = col.row(align=True)
768             row.prop(brush, "spacing", text="Spacing")
769             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
770
771         if brush.use_line or brush.use_curve:
772             col.separator()
773             row = col.row(align=True)
774             row.prop(brush, "spacing", text="Spacing")
775
776         if brush.use_curve:
777             col.separator()
778             col.template_ID(brush, "paint_curve", new="paintcurve.new")
779             col.operator("paintcurve.draw")
780
781         if context.sculpt_object:
782             if brush.sculpt_capabilities.has_jitter:
783                 col.separator()
784
785                 row = col.row(align=True)
786                 if brush.use_relative_jitter:
787                     row.prop(brush, "jitter", slider=True)
788                 else:
789                     row.prop(brush, "jitter_absolute")
790                 row.prop(brush, "use_relative_jitter", icon_only=True)
791                 row.prop(brush, "use_pressure_jitter", toggle=True, text="")
792
793             if brush.sculpt_capabilities.has_smooth_stroke:
794                 col = layout.column()
795                 col.separator()
796
797                 col.prop(brush, "use_smooth_stroke")
798
799                 sub = col.column()
800                 sub.active = brush.use_smooth_stroke
801                 sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
802                 sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
803         else:
804             col.separator()
805
806             row = col.row(align=True)
807             row.prop(brush, "use_relative_jitter", icon_only=True)
808             if brush.use_relative_jitter:
809                 row.prop(brush, "jitter", slider=True)
810             else:
811                 row.prop(brush, "jitter_absolute")
812             row.prop(brush, "use_pressure_jitter", toggle=True, text="")
813
814             col = layout.column()
815             col.separator()
816
817             if brush.brush_capabilities.has_smooth_stroke:
818                 col.prop(brush, "use_smooth_stroke")
819
820                 sub = col.column()
821                 sub.active = brush.use_smooth_stroke
822                 sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
823                 sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
824
825         layout.prop(settings, "input_samples")
826
827
828 # TODO, move to space_view3d.py
829 class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel):
830     bl_context = ".paint_common"  # dot on purpose (access from topbar)
831     bl_label = "Curve"
832     bl_options = {'DEFAULT_CLOSED'}
833
834     @classmethod
835     def poll(cls, context):
836         settings = cls.paint_settings(context)
837         return (settings and settings.brush and settings.brush.curve)
838
839     def draw(self, context):
840         layout = self.layout
841
842         settings = self.paint_settings(context)
843
844         brush = settings.brush
845
846         layout.template_curve_mapping(brush, "curve", brush=True)
847
848         col = layout.column(align=True)
849         row = col.row(align=True)
850         row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
851         row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
852         row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
853         row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
854         row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
855         row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
856
857
858 # TODO, move to space_view3d.py
859 class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
860     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
861     bl_label = "Dyntopo"
862     bl_options = {'DEFAULT_CLOSED'}
863     bl_ui_units_x = 12
864
865     @classmethod
866     def poll(cls, context):
867         return (context.sculpt_object and context.tool_settings.sculpt)
868
869     def draw_header(self, context):
870         is_popover = self.is_popover
871         layout = self.layout
872         layout.operator(
873             "sculpt.dynamic_topology_toggle",
874             icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
875             text="",
876             emboss=is_popover,
877         )
878
879     def draw(self, context):
880         layout = self.layout
881         layout.use_property_split = True
882         layout.use_property_decorate = False
883
884         toolsettings = context.tool_settings
885         sculpt = toolsettings.sculpt
886         settings = self.paint_settings(context)
887         brush = settings.brush
888
889         col = layout.column()
890         col.active = context.sculpt_object.use_dynamic_topology_sculpting
891
892         sub = col.column()
893         sub.active = (brush and brush.sculpt_tool != 'MASK')
894         if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
895             row = sub.row(align=True)
896             row.prop(sculpt, "constant_detail_resolution")
897             row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
898         elif (sculpt.detail_type_method == 'BRUSH'):
899             sub.prop(sculpt, "detail_percent")
900         else:
901             sub.prop(sculpt, "detail_size")
902         sub.prop(sculpt, "detail_refine_method", text="Refine Method")
903         sub.prop(sculpt, "detail_type_method", text="Detailing")
904
905         col.prop(sculpt, "use_smooth_shading")
906
907         col.separator()
908
909         col.prop(sculpt, "symmetrize_direction")
910         col.operator("sculpt.symmetrize")
911         col.operator("sculpt.optimize")
912         if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
913             col.operator("sculpt.detail_flood_fill")
914
915
916 # TODO, move to space_view3d.py
917 class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
918     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
919     bl_label = "Options"
920     bl_options = {'DEFAULT_CLOSED'}
921
922     @classmethod
923     def poll(cls, context):
924         return (context.sculpt_object and context.tool_settings.sculpt)
925
926     def draw(self, context):
927         layout = self.layout
928
929         toolsettings = context.tool_settings
930         sculpt = toolsettings.sculpt
931         capabilities = sculpt.brush.sculpt_capabilities
932
933         col = layout.column(align=True)
934         col.active = capabilities.has_gravity
935         col.label(text="Gravity:")
936         col.prop(sculpt, "gravity", slider=True, text="Factor")
937         col.prop(sculpt, "gravity_object")
938         col.separator()
939
940         layout.prop(sculpt, "use_threaded", text="Threaded Sculpt")
941         layout.prop(sculpt, "show_low_resolution")
942         layout.prop(sculpt, "use_deform_only")
943         layout.prop(sculpt, "show_diffuse_color")
944         layout.prop(sculpt, "show_mask")
945
946         self.unified_paint_settings(layout, context)
947
948
949 # TODO, move to space_view3d.py
950 class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
951     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
952     bl_label = "Symmetry/Lock"
953     bl_options = {'DEFAULT_CLOSED'}
954
955     @classmethod
956     def poll(cls, context):
957         return (context.sculpt_object and context.tool_settings.sculpt)
958
959     def draw(self, context):
960         layout = self.layout
961
962         sculpt = context.tool_settings.sculpt
963
964         split = layout.split()
965
966         col = split.column()
967         col.alignment = 'RIGHT'
968         col.label(text="Mirror")
969
970         col = split.column()
971
972         row = col.row(align=True)
973         row.prop(sculpt, "use_symmetry_x", text="X", toggle=True)
974         row.prop(sculpt, "use_symmetry_y", text="Y", toggle=True)
975         row.prop(sculpt, "use_symmetry_z", text="Z", toggle=True)
976
977         split = layout.split()
978
979         col = split.column()
980         col.alignment = 'RIGHT'
981         col.label(text="Lock")
982
983         col = split.column()
984
985         row = col.row(align=True)
986         row.prop(sculpt, "lock_x", text="X", toggle=True)
987         row.prop(sculpt, "lock_y", text="Y", toggle=True)
988         row.prop(sculpt, "lock_z", text="Z", toggle=True)
989
990         split = layout.split()
991
992         col = split.column()
993         col.alignment = 'RIGHT'
994         col.label(text="Tiling")
995
996         col = split.column()
997
998         row = col.row(align=True)
999         row.prop(sculpt, "tile_x", text="X", toggle=True)
1000         row.prop(sculpt, "tile_y", text="Y", toggle=True)
1001         row.prop(sculpt, "tile_z", text="Z", toggle=True)
1002
1003         layout.use_property_split = True
1004         layout.use_property_decorate = False
1005
1006         layout.prop(sculpt, "use_symmetry_feather", text="Feather")
1007         layout.column().prop(sculpt, "radial_symmetry", text="Radial")
1008         layout.column().prop(sculpt, "tile_offset", text="Tile Offset")
1009
1010
1011 # TODO, move to space_view3d.py
1012 class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel):
1013     bl_context = ".paint_common"  # dot on purpose (access from topbar)
1014     bl_label = "Appearance"
1015     bl_parent_id = "VIEW3D_PT_tools_brush_overlay"
1016     bl_options = {'DEFAULT_CLOSED'}
1017
1018     @classmethod
1019     def poll(cls, context):
1020         settings = cls.paint_settings(context)
1021         return (settings is not None) and (not isinstance(settings, bpy.types.ParticleEdit))
1022
1023     def draw(self, context):
1024         layout = self.layout
1025
1026         settings = self.paint_settings(context)
1027         brush = settings.brush
1028
1029         if brush is None:  # unlikely but can happen
1030             layout.label(text="Brush Unset")
1031             return
1032
1033         col = layout.column()
1034         col.prop(settings, "show_brush")
1035
1036         sub = col.column()
1037         sub.active = settings.show_brush
1038
1039         if context.sculpt_object and context.tool_settings.sculpt:
1040             if brush.sculpt_capabilities.has_secondary_color:
1041                 sub.row().prop(brush, "cursor_color_add", text="Add")
1042                 sub.row().prop(brush, "cursor_color_subtract", text="Subtract")
1043             else:
1044                 sub.prop(brush, "cursor_color_add", text="")
1045         else:
1046             sub.prop(brush, "cursor_color_add", text="")
1047
1048         col.separator()
1049
1050         col = col.column(align=True)
1051         col.prop(brush, "use_custom_icon")
1052         sub = col.column()
1053         sub.active = brush.use_custom_icon
1054         sub.prop(brush, "icon_filepath", text="")
1055
1056 # ********** default tools for weight-paint ****************
1057
1058
1059 # TODO, move to space_view3d.py
1060 class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
1061     bl_context = ".weightpaint"
1062     bl_options = {'DEFAULT_CLOSED'}
1063     bl_label = "Symmetry"
1064
1065     def draw(self, context):
1066         layout = self.layout
1067         toolsettings = context.tool_settings
1068         wpaint = toolsettings.weight_paint
1069         draw_vpaint_symmetry(layout, wpaint)
1070
1071
1072 # TODO, move to space_view3d.py
1073 class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
1074     bl_context = ".weightpaint"
1075     bl_label = "Options"
1076
1077     def draw(self, context):
1078         layout = self.layout
1079
1080         tool_settings = context.tool_settings
1081         wpaint = tool_settings.weight_paint
1082
1083         col = layout.column()
1084         col.prop(wpaint, "use_group_restrict")
1085
1086         obj = context.weight_paint_object
1087         if obj.type == 'MESH':
1088             mesh = obj.data
1089             col.prop(mesh, "use_mirror_x")
1090             row = col.row()
1091             row.active = mesh.use_mirror_x
1092             row.prop(mesh, "use_mirror_topology")
1093
1094         self.unified_paint_settings(col, context)
1095
1096 # ********** default tools for vertex-paint ****************
1097
1098
1099 # TODO, move to space_view3d.py
1100 class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel):
1101     bl_context = ".vertexpaint"  # dot on purpose (access from topbar)
1102     bl_label = "Options"
1103
1104     def draw(self, context):
1105         layout = self.layout
1106
1107         col = layout.column()
1108
1109         self.unified_paint_settings(col, context)
1110
1111
1112 # TODO, move to space_view3d.py
1113 class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
1114     bl_context = ".vertexpaint"  # dot on purpose (access from topbar)
1115     bl_options = {'DEFAULT_CLOSED'}
1116     bl_label = "Symmetry"
1117
1118     def draw(self, context):
1119         layout = self.layout
1120         toolsettings = context.tool_settings
1121         vpaint = toolsettings.vertex_paint
1122         draw_vpaint_symmetry(layout, vpaint)
1123
1124
1125 # ********** default tools for texture-paint ****************
1126
1127
1128 # TODO, move to space_view3d.py
1129 class VIEW3D_PT_tools_imagepaint_external(Panel, View3DPaintPanel):
1130     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1131     bl_label = "External"
1132     bl_options = {'DEFAULT_CLOSED'}
1133
1134     def draw(self, context):
1135         layout = self.layout
1136
1137         toolsettings = context.tool_settings
1138         ipaint = toolsettings.image_paint
1139
1140         col = layout.column()
1141         row = col.split(factor=0.55, align=True)
1142         row.operator("image.project_edit", text="Quick Edit")
1143         row.operator("image.project_apply", text="Apply")
1144
1145         col.row().prop(ipaint, "screen_grab_size", text="")
1146
1147         col.operator("paint.project_image", text="Apply Camera Image")
1148
1149
1150 # TODO, move to space_view3d.py
1151 class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
1152     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1153     bl_label = "Symmetry"
1154     bl_options = {'DEFAULT_CLOSED'}
1155
1156     def draw(self, context):
1157         layout = self.layout
1158
1159         toolsettings = context.tool_settings
1160         ipaint = toolsettings.image_paint
1161
1162         split = layout.split()
1163
1164         col = split.column()
1165         col.alignment = 'RIGHT'
1166         col.label(text="Mirror")
1167
1168         col = split.column()
1169
1170         row = col.row(align=True)
1171         row.prop(ipaint, "use_symmetry_x", text="X", toggle=True)
1172         row.prop(ipaint, "use_symmetry_y", text="Y", toggle=True)
1173         row.prop(ipaint, "use_symmetry_z", text="Z", toggle=True)
1174
1175
1176 # TODO, move to space_view3d.py
1177 class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
1178     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1179     bl_label = "Project Paint"
1180     bl_options = {'DEFAULT_CLOSED'}
1181
1182     @classmethod
1183     def poll(cls, context):
1184         brush = context.tool_settings.image_paint.brush
1185         return (brush is not None)
1186
1187     def draw(self, context):
1188         layout = self.layout
1189
1190         toolsettings = context.tool_settings
1191         ipaint = toolsettings.image_paint
1192
1193         col = layout.column()
1194
1195         col.prop(ipaint, "use_occlude")
1196         col.prop(ipaint, "use_backface_culling")
1197
1198         row = layout.row()
1199         row.prop(ipaint, "use_normal_falloff")
1200
1201         sub = row.row()
1202         sub.active = (ipaint.use_normal_falloff)
1203         sub.prop(ipaint, "normal_angle", text="")
1204
1205         layout.prop(ipaint, "use_cavity")
1206         if ipaint.use_cavity:
1207             layout.template_curve_mapping(ipaint, "cavity_curve", brush=True)
1208
1209         layout.prop(ipaint, "seam_bleed")
1210         layout.prop(ipaint, "dither")
1211         self.unified_paint_settings(layout, context)
1212
1213
1214 # TODO, move to space_view3d.py
1215 class VIEW3D_PT_imagepaint_options(View3DPaintPanel):
1216     bl_label = "Options"
1217
1218     @classmethod
1219     def poll(cls, context):
1220         return (context.image_paint_object and context.tool_settings.image_paint)
1221
1222     def draw(self, context):
1223         layout = self.layout
1224
1225         col = layout.column()
1226         self.unified_paint_settings(col, context)
1227
1228
1229 class VIEW3D_MT_tools_projectpaint_stencil(Menu):
1230     bl_label = "Mask Layer"
1231
1232     def draw(self, context):
1233         layout = self.layout
1234         for i, uv_layer in enumerate(context.active_object.data.uv_layers):
1235             props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
1236             props.data_path = "active_object.data.uv_layer_stencil_index"
1237             props.value = i
1238
1239
1240 # TODO, move to space_view3d.py
1241 class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
1242     """Default tools for particle mode"""
1243     bl_context = ".particlemode"
1244     bl_label = "Options"
1245
1246     def draw(self, context):
1247         layout = self.layout
1248
1249         pe = context.tool_settings.particle_edit
1250         ob = pe.object
1251
1252         layout.prop(pe, "type", text="")
1253
1254         ptcache = None
1255
1256         if pe.type == 'PARTICLES':
1257             if ob.particle_systems:
1258                 if len(ob.particle_systems) > 1:
1259                     layout.template_list("UI_UL_list", "particle_systems", ob, "particle_systems",
1260                                          ob.particle_systems, "active_index", rows=2, maxrows=3)
1261
1262                 ptcache = ob.particle_systems.active.point_cache
1263         else:
1264             for md in ob.modifiers:
1265                 if md.type == pe.type:
1266                     ptcache = md.point_cache
1267
1268         if ptcache and len(ptcache.point_caches) > 1:
1269             layout.template_list("UI_UL_list", "particles_point_caches", ptcache, "point_caches",
1270                                  ptcache.point_caches, "active_index", rows=2, maxrows=3)
1271
1272         if not pe.is_editable:
1273             layout.label(text="Point cache must be baked")
1274             layout.label(text="in memory to enable editing!")
1275
1276         col = layout.column(align=True)
1277         if pe.is_hair:
1278             col.active = pe.is_editable
1279             col.prop(pe, "use_emitter_deflect", text="Deflect Emitter")
1280             sub = col.row(align=True)
1281             sub.active = pe.use_emitter_deflect
1282             sub.prop(pe, "emitter_distance", text="Distance")
1283
1284         col = layout.column(align=True)
1285         col.active = pe.is_editable
1286         col.label(text="Keep:")
1287         col.prop(pe, "use_preserve_length", text="Lengths")
1288         col.prop(pe, "use_preserve_root", text="Root")
1289         if not pe.is_hair:
1290             col.label(text="Correct:")
1291             col.prop(pe, "use_auto_velocity", text="Velocity")
1292         col.prop(ob.data, "use_mirror_x")
1293
1294         col.prop(pe, "shape_object")
1295         col.operator("particle.shape_cut")
1296
1297         col = layout.column(align=True)
1298         col.active = pe.is_editable
1299         col.label(text="Display:")
1300         col.prop(pe, "display_step", text="Path Steps")
1301         if pe.is_hair:
1302             col.prop(pe, "show_particles", text="Children")
1303         else:
1304             if pe.type == 'PARTICLES':
1305                 col.prop(pe, "show_particles", text="Particles")
1306             col.prop(pe, "use_fade_time")
1307             sub = col.row(align=True)
1308             sub.active = pe.use_fade_time
1309             sub.prop(pe, "fade_frames", slider=True)
1310
1311
1312 class VIEW3D_PT_tools_normal(View3DPanel, Panel):
1313     bl_category = ""
1314     bl_context = ".mesh_edit"
1315     bl_label = "Normal Tools"
1316
1317     def draw(self, context):
1318         layout = self.layout
1319         toolsettings = context.tool_settings
1320
1321         col = layout.column(align=True)
1322         col.label(text="Normal Vector")
1323         col.prop(toolsettings, "normal_vector", text="")
1324
1325         layout.separator()
1326         layout.label(text="Face Strength")
1327         layout.prop(toolsettings, "face_strength", text="")
1328
1329         col = layout.column(align=True)
1330
1331
1332 # ********** grease pencil object tool panels ****************
1333
1334 # Grease Pencil drawing brushes
1335 class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
1336     bl_context = ".greasepencil_paint"
1337     bl_label = "Brush"
1338
1339     @classmethod
1340     def poll(cls, context):
1341         is_3d_view = context.space_data.type == 'VIEW_3D'
1342         if is_3d_view:
1343             if context.gpencil_data is None:
1344                 return False
1345
1346             gpd = context.gpencil_data
1347             return bool(gpd.is_stroke_paint_mode)
1348         else:
1349             return True
1350
1351     @staticmethod
1352     def draw(self, context):
1353         layout = self.layout
1354         layout.use_property_split = True
1355         layout.use_property_decorate = False
1356
1357         ts = context.scene.tool_settings
1358         settings = ts.gpencil_paint
1359
1360         row = layout.row()
1361         col = row.column()
1362         col.template_ID_preview(settings, "brush", new="brush.add_gpencil", rows=3, cols=8)
1363
1364         col = row.column()
1365         brush = context.active_gpencil_brush
1366         gp_settings = brush.gpencil_settings
1367
1368         sub = col.column(align=True)
1369         sub.operator("gpencil.brush_presets_create", icon='HELP', text="")
1370
1371         if brush is not None:
1372             # XXX: Items in "sub" currently show up beside the brush selector in a separate column
1373             if gp_settings.gpencil_brush_type == 'ERASE':
1374                 sub.prop(gp_settings, "default_eraser", text="")
1375
1376             # Brush details
1377             if gp_settings.gpencil_brush_type == 'ERASE':
1378                 row = layout.row(align=True)
1379                 row.prop(brush, "size", text="Radius")
1380                 row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
1381
1382                 if gp_settings.eraser_mode == 'SOFT':
1383                     row = layout.row(align=True)
1384                     row.prop(gp_settings, "pen_strength", slider=True)
1385                     row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
1386                     row = layout.row(align=True)
1387                     row.prop(gp_settings, "eraser_strength_factor")
1388                     row = layout.row(align=True)
1389                     row.prop(gp_settings, "eraser_thickness_factor")
1390             elif gp_settings.gpencil_brush_type == 'FILL':
1391                 col = layout.column(align=True)
1392                 col.prop(gp_settings, "gpencil_fill_leak", text="Leak Size")
1393                 col.separator()
1394                 col.prop(brush, "size", text="Thickness")
1395                 col.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify")
1396
1397                 col = layout.row(align=True)
1398                 col.template_ID(gp_settings, "material")
1399
1400                 row = layout.row(align=True)
1401                 row.prop(gp_settings, "gpencil_fill_draw_mode", text="Boundary Draw Mode")
1402                 row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID')
1403
1404                 col = layout.column(align=True)
1405                 col.enabled = gp_settings.gpencil_fill_draw_mode != 'STROKE'
1406                 col.prop(gp_settings, "gpencil_fill_hide", text="Ignore Transparent Strokes")
1407                 sub = col.row(align=True)
1408                 sub.enabled = gp_settings.gpencil_fill_hide
1409                 sub.prop(gp_settings, "gpencil_fill_threshold", text="Threshold")
1410             else:  # bgpsettings.gpencil_brush_type == 'DRAW':
1411                 row = layout.row(align=True)
1412                 row.prop(brush, "size", text="Radius")
1413                 row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
1414                 row = layout.row(align=True)
1415                 row.prop(gp_settings, "pen_strength", slider=True)
1416                 row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
1417
1418                 row = layout.row(align=True)
1419                 row.template_ID(gp_settings, "material")
1420
1421
1422 # Grease Pencil drawing brushes options
1423 class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
1424     bl_context = ".greasepencil_paint"
1425     bl_label = "Options"
1426     bl_options = {'DEFAULT_CLOSED'}
1427
1428     @classmethod
1429     def poll(cls, context):
1430         brush = context.active_gpencil_brush
1431         gp_settings = brush.gpencil_settings
1432
1433         return brush is not None and gp_settings.gpencil_brush_type != 'ERASE'
1434
1435     def draw_header_preset(self, context):
1436         VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout)
1437
1438     @staticmethod
1439     def draw(self, context):
1440         layout = self.layout
1441         layout.use_property_split = True
1442         layout.use_property_decorate = False
1443
1444         brush = context.active_gpencil_brush
1445         gp_settings = brush.gpencil_settings
1446
1447         if brush is not None:
1448             col = layout.column(align=True)
1449             col.prop(gp_settings, "input_samples")
1450             col.separator()
1451
1452             col.prop(gp_settings, "active_smooth_factor")
1453             col.separator()
1454
1455             col.prop(gp_settings, "angle", slider=True)
1456             col.prop(gp_settings, "angle_factor", text="Factor", slider=True)
1457             col.separator()
1458
1459
1460 class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
1461     bl_context = ".greasepencil_paint"
1462     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
1463     bl_label = "Stabilizer"
1464     bl_options = {'DEFAULT_CLOSED'}
1465
1466     @classmethod
1467     def poll(cls, context):
1468         brush = context.active_gpencil_brush
1469         gp_settings = brush.gpencil_settings
1470
1471         return brush is not None and gp_settings.gpencil_brush_type == 'DRAW'
1472
1473     def draw_header(self, context):
1474         brush = context.active_gpencil_brush
1475         gp_settings = brush.gpencil_settings
1476         self.layout.prop(gp_settings, "use_stabilizer", text="")
1477
1478     @staticmethod
1479     def draw(self, context):
1480         layout = self.layout
1481         layout.use_property_split = True
1482         layout.use_property_decorate = False
1483
1484         brush = context.active_gpencil_brush
1485         gp_settings = brush.gpencil_settings
1486         layout.active = gp_settings.use_stabilizer
1487
1488         layout.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
1489         layout.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
1490
1491
1492 class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
1493     bl_context = ".greasepencil_paint"
1494     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
1495     bl_label = "Post-processing Settings"
1496     bl_options = {'DEFAULT_CLOSED'}
1497
1498     @classmethod
1499     def poll(cls, context):
1500         brush = context.active_gpencil_brush
1501         gp_settings = brush.gpencil_settings
1502
1503         return brush is not None and gp_settings.gpencil_brush_type != 'ERASE'
1504
1505     def draw_header(self, context):
1506         brush = context.active_gpencil_brush
1507         gp_settings = brush.gpencil_settings
1508         self.layout.prop(gp_settings, "enable_settings", text="")
1509
1510     @staticmethod
1511     def draw(self, context):
1512         layout = self.layout
1513         layout.use_property_split = True
1514         layout.use_property_decorate = False
1515
1516         brush = context.active_gpencil_brush
1517         gp_settings = brush.gpencil_settings
1518         layout.active = gp_settings.enable_settings
1519
1520         col = layout.column(align=True)
1521         col.prop(gp_settings, "pen_smooth_factor")
1522         col.prop(gp_settings, "pen_smooth_steps")
1523
1524         col = layout.column(align=True)
1525         col.prop(gp_settings, "pen_thick_smooth_factor")
1526         col.prop(gp_settings, "pen_thick_smooth_steps", text="Iterations")
1527
1528         col = layout.column(align=True)
1529         col.prop(gp_settings, "pen_subdivision_steps")
1530         col.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
1531
1532
1533 class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
1534     bl_context = ".greasepencil_paint"
1535     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
1536     bl_label = "Random Settings"
1537     bl_options = {'DEFAULT_CLOSED'}
1538
1539     @classmethod
1540     def poll(cls, context):
1541         brush = context.active_gpencil_brush
1542         gp_settings = brush.gpencil_settings
1543
1544         return brush is not None and gp_settings.gpencil_brush_type != 'ERASE'
1545
1546     def draw_header(self, context):
1547         brush = context.active_gpencil_brush
1548         gp_settings = brush.gpencil_settings
1549         self.layout.prop(gp_settings, "enable_random", text="")
1550
1551     @staticmethod
1552     def draw(self, context):
1553         layout = self.layout
1554         layout.use_property_split = True
1555         layout.use_property_decorate = False
1556
1557         brush = context.active_gpencil_brush
1558         gp_settings = brush.gpencil_settings
1559         layout.active = gp_settings.enable_random
1560
1561         layout.prop(gp_settings, "random_pressure", text="Pressure", slider=True)
1562         layout.prop(gp_settings, "random_strength", text="Strength", slider=True)
1563         layout.prop(gp_settings, "uv_random", text="UV", slider=True)
1564
1565         row = layout.row(align=True)
1566         row.prop(gp_settings, "pen_jitter", slider=True)
1567         row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
1568
1569
1570 # Grease Pencil drawingcurves
1571 class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel):
1572     bl_context = ".greasepencil_paint"
1573     bl_label = "Curves"
1574     bl_options = {'DEFAULT_CLOSED'}
1575
1576     @classmethod
1577     def poll(cls, context):
1578         brush = context.active_gpencil_brush
1579         gp_settings = brush.gpencil_settings
1580
1581         return brush is not None and gp_settings.gpencil_brush_type != 'ERASE'
1582
1583     @staticmethod
1584     def draw(self, context):
1585         layout = self.layout
1586         layout.use_property_split = True
1587
1588         brush = context.active_gpencil_brush
1589         gp_settings = brush.gpencil_settings
1590
1591         # Brush
1592         layout.label(text="Sensitivity")
1593         layout.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True)
1594
1595         layout.label(text="Strength")
1596         layout.template_curve_mapping(gp_settings, "curve_strength", brush=True)
1597
1598         layout.label(text="Jitter")
1599         layout.template_curve_mapping(gp_settings, "curve_jitter", brush=True)
1600
1601
1602 # Grease Pencil create shapes
1603 class VIEW3D_PT_tools_grease_pencil_shapes(View3DPanel, Panel):
1604     bl_space_type = 'VIEW_3D'
1605     bl_region_type = 'HEADER'
1606     bl_label = "Shapes"
1607
1608     @classmethod
1609     def poll(cls, context):
1610         ob = context.active_object
1611         return ob and ob.type == 'GPENCIL'
1612
1613     @staticmethod
1614     def draw(self, context):
1615         layout = self.layout
1616         layout.use_property_split = True
1617
1618         col = layout.column(align=True)
1619         col.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE'
1620         col.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX'
1621         col.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE'
1622
1623         layout.operator("object.gpencil_add", text="Monkey", icon='MONKEY').type = 'MONKEY'
1624
1625
1626 # Grease Pencil stroke editing tools
1627 class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
1628     bl_space_type = 'VIEW_3D'
1629
1630
1631 # Grease Pencil stroke interpolation tools
1632 class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
1633     bl_space_type = 'VIEW_3D'
1634     bl_region_type = 'HEADER'
1635     bl_label = "Interpolate"
1636
1637     @classmethod
1638     def poll(cls, context):
1639         if context.gpencil_data is None:
1640             return False
1641
1642         gpd = context.gpencil_data
1643         return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
1644
1645     @staticmethod
1646     def draw(self, context):
1647         layout = self.layout
1648         settings = context.tool_settings.gpencil_interpolate
1649
1650         col = layout.column(align=True)
1651         col.label(text="Interpolate Strokes")
1652         col.operator("gpencil.interpolate", text="Interpolate")
1653         col.operator("gpencil.interpolate_sequence", text="Sequence")
1654         col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns")
1655
1656         col = layout.column(align=True)
1657         col.label(text="Options:")
1658         col.prop(settings, "interpolate_all_layers")
1659         col.prop(settings, "interpolate_selected_only")
1660
1661         col = layout.column(align=True)
1662         col.label(text="Sequence Options:")
1663         col.prop(settings, "type")
1664         if settings.type == 'CUSTOM':
1665             # TODO: Options for loading/saving curve presets?
1666             col.template_curve_mapping(settings, "interpolation_curve", brush=True)
1667         elif settings.type != 'LINEAR':
1668             col.prop(settings, "easing")
1669
1670             if settings.type == 'BACK':
1671                 layout.prop(settings, "back")
1672             elif setting.type == 'ELASTIC':
1673                 sub = layout.column(align=True)
1674                 sub.prop(settings, "amplitude")
1675                 sub.prop(settings, "period")
1676
1677
1678 # Grease Pencil stroke sculpting tools
1679 class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, View3DPanel, Panel):
1680     bl_context = ".greasepencil_sculpt"
1681     bl_category = "Tools"
1682     bl_label = "Brush"
1683
1684
1685 # Grease Pencil weight painting tools
1686 class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel):
1687     bl_context = ".greasepencil_weight"
1688     bl_category = "Tools"
1689     bl_label = "Brush"
1690
1691     @staticmethod
1692     def draw(self, context):
1693         layout = self.layout
1694         layout.use_property_split = True
1695         layout.use_property_decorate = False
1696
1697         settings = context.tool_settings.gpencil_sculpt
1698         brush = settings.brush
1699
1700         layout.template_icon_view(settings, "weight_tool", show_labels=True)
1701
1702         col = layout.column()
1703         col.prop(brush, "size", slider=True)
1704         row = col.row(align=True)
1705         row.prop(brush, "strength", slider=True)
1706         row.prop(brush, "use_pressure_strength", text="")
1707
1708         col.prop(brush, "use_falloff")
1709
1710
1711 # Grease Pencil Brush Appeareance (one for each mode)
1712 class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
1713     bl_context = ".greasepencil_paint"
1714     bl_label = "Appearance"
1715
1716
1717 class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
1718     bl_context = ".greasepencil_sculpt"
1719     bl_label = "Appearance"
1720
1721
1722 class VIEW3D_PT_tools_grease_pencil_sculpt_options(GreasePencilSculptOptionsPanel, View3DPanel, Panel):
1723     bl_context = ".greasepencil_sculpt"
1724     bl_label = "Sculpt Strokes"
1725     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt'
1726
1727
1728 class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
1729     bl_context = ".greasepencil_weight"
1730     bl_label = "Appearance"
1731
1732
1733 class VIEW3D_PT_gpencil_brush_presets(PresetMenu):
1734     """Brush settings"""
1735     bl_label = "Brush Presets"
1736     preset_subdir = "gpencil_brush"
1737     preset_operator = "script.execute_preset"
1738     preset_add_operator = "scene.gpencil_brush_preset_add"
1739
1740
1741 classes = (
1742     VIEW3D_PT_tools_meshedit_options,
1743     VIEW3D_PT_tools_curveedit_options_stroke,
1744     VIEW3D_PT_tools_armatureedit_options,
1745     VIEW3D_PT_tools_posemode_options,
1746     VIEW3D_PT_slots_projectpaint,
1747     VIEW3D_PT_tools_brush,
1748     TEXTURE_UL_texpaintslots,
1749     VIEW3D_MT_tools_projectpaint_uvlayer,
1750     VIEW3D_PT_stencil_projectpaint,
1751     VIEW3D_PT_tools_brush_overlay,
1752     VIEW3D_PT_tools_brush_texture,
1753     VIEW3D_PT_tools_mask_texture,
1754     VIEW3D_PT_tools_brush_stroke,
1755     VIEW3D_PT_tools_brush_curve,
1756     VIEW3D_PT_sculpt_dyntopo,
1757     VIEW3D_PT_sculpt_options,
1758     VIEW3D_PT_sculpt_symmetry,
1759     VIEW3D_PT_tools_brush_appearance,
1760     VIEW3D_PT_tools_weightpaint_symmetry,
1761     VIEW3D_PT_tools_weightpaint_options,
1762     VIEW3D_PT_tools_vertexpaint,
1763     VIEW3D_PT_tools_vertexpaint_symmetry,
1764     VIEW3D_PT_tools_imagepaint_external,
1765     VIEW3D_PT_tools_imagepaint_symmetry,
1766     VIEW3D_PT_tools_projectpaint,
1767     VIEW3D_MT_tools_projectpaint_stencil,
1768     VIEW3D_PT_tools_particlemode,
1769
1770     VIEW3D_PT_gpencil_brush_presets,
1771     VIEW3D_PT_tools_grease_pencil_brush,
1772     VIEW3D_PT_tools_grease_pencil_brush_option,
1773     VIEW3D_PT_tools_grease_pencil_brush_settings,
1774     VIEW3D_PT_tools_grease_pencil_brush_stabilizer,
1775     VIEW3D_PT_tools_grease_pencil_brush_random,
1776     VIEW3D_PT_tools_grease_pencil_brushcurves,
1777     VIEW3D_PT_tools_grease_pencil_shapes,
1778     VIEW3D_PT_tools_grease_pencil_sculpt,
1779     VIEW3D_PT_tools_grease_pencil_weight_paint,
1780     VIEW3D_PT_tools_grease_pencil_paint_appearance,
1781     VIEW3D_PT_tools_grease_pencil_sculpt_options,
1782     VIEW3D_PT_tools_grease_pencil_sculpt_appearance,
1783     VIEW3D_PT_tools_grease_pencil_weight_appearance,
1784     VIEW3D_PT_tools_grease_pencil_interpolate,
1785     VIEW3D_PT_tools_normal,
1786 )
1787
1788 if __name__ == "__main__":  # only for live edit.
1789     from bpy.utils import register_class
1790     for cls in classes:
1791         register_class(cls)