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