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