Pose brush: Smooth Iterations Brush Property
[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 from bpy.types import Menu, Panel, UIList
21 from bl_ui.properties_grease_pencil_common import (
22     GreasePencilStrokeEditPanel,
23     GreasePencilStrokeSculptPanel,
24     GreasePencilSculptOptionsPanel,
25     GreasePencilAppearancePanel,
26 )
27 from bl_ui.properties_paint_common import (
28     UnifiedPaintPanel,
29     brush_mask_texture_settings,
30     brush_texpaint_common,
31     brush_texpaint_common_color,
32     brush_texpaint_common_gradient,
33     brush_texpaint_common_clone,
34     brush_texpaint_common_options,
35     brush_texture_settings,
36 )
37 from bl_ui.utils import PresetPanel
38
39
40 class VIEW3D_MT_brush_context_menu(Menu):
41     bl_label = "Material Specials"
42
43     def draw(self, context):
44         layout = self.layout
45
46         settings = UnifiedPaintPanel.paint_settings(context)
47         brush = getattr(settings, "brush", None)
48
49         # skip if no active brush
50         if not brush:
51             layout.label(text="No Brushes currently available", icon='INFO')
52             return
53
54         # brush paint modes
55         layout.menu("VIEW3D_MT_brush_paint_modes")
56
57         # brush tool
58
59         if context.image_paint_object:
60             layout.prop_menu_enum(brush, "image_tool")
61         elif context.vertex_paint_object:
62             layout.prop_menu_enum(brush, "vertex_tool")
63         elif context.weight_paint_object:
64             layout.prop_menu_enum(brush, "weight_tool")
65         elif context.sculpt_object:
66             layout.prop_menu_enum(brush, "sculpt_tool")
67             layout.operator("brush.reset")
68
69
70 class VIEW3D_MT_brush_context_menu_paint_modes(Menu):
71     bl_label = "Enabled Modes"
72
73     def draw(self, context):
74         layout = self.layout
75
76         settings = UnifiedPaintPanel.paint_settings(context)
77         brush = settings.brush
78
79         layout.prop(brush, "use_paint_sculpt", text="Sculpt")
80         layout.prop(brush, "use_paint_uv_sculpt", text="UV Sculpt")
81         layout.prop(brush, "use_paint_vertex", text="Vertex Paint")
82         layout.prop(brush, "use_paint_weight", text="Weight Paint")
83         layout.prop(brush, "use_paint_image", text="Texture Paint")
84
85
86 class View3DPanel:
87     bl_space_type = 'VIEW_3D'
88     bl_region_type = 'UI'
89
90
91 # **************** standard tool clusters ******************
92
93 # Used by vertex & weight paint
94 def draw_vpaint_symmetry(layout, vpaint):
95
96     split = layout.split()
97
98     col = split.column()
99     col.alignment = 'RIGHT'
100     col.label(text="Mirror")
101
102     col = split.column()
103     row = col.row(align=True)
104     row.prop(vpaint, "use_symmetry_x", text="X", toggle=True)
105     row.prop(vpaint, "use_symmetry_y", text="Y", toggle=True)
106     row.prop(vpaint, "use_symmetry_z", text="Z", toggle=True)
107
108     col = layout.column()
109     col.use_property_split = True
110     col.use_property_decorate = False
111     col.prop(vpaint, "radial_symmetry", text="Radial")
112
113 # Most of these panels should not be visible in GP edit modes
114
115
116 def is_not_gpencil_edit_mode(context):
117     is_gpmode = (
118         context.active_object and
119         context.active_object.mode in {'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}
120     )
121     return not is_gpmode
122
123
124 # ********** default tools for object mode ****************
125
126
127 class VIEW3D_PT_tools_object_options(View3DPanel, Panel):
128     bl_category = "Tool"
129     bl_context = ".objectmode"  # dot on purpose (access from topbar)
130     bl_label = "Options"
131
132     def draw(self, context):
133         # layout = self.layout
134         pass
135
136
137 class VIEW3D_PT_tools_object_options_transform(View3DPanel, Panel):
138     bl_category = "Tool"
139     bl_context = ".objectmode"  # dot on purpose (access from topbar)
140     bl_label = "Transform"
141     bl_parent_id = "VIEW3D_PT_tools_object_options"
142
143     def draw(self, context):
144         layout = self.layout
145
146         layout.use_property_split = True
147         layout.use_property_decorate = False
148
149         tool_settings = context.tool_settings
150
151         layout.label(text="Affect Only")
152         layout.prop(tool_settings, "use_transform_data_origin", text="Origins")
153         layout.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
154         layout.prop(tool_settings, "use_transform_skip_children", text="Parents")
155
156
157 # ********** default tools for editmode_mesh ****************
158
159
160 class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel):
161     bl_category = "Tool"
162     bl_context = ".mesh_edit"  # dot on purpose (access from topbar)
163     bl_label = "Options"
164     bl_options = {'DEFAULT_CLOSED'}
165
166     @classmethod
167     def poll(cls, context):
168         return context.active_object
169
170     def draw(self, context):
171         layout = self.layout
172
173         layout.use_property_split = True
174         layout.use_property_decorate = False
175
176         ob = context.active_object
177         mesh = ob.data
178
179         split = layout.split()
180
181         col = split.column()
182         col.alignment = 'RIGHT'
183         col.label(text="Mirror")
184
185         col = split.column()
186
187         row = col.row(align=True)
188         row.prop(mesh, "use_mirror_x", text="X", toggle=True)
189         row.prop(mesh, "use_mirror_y", text="Y", toggle=True)
190         row.prop(mesh, "use_mirror_z", text="Z", toggle=True)
191
192         row = layout.row(align=True)
193         row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z
194         row.prop(mesh, "use_mirror_topology")
195
196
197 class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel):
198     bl_category = "Tool"
199     bl_context = ".mesh_edit"  # dot on purpose (access from topbar)
200     bl_label = "Auto Merge"
201     bl_parent_id = "VIEW3D_PT_tools_meshedit_options"
202     bl_options = {'DEFAULT_CLOSED'}
203
204     @classmethod
205     def poll(cls, context):
206         return context.active_object
207
208     def draw_header(self, context):
209         tool_settings = context.tool_settings
210
211         self.layout.prop(tool_settings, "use_mesh_automerge", text="", toggle=False)
212
213     def draw(self, context):
214         layout = self.layout
215
216         tool_settings = context.tool_settings
217
218         layout.use_property_split = True
219         layout.use_property_decorate = False
220
221         col = layout.column(align=True)
222         col.active = tool_settings.use_mesh_automerge
223         col.prop(tool_settings, "use_mesh_automerge_and_split", toggle=False)
224         col.prop(tool_settings, "double_threshold", text="Threshold")
225
226 # ********** default tools for editmode_curve ****************
227
228
229 class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
230     bl_category = "Tool"
231     bl_context = ".curve_edit"  # dot on purpose (access from topbar)
232     bl_label = "Curve Stroke"
233
234     def draw(self, context):
235         layout = self.layout
236
237         tool_settings = context.tool_settings
238         cps = tool_settings.curve_paint_settings
239
240         col = layout.column()
241
242         col.prop(cps, "curve_type")
243
244         if cps.curve_type == 'BEZIER':
245             col.label(text="Bezier Options:")
246             col.prop(cps, "error_threshold")
247             col.prop(cps, "fit_method")
248             col.prop(cps, "use_corners_detect")
249
250             col = layout.column()
251             col.active = cps.use_corners_detect
252             col.prop(cps, "corner_angle")
253
254         col.label(text="Pressure Radius:")
255         row = layout.row(align=True)
256         rowsub = row.row(align=True)
257         rowsub.prop(cps, "radius_min", text="Min")
258         rowsub.prop(cps, "radius_max", text="Max")
259
260         row.prop(cps, "use_pressure_radius", text="", icon_only=True)
261
262         col = layout.column()
263         col.label(text="Taper Radius:")
264         row = layout.row(align=True)
265         row.prop(cps, "radius_taper_start", text="Start")
266         row.prop(cps, "radius_taper_end", text="End")
267
268         col = layout.column()
269         col.label(text="Projection Depth:")
270         row = layout.row(align=True)
271         row.prop(cps, "depth_mode", expand=True)
272
273         col = layout.column()
274         if cps.depth_mode == 'SURFACE':
275             col.prop(cps, "surface_offset")
276             col.prop(cps, "use_offset_absolute")
277             col.prop(cps, "use_stroke_endpoints")
278             if cps.use_stroke_endpoints:
279                 colsub = layout.column(align=True)
280                 colsub.prop(cps, "surface_plane", expand=True)
281
282
283 # ********** default tools for editmode_armature ****************
284
285
286 class VIEW3D_PT_tools_armatureedit_options(View3DPanel, Panel):
287     bl_category = "Tool"
288     bl_context = ".armature_edit"  # dot on purpose (access from topbar)
289     bl_label = "Options"
290
291     def draw(self, context):
292         arm = context.active_object.data
293
294         self.layout.prop(arm, "use_mirror_x")
295
296
297 # ********** default tools for pose-mode ****************
298
299 class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
300     bl_category = "Tool"
301     bl_context = ".posemode"  # dot on purpose (access from topbar)
302     bl_label = "Pose Options"
303
304     def draw(self, context):
305         pose = context.active_object.pose
306         layout = self.layout
307
308         tool_settings = context.tool_settings
309
310         layout.prop(pose, "use_auto_ik")
311         layout.prop(pose, "use_mirror_x")
312         col = layout.column()
313         col.active = pose.use_mirror_x
314         col.prop(pose, "use_mirror_relative")
315
316         layout.label(text="Affect Only")
317         layout.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
318
319 # ********** default tools for paint modes ****************
320
321
322 class View3DPaintPanel(UnifiedPaintPanel):
323     bl_space_type = 'VIEW_3D'
324     bl_region_type = 'UI'
325     bl_category = "Tool"
326
327
328 class VIEW3D_PT_tools_particlemode(Panel, View3DPaintPanel):
329     bl_context = ".paint_common"  # dot on purpose (access from topbar)
330     bl_label = "Particle tools"
331     bl_options = {'HIDE_HEADER'}
332
333     @classmethod
334     def poll(cls, context):
335         settings = cls.paint_settings(context)
336         return (settings and settings.brush and context.particle_edit_object)
337
338     def draw(self, context):
339         layout = self.layout
340
341         settings = self.paint_settings(context)
342         brush = settings.brush
343         tool = settings.tool
344
345         layout.use_property_split = True
346         layout.use_property_decorate = False  # No animation.
347
348         if tool is not None:
349             col = layout.column()
350             col.prop(brush, "size", slider=True)
351             if tool == 'ADD':
352                 col.prop(brush, "count")
353
354                 col = layout.column()
355                 col.prop(settings, "use_default_interpolate")
356                 col.prop(brush, "steps", slider=True)
357                 col.prop(settings, "default_key_count", slider=True)
358             else:
359                 col.prop(brush, "strength", slider=True)
360
361                 if tool == 'LENGTH':
362                     layout.row().prop(brush, "length_mode", expand=True)
363                 elif tool == 'PUFF':
364                     layout.row().prop(brush, "puff_mode", expand=True)
365                     layout.prop(brush, "use_puff_volume")
366                 elif tool == 'COMB':
367                     layout.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
368                     col = layout.column()
369                     col.active = settings.use_emitter_deflect
370                     col.prop(settings, "emitter_distance", text="Distance")
371
372
373 # TODO, move to space_view3d.py
374 class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
375     bl_context = ".paint_common"  # dot on purpose (access from topbar)
376     bl_label = "Brush"
377
378     @classmethod
379     def poll(cls, context):
380         settings = cls.paint_settings(context)
381         return (settings and
382                 settings.brush and
383                 (context.sculpt_object or
384                  context.vertex_paint_object or
385                  context.weight_paint_object or
386                  context.image_paint_object))
387
388     def draw(self, context):
389         layout = self.layout
390
391         layout.use_property_split = True
392         layout.use_property_decorate = False  # No animation.
393
394         settings = self.paint_settings(context)
395         brush = settings.brush
396
397         if not self.is_popover:
398             row = layout.row()
399             row.column().template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
400             row.menu("VIEW3D_MT_brush_context_menu", icon='DOWNARROW_HLT', text="")
401
402         # Sculpt Mode #
403         if context.sculpt_object and brush:
404             from bl_ui.properties_paint_common import (
405                 brush_basic_sculpt_settings,
406             )
407
408             capabilities = brush.sculpt_capabilities
409
410             col = layout.column()
411
412             if not self.is_popover:
413                 brush_basic_sculpt_settings(col, context, brush)
414
415             # normal_radius_factor
416             col.separator()
417             row = col.row()
418             row.prop(brush, "normal_radius_factor", slider=True)
419
420             if brush.sculpt_tool == 'ELASTIC_DEFORM':
421                 col.separator()
422                 row = col.row()
423                 row.prop(brush, "elastic_deform_type")
424                 row = col.row()
425                 row.prop(brush, "elastic_deform_volume_preservation", slider=True)
426             elif brush.sculpt_tool == 'POSE':
427                 row = col.row()
428                 row.prop(brush, "pose_offset")
429                 row = col.row()
430                 row.prop(brush, "pose_smooth_iterations")
431             elif brush.sculpt_tool == 'GRAB':
432                 col.separator()
433                 row = col.row()
434                 row.prop(brush, "use_grab_active_vertex")
435             elif brush.sculpt_tool == 'MULTIPLANE_SCRAPE':
436                 row = col.row()
437                 row.prop(brush, "multiplane_scrape_angle")
438                 row = col.row()
439                 row.prop(brush, "use_multiplane_scrape_dynamic")
440                 row = col.row()
441                 row.prop(brush, "show_multiplane_scrape_planes_preview")
442
443             # topology_rake_factor
444             if (
445                     capabilities.has_topology_rake and
446                     context.sculpt_object.use_dynamic_topology_sculpting
447             ):
448                 row = col.row()
449                 row.prop(brush, "topology_rake_factor", slider=True)
450
451             # auto_smooth_factor and use_inverse_smooth_pressure
452             if capabilities.has_auto_smooth:
453                 row = col.row(align=True)
454                 row.prop(brush, "auto_smooth_factor", slider=True)
455                 row.prop(brush, "use_inverse_smooth_pressure", toggle=True, text="")
456
457             # normal_weight
458             if capabilities.has_normal_weight:
459                 row = col.row(align=True)
460                 row.prop(brush, "normal_weight", slider=True)
461
462             # crease_pinch_factor
463             if capabilities.has_pinch_factor:
464                 row = col.row(align=True)
465                 if brush.sculpt_tool in {'BLOB', 'SNAKE_HOOK'}:
466                     row.prop(brush, "crease_pinch_factor", slider=True, text="Magnify")
467                 else:
468                     row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
469
470             # rake_factor
471             if capabilities.has_rake_factor:
472                 row = col.row(align=True)
473                 row.prop(brush, "rake_factor", slider=True)
474
475             if brush.sculpt_tool == 'MASK':
476                 col.prop(brush, "mask_tool")
477
478             # plane_offset, use_offset_pressure, use_plane_trim, plane_trim
479             if capabilities.has_plane_offset:
480                 row = col.row(align=True)
481                 row.prop(brush, "plane_offset", slider=True)
482                 row.prop(brush, "use_offset_pressure", text="")
483
484                 col.separator()
485
486                 row = col.row()
487                 row.prop(brush, "use_plane_trim", text="Plane Trim")
488                 row = col.row()
489                 row.active = brush.use_plane_trim
490                 row.prop(brush, "plane_trim", slider=True, text="Distance")
491
492             # height
493             if capabilities.has_height:
494                 row = col.row()
495                 row.prop(brush, "height", slider=True, text="Height")
496
497             # use_persistent, set_persistent_base
498             if capabilities.has_persistence:
499                 ob = context.sculpt_object
500                 do_persistent = True
501
502                 # not supported yet for this case
503                 for md in ob.modifiers:
504                     if md.type == 'MULTIRES':
505                         do_persistent = False
506                         break
507
508                 if do_persistent:
509                     col.prop(brush, "use_persistent")
510                     col.operator("sculpt.set_persistent_base")
511
512         # Texture Paint Mode #
513
514         elif context.image_paint_object and brush:
515             brush_texpaint_common(self, context, layout, brush, settings, projpaint=True)
516
517         # Weight Paint Mode #
518         elif context.weight_paint_object and brush:
519             from bl_ui.properties_paint_common import (
520                 brush_basic_wpaint_settings,
521             )
522
523             col = layout.column()
524
525             if not self.is_popover:
526                 brush_basic_wpaint_settings(col, context, brush)
527
528         # Vertex Paint Mode #
529         elif context.vertex_paint_object and brush:
530             from bl_ui.properties_paint_common import (
531                 brush_basic_vpaint_settings,
532             )
533
534             col = layout.column()
535
536             if not self.is_popover:
537                 brush_basic_vpaint_settings(col, context, brush)
538
539
540 class VIEW3D_PT_tools_brush_color(Panel, View3DPaintPanel):
541     bl_context = ".paint_common"  # dot on purpose (access from topbar)
542     bl_parent_id = "VIEW3D_PT_tools_brush"
543     bl_label = "Color Picker"
544
545     @classmethod
546     def poll(cls, context):
547         settings = cls.paint_settings(context)
548         brush = settings.brush
549         if context.image_paint_object:
550             capabilities = brush.image_paint_capabilities
551             return capabilities.has_color
552
553         elif context.vertex_paint_object:
554             capabilities = brush.vertex_paint_capabilities
555             return capabilities.has_color
556
557     def draw(self, context):
558         layout = self.layout
559         settings = self.paint_settings(context)
560         brush = settings.brush
561
562         if context.vertex_paint_object:
563             brush_texpaint_common_color(self, context, layout, brush, settings, projpaint=True)
564
565         else:
566             layout.prop(brush, "color_type", expand=True)
567
568             if brush.color_type == 'COLOR':
569                 brush_texpaint_common_color(self, context, layout, brush, settings, projpaint=True)
570             elif brush.color_type == 'GRADIENT':
571                 brush_texpaint_common_gradient(self, context, layout, brush, settings, projpaint=True)
572
573
574 class VIEW3D_PT_tools_brush_swatches(Panel, View3DPaintPanel):
575     bl_context = ".paint_common"  # dot on purpose (access from topbar)
576     bl_parent_id = "VIEW3D_PT_tools_brush"
577     bl_label = "Color Palette"
578     bl_options = {'DEFAULT_CLOSED'}
579
580     @classmethod
581     def poll(cls, context):
582         settings = cls.paint_settings(context)
583         brush = settings.brush
584         if context.image_paint_object:
585             capabilities = brush.image_paint_capabilities
586             return capabilities.has_color
587
588         elif context.vertex_paint_object:
589             capabilities = brush.vertex_paint_capabilities
590             return capabilities.has_color
591
592     def draw(self, context):
593         layout = self.layout
594         settings = self.paint_settings(context)
595
596         layout.template_ID(settings, "palette", new="palette.new")
597         if settings.palette:
598             layout.template_palette(settings, "palette", color=True)
599
600
601 class VIEW3D_PT_tools_brush_clone(Panel, View3DPaintPanel):
602     bl_context = ".paint_common"  # dot on purpose (access from topbar)
603     bl_parent_id = "VIEW3D_PT_tools_brush"
604     bl_label = "Clone from Paint Slot"
605     bl_options = {'DEFAULT_CLOSED'}
606
607     @classmethod
608     def poll(cls, context):
609         settings = cls.paint_settings(context)
610         brush = settings.brush
611
612         return brush.image_tool == 'CLONE'
613
614     def draw_header(self, context):
615         settings = self.paint_settings(context)
616         self.layout.prop(settings, "use_clone_layer", text="")
617
618     def draw(self, context):
619         layout = self.layout
620         settings = self.paint_settings(context)
621         brush = settings.brush
622
623         layout.active = settings.use_clone_layer
624
625         brush_texpaint_common_clone(self, context, layout, brush, settings, projpaint=True)
626
627
628 class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
629     bl_context = ".paint_common"  # dot on purpose (access from topbar)
630     bl_parent_id = "VIEW3D_PT_tools_brush"
631     bl_label = "Options"
632     bl_options = {'DEFAULT_CLOSED'}
633
634     def draw(self, context):
635         layout = self.layout
636         tool_settings = context.tool_settings
637         settings = self.paint_settings(context)
638         brush = settings.brush
639         capabilities = brush.sculpt_capabilities
640
641         layout.use_property_split = True
642         layout.use_property_decorate = False  # No animation.
643
644         col = layout.column()
645
646         if context.image_paint_object and brush:
647             brush_texpaint_common_options(self, context, layout, brush, settings, projpaint=True)
648
649         elif context.sculpt_object and brush:
650             col.prop(brush, "use_automasking_topology")
651             if capabilities.has_accumulate:
652                 col.prop(brush, "use_accumulate")
653
654             UnifiedPaintPanel.prop_unified_size(col, context, brush, "use_locked_size")
655
656             if capabilities.has_sculpt_plane:
657                 col.prop(brush, "sculpt_plane")
658                 col.prop(brush, "use_original_normal")
659                 col.prop(brush, "use_original_plane")
660
661             col.prop(brush, "use_frontface", text="Front Faces Only")
662             col.prop(brush, "use_projected")
663
664         elif context.weight_paint_object and brush:
665
666             if brush.weight_tool != 'SMEAR':
667                 col.prop(brush, "use_accumulate")
668
669             col.prop(brush, "use_frontface", text="Front Faces Only")
670             col.prop(brush, "use_projected")
671             col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize")
672             col.prop(tool_settings, "use_multipaint", text="Multi-Paint")
673
674         elif context.vertex_paint_object and brush:
675
676             if brush.vertex_tool != 'SMEAR':
677                 col.prop(brush, "use_accumulate")
678
679             col.prop(brush, "use_alpha")
680             col.prop(brush, "use_frontface", text="Front Faces Only")
681             col.prop(brush, "use_projected")
682
683
684 class TEXTURE_UL_texpaintslots(UIList):
685     def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
686         # mat = data
687
688         if self.layout_type in {'DEFAULT', 'COMPACT'}:
689             layout.prop(item, "name", text="", emboss=False, icon_value=icon)
690         elif self.layout_type == 'GRID':
691             layout.alignment = 'CENTER'
692             layout.label(text="")
693
694
695 class VIEW3D_MT_tools_projectpaint_uvlayer(Menu):
696     bl_label = "Clone Layer"
697
698     def draw(self, context):
699         layout = self.layout
700
701         for i, uv_layer in enumerate(context.active_object.data.uv_layers):
702             props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
703             props.data_path = "active_object.data.uv_layers.active_index"
704             props.value = i
705
706
707 class VIEW3D_PT_slots_projectpaint(View3DPanel, Panel):
708     bl_category = "Tool"
709     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
710     bl_label = "Texture Slots"
711
712     @classmethod
713     def poll(cls, context):
714         brush = context.tool_settings.image_paint.brush
715         ob = context.active_object
716         return (brush is not None and ob is not None)
717
718     def draw(self, context):
719         layout = self.layout
720         layout.use_property_split = True
721         layout.use_property_decorate = False
722
723         settings = context.tool_settings.image_paint
724
725         ob = context.active_object
726
727         layout.prop(settings, "mode", text="Mode")
728         layout.separator()
729
730         if settings.mode == 'MATERIAL':
731             if len(ob.material_slots) > 1:
732                 layout.template_list("MATERIAL_UL_matslots", "layers",
733                                      ob, "material_slots",
734                                      ob, "active_material_index", rows=2)
735             mat = ob.active_material
736             if mat and mat.texture_paint_images:
737                 row = layout.row()
738                 row.template_list("TEXTURE_UL_texpaintslots", "",
739                                   mat, "texture_paint_images",
740                                   mat, "paint_active_slot", rows=2)
741
742                 if mat.texture_paint_slots:
743                     slot = mat.texture_paint_slots[mat.paint_active_slot]
744                 else:
745                     slot = None
746
747                 have_image = slot is not None
748             else:
749                 row = layout.row()
750
751                 box = row.box()
752                 box.label(text="No Textures")
753                 have_image = False
754
755             sub = row.column(align=True)
756             sub.operator_menu_enum("paint.add_texture_paint_slot", "type", icon='ADD', text="")
757
758         elif settings.mode == 'IMAGE':
759             mesh = ob.data
760             uv_text = mesh.uv_layers.active.name if mesh.uv_layers.active else ""
761             layout.template_ID(settings, "canvas", new="image.new", open="image.open")
762             if settings.missing_uvs:
763                 layout.operator("paint.add_simple_uvs", icon='ADD', text="Add UVs")
764             else:
765                 layout.menu("VIEW3D_MT_tools_projectpaint_uvlayer", text=uv_text, translate=False)
766             have_image = settings.canvas is not None
767
768             layout.prop(settings, "interpolation", text="")
769
770         if settings.missing_uvs:
771             layout.separator()
772             split = layout.split()
773             split.label(text="UV Map Needed", icon='INFO')
774             split.operator("paint.add_simple_uvs", icon='ADD', text="Add Simple UVs")
775         elif have_image:
776             layout.separator()
777             layout.operator("image.save_all_modified", text="Save All Images", icon='FILE_TICK')
778
779 # TODO, move to space_view3d.py
780
781
782 class VIEW3D_PT_stencil_projectpaint(View3DPanel, Panel):
783     bl_category = "Tool"
784     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
785     bl_label = "Mask"
786     bl_options = {'DEFAULT_CLOSED'}
787     bl_ui_units_x = 14
788
789     @classmethod
790     def poll(cls, context):
791         brush = context.tool_settings.image_paint.brush
792         ob = context.active_object
793         return (brush is not None and ob is not None)
794
795     def draw_header(self, context):
796         ipaint = context.tool_settings.image_paint
797         self.layout.prop(ipaint, "use_stencil_layer", text="")
798
799     def draw(self, context):
800         layout = self.layout
801         layout.use_property_split = True
802         layout.use_property_decorate = False
803
804         tool_settings = context.tool_settings
805         ipaint = tool_settings.image_paint
806         ob = context.active_object
807         mesh = ob.data
808
809         col = layout.column()
810         col.active = ipaint.use_stencil_layer
811
812         col.label(text="Stencil Image")
813         col.template_ID(ipaint, "stencil_image", new="image.new", open="image.open")
814
815         stencil_text = mesh.uv_layer_stencil.name if mesh.uv_layer_stencil else ""
816
817         col.separator()
818
819         split = col.split()
820         colsub = split.column()
821         colsub.alignment = 'RIGHT'
822         colsub.label(text="UV Layer")
823         split.column().menu("VIEW3D_MT_tools_projectpaint_stencil", text=stencil_text, translate=False)
824
825         col.separator()
826
827         row = col.row(align=True)
828         row.prop(ipaint, "stencil_color", text="Display Color")
829         row.prop(ipaint, "invert_stencil", text="", icon='IMAGE_ALPHA')
830
831
832 # TODO, move to space_view3d.py
833 class VIEW3D_PT_tools_brush_display(Panel, View3DPaintPanel):
834     bl_context = ".paint_common"  # dot on purpose (access from topbar)
835     bl_label = "Display"
836     bl_options = {'DEFAULT_CLOSED'}
837
838     @classmethod
839     def poll(cls, context):
840         settings = cls.paint_settings(context)
841         return (settings and
842                 settings.brush and
843                 (context.sculpt_object or
844                  context.vertex_paint_object or
845                  context.weight_paint_object or
846                  context.image_paint_object))
847
848     def draw(self, context):
849         layout = self.layout
850         layout.use_property_split = True
851         layout.use_property_decorate = False
852
853         settings = self.paint_settings(context)
854         brush = settings.brush
855         tex_slot = brush.texture_slot
856         tex_slot_mask = brush.mask_texture_slot
857
858         col = layout.column()
859
860         row = col.row(align=True)
861
862         sub = row.row(align=True)
863         sub.prop(brush, "cursor_overlay_alpha", text="Curve Alpha")
864         sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
865         row.prop(
866             brush, "use_cursor_overlay", text="", toggle=True,
867             icon='HIDE_OFF' if brush.use_cursor_overlay else 'HIDE_ON',
868         )
869
870         col.active = brush.brush_capabilities.has_overlay
871
872         if context.image_paint_object or context.sculpt_object or context.vertex_paint_object:
873             row = col.row(align=True)
874
875             sub = row.row(align=True)
876             sub.prop(brush, "texture_overlay_alpha", text="Texture Alpha")
877             sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
878             if tex_slot.map_mode != 'STENCIL':
879                 row.prop(
880                     brush, "use_primary_overlay", text="", toggle=True,
881                     icon='HIDE_OFF' if brush.use_primary_overlay else 'HIDE_ON',
882                 )
883
884         if context.image_paint_object:
885             row = col.row(align=True)
886
887             sub = row.row(align=True)
888             sub.prop(brush, "mask_overlay_alpha", text="Mask Texture Alpha")
889             sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA')
890             if tex_slot_mask.map_mode != 'STENCIL':
891                 row.prop(
892                     brush, "use_secondary_overlay", text="", toggle=True,
893                     icon='HIDE_OFF' if brush.use_secondary_overlay else 'HIDE_ON',
894                 )
895
896
897 # TODO, move to space_view3d.py
898 class VIEW3D_PT_tools_brush_texture(Panel, View3DPaintPanel):
899     bl_context = ".paint_common"  # dot on purpose (access from topbar)
900     bl_label = "Texture"
901     bl_options = {'DEFAULT_CLOSED'}
902
903     @classmethod
904     def poll(cls, context):
905         settings = cls.paint_settings(context)
906         return (settings and settings.brush and
907                 (context.sculpt_object or context.image_paint_object or context.vertex_paint_object))
908
909     def draw(self, context):
910         layout = self.layout
911
912         settings = self.paint_settings(context)
913         brush = settings.brush
914
915         col = layout.column()
916
917         col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
918
919         brush_texture_settings(col, brush, context.sculpt_object)
920
921
922 # TODO, move to space_view3d.py
923 class VIEW3D_PT_tools_mask_texture(Panel, View3DPaintPanel):
924     bl_category = "Tool"
925     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
926     bl_label = "Texture Mask"
927     bl_options = {'DEFAULT_CLOSED'}
928
929     @classmethod
930     def poll(cls, context):
931         settings = cls.paint_settings(context)
932         return (settings and settings.brush and context.image_paint_object)
933
934     def draw(self, context):
935         layout = self.layout
936
937         brush = context.tool_settings.image_paint.brush
938
939         col = layout.column()
940
941         col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8)
942
943         brush_mask_texture_settings(col, brush)
944
945
946 # TODO, move to space_view3d.py
947 class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel):
948     bl_context = ".paint_common"  # dot on purpose (access from topbar)
949     bl_label = "Stroke"
950     bl_options = {'DEFAULT_CLOSED'}
951
952     @classmethod
953     def poll(cls, context):
954         settings = cls.paint_settings(context)
955         return (settings and
956                 settings.brush and
957                 (context.sculpt_object or
958                  context.vertex_paint_object or
959                  context.weight_paint_object or
960                  context.image_paint_object))
961
962     def draw(self, context):
963         layout = self.layout
964
965         settings = self.paint_settings(context)
966         brush = settings.brush
967         layout.use_property_split = True
968         layout.use_property_decorate = False
969
970         col = layout.column()
971
972         col.prop(brush, "stroke_method")
973
974         if brush.use_anchor:
975             col.prop(brush, "use_edge_to_edge", text="Edge To Edge")
976
977         if brush.use_airbrush:
978             col.prop(brush, "rate", text="Rate", slider=True)
979
980         if brush.use_space:
981             row = col.row(align=True)
982             row.prop(brush, "spacing", text="Spacing")
983             row.prop(brush, "use_pressure_spacing", toggle=True, text="")
984             col.prop(brush, "dash_ratio")
985             col.prop(brush, "dash_samples")
986
987         if brush.use_line or brush.use_curve:
988             row = col.row(align=True)
989             row.prop(brush, "spacing", text="Spacing")
990             col.prop(brush, "dash_ratio")
991             col.prop(brush, "dash_samples")
992
993         if brush.use_curve:
994             col.template_ID(brush, "paint_curve", new="paintcurve.new")
995             col.operator("paintcurve.draw")
996
997         if context.sculpt_object:
998
999             if brush.sculpt_capabilities.has_space_attenuation:
1000                 col.prop(brush, "use_space_attenuation")
1001
1002             col.prop(brush, "use_scene_spacing")
1003
1004             if brush.sculpt_capabilities.has_jitter:
1005
1006                 row = col.row(align=True)
1007                 if brush.use_relative_jitter:
1008                     row.prop(brush, "jitter", slider=True)
1009                 else:
1010                     row.prop(brush, "jitter_absolute")
1011                 row.prop(brush, "use_relative_jitter", icon_only=True)
1012                 row.prop(brush, "use_pressure_jitter", toggle=True, text="")
1013
1014         else:
1015
1016             row = col.row(align=True)
1017             if brush.use_relative_jitter:
1018                 row.prop(brush, "jitter", slider=True)
1019             else:
1020                 row.prop(brush, "jitter_absolute")
1021             row.prop(brush, "use_relative_jitter", icon_only=True)
1022             row.prop(brush, "use_pressure_jitter", toggle=True, text="")
1023
1024         col.prop(settings, "input_samples")
1025
1026
1027 class VIEW3D_PT_tools_brush_stroke_smooth_stroke(Panel, View3DPaintPanel):
1028     bl_context = ".paint_common"  # dot on purpose (access from topbar)
1029     bl_label = "Smooth Stroke"
1030     bl_parent_id = "VIEW3D_PT_tools_brush_stroke"
1031     bl_options = {'DEFAULT_CLOSED'}
1032
1033     @classmethod
1034     def poll(cls, context):
1035         settings = cls.paint_settings(context)
1036         brush = settings.brush
1037         if brush.brush_capabilities.has_smooth_stroke:
1038             return True
1039
1040     def draw_header(self, context):
1041         settings = self.paint_settings(context)
1042         brush = settings.brush
1043
1044         self.layout.prop(brush, "use_smooth_stroke", text="")
1045
1046     def draw(self, context):
1047         layout = self.layout
1048         layout.use_property_split = True
1049         layout.use_property_decorate = False
1050
1051         settings = self.paint_settings(context)
1052         brush = settings.brush
1053
1054         col = layout.column()
1055         col.active = brush.use_smooth_stroke
1056         col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
1057         col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
1058
1059
1060 # TODO, move to space_view3d.py
1061 class VIEW3D_PT_tools_brush_falloff(Panel, View3DPaintPanel):
1062     bl_context = ".paint_common"  # dot on purpose (access from topbar)
1063     bl_label = "Falloff"
1064     bl_options = {'DEFAULT_CLOSED'}
1065
1066     @classmethod
1067     def poll(cls, context):
1068         settings = cls.paint_settings(context)
1069         return (settings and settings.brush and settings.brush.curve)
1070
1071     def draw(self, context):
1072         layout = self.layout
1073         settings = self.paint_settings(context)
1074         brush = settings.brush
1075
1076         col = layout.column(align=True)
1077         row = col.row(align=True)
1078         row.prop(brush, "curve_preset", text="")
1079
1080         if brush.curve_preset == 'CUSTOM':
1081             layout.template_curve_mapping(brush, "curve", brush=True)
1082
1083             col = layout.column(align=True)
1084             row = col.row(align=True)
1085             row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
1086             row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
1087             row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
1088             row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
1089             row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
1090             row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
1091
1092
1093 class VIEW3D_PT_tools_brush_falloff_frontface(View3DPaintPanel, Panel):
1094     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1095     bl_label = "Frontface Falloff"
1096     bl_parent_id = "VIEW3D_PT_tools_brush_falloff"
1097     bl_options = {'DEFAULT_CLOSED'}
1098
1099     @classmethod
1100     def poll(cls, context):
1101         return (context.weight_paint_object or context.vertex_paint_object)
1102
1103     def draw_header(self, context):
1104         settings = self.paint_settings(context)
1105         brush = settings.brush
1106
1107         self.layout.prop(brush, "use_frontface_falloff", text="")
1108
1109     def draw(self, context):
1110         settings = self.paint_settings(context)
1111         brush = settings.brush
1112
1113         layout = self.layout
1114
1115         layout.use_property_split = True
1116         layout.use_property_decorate = False
1117
1118         layout.active = brush.use_frontface_falloff
1119         layout.prop(brush, "falloff_angle", text="Angle")
1120
1121
1122 class VIEW3D_PT_tools_brush_falloff_normal(View3DPaintPanel, Panel):
1123     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1124     bl_label = "Normal Falloff"
1125     bl_parent_id = "VIEW3D_PT_tools_brush_falloff"
1126     bl_options = {'DEFAULT_CLOSED'}
1127
1128     @classmethod
1129     def poll(cls, context):
1130         return context.image_paint_object
1131
1132     def draw_header(self, context):
1133         tool_settings = context.tool_settings
1134         ipaint = tool_settings.image_paint
1135
1136         self.layout.prop(ipaint, "use_normal_falloff", text="")
1137
1138     def draw(self, context):
1139         tool_settings = context.tool_settings
1140         ipaint = tool_settings.image_paint
1141
1142         layout = self.layout
1143
1144         layout.use_property_split = True
1145         layout.use_property_decorate = False
1146
1147         layout.active = ipaint.use_normal_falloff
1148         layout.prop(ipaint, "normal_angle", text="Angle")
1149
1150
1151 # TODO, move to space_view3d.py
1152 class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
1153     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
1154     bl_label = "Dyntopo"
1155     bl_options = {'DEFAULT_CLOSED'}
1156     bl_ui_units_x = 12
1157
1158     @classmethod
1159     def poll(cls, context):
1160         return (context.sculpt_object and context.tool_settings.sculpt)
1161
1162     def draw_header(self, context):
1163         is_popover = self.is_popover
1164         layout = self.layout
1165         layout.operator(
1166             "sculpt.dynamic_topology_toggle",
1167             icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT',
1168             text="",
1169             emboss=is_popover,
1170         )
1171
1172     def draw(self, context):
1173         layout = self.layout
1174         layout.use_property_split = True
1175         layout.use_property_decorate = False
1176
1177         tool_settings = context.tool_settings
1178         sculpt = tool_settings.sculpt
1179         settings = self.paint_settings(context)
1180         brush = settings.brush
1181
1182         col = layout.column()
1183         col.active = context.sculpt_object.use_dynamic_topology_sculpting
1184
1185         sub = col.column()
1186         sub.active = (brush and brush.sculpt_tool != 'MASK')
1187         if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
1188             row = sub.row(align=True)
1189             row.prop(sculpt, "constant_detail_resolution")
1190             row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER')
1191         elif (sculpt.detail_type_method == 'BRUSH'):
1192             sub.prop(sculpt, "detail_percent")
1193         else:
1194             sub.prop(sculpt, "detail_size")
1195         sub.prop(sculpt, "detail_refine_method", text="Refine Method")
1196         sub.prop(sculpt, "detail_type_method", text="Detailing")
1197
1198         col.prop(sculpt, "use_smooth_shading")
1199
1200
1201 class VIEW3D_PT_sculpt_dyntopo_remesh(Panel, View3DPaintPanel):
1202     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
1203     bl_label = "Remesh"
1204     bl_parent_id = "VIEW3D_PT_sculpt_dyntopo"
1205     bl_options = {'DEFAULT_CLOSED'}
1206     bl_ui_units_x = 12
1207
1208     def draw(self, context):
1209         layout = self.layout
1210         layout.use_property_split = True
1211         layout.use_property_decorate = False
1212
1213         tool_settings = context.tool_settings
1214         sculpt = tool_settings.sculpt
1215
1216         col = layout.column()
1217         col.active = context.sculpt_object.use_dynamic_topology_sculpting
1218
1219         col.prop(sculpt, "symmetrize_direction")
1220
1221         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
1222
1223         col = flow.column()
1224         col.operator("sculpt.symmetrize")
1225         col = flow.column()
1226         col.operator("sculpt.optimize")
1227         if sculpt.detail_type_method in {'CONSTANT', 'MANUAL'}:
1228             col = flow.column()
1229             col.operator("sculpt.detail_flood_fill")
1230
1231
1232 class VIEW3D_PT_sculpt_voxel_remesh(Panel, View3DPaintPanel):
1233     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
1234     bl_label = "Remesh"
1235     bl_options = {'DEFAULT_CLOSED'}
1236     bl_ui_units_x = 12
1237
1238     @classmethod
1239     def poll(cls, context):
1240         return (context.sculpt_object and context.tool_settings.sculpt)
1241
1242     def draw(self, context):
1243         layout = self.layout
1244         layout.use_property_split = True
1245         layout.use_property_decorate = False
1246
1247         col = layout.column()
1248         mesh = context.active_object.data
1249         col.prop(mesh, "remesh_voxel_size")
1250         col.prop(mesh, "remesh_voxel_adaptivity")
1251         col.prop(mesh, "use_remesh_fix_poles")
1252         col.prop(mesh, "use_remesh_smooth_normals")
1253         col.prop(mesh, "use_remesh_preserve_volume")
1254         col.prop(mesh, "use_remesh_preserve_paint_mask")
1255         col.operator("object.voxel_remesh", text="Remesh")
1256
1257 # TODO, move to space_view3d.py
1258
1259
1260 class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
1261     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
1262     bl_label = "Options"
1263     bl_options = {'DEFAULT_CLOSED'}
1264
1265     @classmethod
1266     def poll(cls, context):
1267         return (context.sculpt_object and context.tool_settings.sculpt)
1268
1269     def draw(self, context):
1270         layout = self.layout
1271         layout.use_property_split = True
1272         layout.use_property_decorate = False
1273
1274         tool_settings = context.tool_settings
1275         sculpt = tool_settings.sculpt
1276
1277         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
1278
1279         col = flow.column()
1280         col.prop(sculpt, "use_threaded", text="Threaded Sculpt")
1281         col = flow.column()
1282         col.prop(sculpt, "show_low_resolution")
1283         col = flow.column()
1284         col.prop(sculpt, "use_deform_only")
1285
1286
1287 class VIEW3D_PT_sculpt_options_unified(Panel, View3DPaintPanel):
1288     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
1289     bl_parent_id = "VIEW3D_PT_sculpt_options"
1290     bl_label = "Unified Brush"
1291
1292     @classmethod
1293     def poll(cls, context):
1294         return (context.sculpt_object and context.tool_settings.sculpt)
1295
1296     def draw(self, context):
1297         layout = self.layout
1298         layout.use_property_split = True
1299         layout.use_property_decorate = False
1300
1301         self.unified_paint_settings(layout, context)
1302
1303
1304 class VIEW3D_PT_sculpt_options_gravity(Panel, View3DPaintPanel):
1305     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
1306     bl_parent_id = "VIEW3D_PT_sculpt_options"
1307     bl_label = "Gravity"
1308
1309     @classmethod
1310     def poll(cls, context):
1311         return (context.sculpt_object and context.tool_settings.sculpt)
1312
1313     def draw(self, context):
1314         layout = self.layout
1315         layout.use_property_split = True
1316         layout.use_property_decorate = False
1317
1318         tool_settings = context.tool_settings
1319         sculpt = tool_settings.sculpt
1320         capabilities = sculpt.brush.sculpt_capabilities
1321
1322         col = layout.column()
1323         col.active = capabilities.has_gravity
1324         col.prop(sculpt, "gravity", slider=True, text="Factor")
1325         col.prop(sculpt, "gravity_object")
1326
1327
1328 # TODO, move to space_view3d.py
1329 class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
1330     bl_context = ".sculpt_mode"  # dot on purpose (access from topbar)
1331     bl_label = "Symmetry"
1332     bl_options = {'DEFAULT_CLOSED'}
1333
1334     @classmethod
1335     def poll(cls, context):
1336         return (
1337             (context.sculpt_object and context.tool_settings.sculpt) and
1338             # When used in the tool header, this is explicitly included next to the XYZ symmetry buttons.
1339             (context.region.type != 'TOOL_HEADER')
1340         )
1341
1342     def draw(self, context):
1343         layout = self.layout
1344
1345         sculpt = context.tool_settings.sculpt
1346
1347         split = layout.split()
1348
1349         col = split.column()
1350         col.alignment = 'RIGHT'
1351         col.label(text="Mirror")
1352
1353         col = split.column()
1354
1355         row = col.row(align=True)
1356         row.prop(sculpt, "use_symmetry_x", text="X", toggle=True)
1357         row.prop(sculpt, "use_symmetry_y", text="Y", toggle=True)
1358         row.prop(sculpt, "use_symmetry_z", text="Z", toggle=True)
1359
1360         split = layout.split()
1361
1362         col = split.column()
1363         col.alignment = 'RIGHT'
1364         col.label(text="Lock")
1365
1366         col = split.column()
1367
1368         row = col.row(align=True)
1369         row.prop(sculpt, "lock_x", text="X", toggle=True)
1370         row.prop(sculpt, "lock_y", text="Y", toggle=True)
1371         row.prop(sculpt, "lock_z", text="Z", toggle=True)
1372
1373         split = layout.split()
1374
1375         col = split.column()
1376         col.alignment = 'RIGHT'
1377         col.label(text="Tiling")
1378
1379         col = split.column()
1380
1381         row = col.row(align=True)
1382         row.prop(sculpt, "tile_x", text="X", toggle=True)
1383         row.prop(sculpt, "tile_y", text="Y", toggle=True)
1384         row.prop(sculpt, "tile_z", text="Z", toggle=True)
1385
1386         layout.use_property_split = True
1387         layout.use_property_decorate = False
1388
1389         layout.prop(sculpt, "use_symmetry_feather", text="Feather")
1390         layout.column().prop(sculpt, "radial_symmetry", text="Radial")
1391         layout.column().prop(sculpt, "tile_offset", text="Tile Offset")
1392
1393
1394 class VIEW3D_PT_sculpt_symmetry_for_topbar(Panel):
1395     bl_space_type = 'TOPBAR'
1396     bl_region_type = 'HEADER'
1397     bl_label = "Symmetry"
1398
1399     draw = VIEW3D_PT_sculpt_symmetry.draw
1400
1401
1402 class VIEW3D_PT_tools_brush_display_show_brush(Panel, View3DPaintPanel):
1403     bl_context = ".paint_common"  # dot on purpose (access from topbar)
1404     bl_label = "Show Brush"
1405     bl_parent_id = "VIEW3D_PT_tools_brush_display"
1406     bl_options = {'DEFAULT_CLOSED'}
1407
1408     def draw_header(self, context):
1409         settings = self.paint_settings(context)
1410
1411         self.layout.prop(settings, "show_brush", text="")
1412
1413     def draw(self, context):
1414         layout = self.layout
1415
1416         layout.use_property_split = True
1417         layout.use_property_decorate = False
1418
1419         settings = self.paint_settings(context)
1420         brush = settings.brush
1421
1422         col = layout.column()
1423         col.active = settings.show_brush
1424
1425         if context.sculpt_object and context.tool_settings.sculpt:
1426             if brush.sculpt_capabilities.has_secondary_color:
1427                 col.prop(brush, "cursor_color_add", text="Add")
1428                 col.prop(brush, "cursor_color_subtract", text="Subtract")
1429             else:
1430                 col.prop(brush, "cursor_color_add", text="Color")
1431         else:
1432             col.prop(brush, "cursor_color_add", text="Color")
1433
1434
1435 class VIEW3D_PT_tools_brush_display_custom_icon(Panel, View3DPaintPanel):
1436     bl_context = ".paint_common"  # dot on purpose (access from topbar)
1437     bl_label = "Custom Icon"
1438     bl_parent_id = "VIEW3D_PT_tools_brush_display"
1439     bl_options = {'DEFAULT_CLOSED'}
1440
1441     def draw_header(self, context):
1442         settings = self.paint_settings(context)
1443         brush = settings.brush
1444
1445         self.layout.prop(brush, "use_custom_icon", text="")
1446
1447     def draw(self, context):
1448         layout = self.layout
1449
1450         layout.use_property_split = True
1451         layout.use_property_decorate = False
1452
1453         settings = self.paint_settings(context)
1454         brush = settings.brush
1455
1456         col = layout.column()
1457         col.active = brush.use_custom_icon
1458         col.prop(brush, "icon_filepath", text="")
1459
1460 # ********** default tools for weight-paint ****************
1461
1462
1463 # TODO, move to space_view3d.py
1464 class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
1465     bl_context = ".weightpaint"
1466     bl_options = {'DEFAULT_CLOSED'}
1467     bl_label = "Symmetry"
1468
1469     @classmethod
1470     def poll(cls, context):
1471         # When used in the tool header, this is explicitly included next to the XYZ symmetry buttons.
1472         return (context.region.type != 'TOOL_HEADER')
1473
1474     def draw(self, context):
1475         layout = self.layout
1476         tool_settings = context.tool_settings
1477         wpaint = tool_settings.weight_paint
1478         draw_vpaint_symmetry(layout, wpaint)
1479
1480
1481 class VIEW3D_PT_tools_weightpaint_symmetry_for_topbar(Panel):
1482     bl_space_type = 'TOPBAR'
1483     bl_region_type = 'HEADER'
1484     bl_label = "Symmetry"
1485
1486     draw = VIEW3D_PT_tools_weightpaint_symmetry.draw
1487
1488
1489 # TODO, move to space_view3d.py
1490 class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
1491     bl_context = ".weightpaint"
1492     bl_label = "Options"
1493     bl_options = {'DEFAULT_CLOSED'}
1494
1495     def draw(self, context):
1496         layout = self.layout
1497
1498         layout.use_property_split = True
1499         layout.use_property_decorate = False
1500
1501         tool_settings = context.tool_settings
1502         wpaint = tool_settings.weight_paint
1503
1504         col = layout.column()
1505         col.prop(wpaint, "use_group_restrict")
1506
1507         obj = context.weight_paint_object
1508         if obj.type == 'MESH':
1509             mesh = obj.data
1510             col.prop(mesh, "use_mirror_x")
1511             row = col.row()
1512             row.active = mesh.use_mirror_x
1513             row.prop(mesh, "use_mirror_topology")
1514
1515
1516 class VIEW3D_PT_tools_weightpaint_options_unified(Panel, View3DPaintPanel):
1517     bl_context = ".weightpaint"
1518     bl_label = "Unified Brush"
1519     bl_parent_id = "VIEW3D_PT_tools_weightpaint_options"
1520
1521     def draw(self, context):
1522         layout = self.layout
1523
1524         layout.use_property_split = True
1525         layout.use_property_decorate = False
1526
1527         self.unified_paint_settings(layout, context)
1528
1529 # ********** default tools for vertex-paint ****************
1530
1531
1532 # TODO, move to space_view3d.py
1533 class VIEW3D_PT_tools_vertexpaint_options(Panel, View3DPaintPanel):
1534     bl_context = ".vertexpaint"  # dot on purpose (access from topbar)
1535     bl_label = "Options"
1536     bl_options = {'DEFAULT_CLOSED'}
1537
1538     def draw(self, context):
1539         layout = self.layout
1540
1541         layout.label(text="Unified Brush")
1542
1543         layout.use_property_split = True
1544         layout.use_property_decorate = False
1545
1546         self.unified_paint_settings(layout, context)
1547
1548
1549 # TODO, move to space_view3d.py
1550 class VIEW3D_PT_tools_vertexpaint_symmetry(Panel, View3DPaintPanel):
1551     bl_context = ".vertexpaint"  # dot on purpose (access from topbar)
1552     bl_options = {'DEFAULT_CLOSED'}
1553     bl_label = "Symmetry"
1554
1555     @classmethod
1556     def poll(cls, context):
1557         # When used in the tool header, this is explicitly included next to the XYZ symmetry buttons.
1558         return (context.region.type != 'TOOL_HEADER')
1559
1560     def draw(self, context):
1561         layout = self.layout
1562         tool_settings = context.tool_settings
1563         vpaint = tool_settings.vertex_paint
1564         draw_vpaint_symmetry(layout, vpaint)
1565
1566
1567 class VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar(Panel):
1568     bl_space_type = 'TOPBAR'
1569     bl_region_type = 'HEADER'
1570     bl_label = "Symmetry"
1571
1572     draw = VIEW3D_PT_tools_vertexpaint_symmetry.draw
1573
1574
1575 # ********** default tools for texture-paint ****************
1576
1577
1578 # TODO, move to space_view3d.py
1579 class VIEW3D_PT_tools_imagepaint_options_external(Panel, View3DPaintPanel):
1580     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1581     bl_label = "External"
1582     bl_parent_id = "VIEW3D_PT_tools_imagepaint_options"
1583     bl_options = {'DEFAULT_CLOSED'}
1584
1585     def draw(self, context):
1586         layout = self.layout
1587         layout.use_property_split = True
1588         layout.use_property_decorate = False
1589
1590         tool_settings = context.tool_settings
1591         ipaint = tool_settings.image_paint
1592
1593         layout.prop(ipaint, "screen_grab_size", text="Screen Grab Size")
1594
1595         layout.separator()
1596
1597         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
1598         col = flow.column()
1599         col.operator("image.project_edit", text="Quick Edit")
1600         col = flow.column()
1601         col.operator("image.project_apply", text="Apply")
1602         col = flow.column()
1603         col.operator("paint.project_image", text="Apply Camera Image")
1604
1605
1606 # TODO, move to space_view3d.py
1607 class VIEW3D_PT_tools_imagepaint_symmetry(Panel, View3DPaintPanel):
1608     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1609     bl_label = "Symmetry"
1610     bl_options = {'DEFAULT_CLOSED'}
1611
1612     @classmethod
1613     def poll(cls, context):
1614         # When used in the tool header, this is explicitly included next to the XYZ symmetry buttons.
1615         return (context.region.type != 'TOOL_HEADER')
1616
1617     def draw(self, context):
1618         layout = self.layout
1619
1620         tool_settings = context.tool_settings
1621         ipaint = tool_settings.image_paint
1622
1623         split = layout.split()
1624
1625         col = split.column()
1626         col.alignment = 'RIGHT'
1627         col.label(text="Mirror")
1628
1629         col = split.column()
1630
1631         row = col.row(align=True)
1632         row.prop(ipaint, "use_symmetry_x", text="X", toggle=True)
1633         row.prop(ipaint, "use_symmetry_y", text="Y", toggle=True)
1634         row.prop(ipaint, "use_symmetry_z", text="Z", toggle=True)
1635
1636
1637 # TODO, move to space_view3d.py
1638 class VIEW3D_PT_tools_imagepaint_options(View3DPaintPanel, Panel):
1639     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1640     bl_label = "Options"
1641     bl_options = {'DEFAULT_CLOSED'}
1642
1643     @classmethod
1644     def poll(cls, context):
1645         brush = context.tool_settings.image_paint.brush
1646         return (brush is not None)
1647
1648     def draw(self, context):
1649         layout = self.layout
1650
1651         layout.use_property_split = True
1652         layout.use_property_decorate = False
1653
1654         tool_settings = context.tool_settings
1655         ipaint = tool_settings.image_paint
1656
1657         layout.prop(ipaint, "seam_bleed")
1658         layout.prop(ipaint, "dither", slider=True)
1659
1660         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
1661
1662         col = flow.column()
1663         col.prop(ipaint, "use_occlude")
1664
1665         col = flow.column()
1666         col.prop(ipaint, "use_backface_culling", text="Backface Culling")
1667
1668
1669 class VIEW3D_PT_tools_imagepaint_options_unified(Panel, View3DPaintPanel):
1670     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1671     bl_parent_id = "VIEW3D_PT_tools_imagepaint_options"
1672     bl_label = "Unified Brush"
1673
1674     def draw(self, context):
1675         layout = self.layout
1676         layout.use_property_split = True
1677         layout.use_property_decorate = False
1678
1679         self.unified_paint_settings(layout, context)
1680
1681
1682 class VIEW3D_PT_tools_imagepaint_options_cavity(View3DPaintPanel, Panel):
1683     bl_context = ".imagepaint"  # dot on purpose (access from topbar)
1684     bl_label = "Cavity Mask"
1685     bl_parent_id = "VIEW3D_PT_tools_imagepaint_options"
1686     bl_options = {'DEFAULT_CLOSED'}
1687
1688     def draw_header(self, context):
1689         tool_settings = context.tool_settings
1690         ipaint = tool_settings.image_paint
1691
1692         self.layout.prop(ipaint, "use_cavity", text="")
1693
1694     def draw(self, context):
1695         layout = self.layout
1696
1697         tool_settings = context.tool_settings
1698         ipaint = tool_settings.image_paint
1699
1700         layout.active = ipaint.use_cavity
1701
1702         layout.template_curve_mapping(ipaint, "cavity_curve", brush=True,
1703                                       use_negative_slope=True)
1704
1705
1706 # TODO, move to space_view3d.py
1707 class VIEW3D_PT_imagepaint_options(View3DPaintPanel):
1708     bl_label = "Options"
1709
1710     @classmethod
1711     def poll(cls, context):
1712         return (context.image_paint_object and context.tool_settings.image_paint)
1713
1714     def draw(self, context):
1715         layout = self.layout
1716
1717         col = layout.column()
1718         self.unified_paint_settings(col, context)
1719
1720
1721 class VIEW3D_MT_tools_projectpaint_stencil(Menu):
1722     bl_label = "Mask Layer"
1723
1724     def draw(self, context):
1725         layout = self.layout
1726         for i, uv_layer in enumerate(context.active_object.data.uv_layers):
1727             props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
1728             props.data_path = "active_object.data.uv_layer_stencil_index"
1729             props.value = i
1730
1731
1732 # TODO, move to space_view3d.py
1733 class VIEW3D_PT_tools_particlemode_options(View3DPanel, Panel):
1734     """Default tools for particle mode"""
1735     bl_category = "Tool"
1736     bl_context = ".particlemode"
1737     bl_label = "Options"
1738     bl_options = {'DEFAULT_CLOSED'}
1739
1740     def draw(self, context):
1741         layout = self.layout
1742
1743         layout.use_property_split = True
1744         layout.use_property_decorate = False  # No animation.
1745
1746         pe = context.tool_settings.particle_edit
1747         ob = pe.object
1748
1749         layout.prop(pe, "type", text="Editing Type")
1750
1751         ptcache = None
1752
1753         if pe.type == 'PARTICLES':
1754             if ob.particle_systems:
1755                 if len(ob.particle_systems) > 1:
1756                     layout.template_list("UI_UL_list", "particle_systems", ob, "particle_systems",
1757                                          ob.particle_systems, "active_index", rows=2, maxrows=3)
1758
1759                 ptcache = ob.particle_systems.active.point_cache
1760         else:
1761             for md in ob.modifiers:
1762                 if md.type == pe.type:
1763                     ptcache = md.point_cache
1764
1765         if ptcache and len(ptcache.point_caches) > 1:
1766             layout.template_list("UI_UL_list", "particles_point_caches", ptcache, "point_caches",
1767                                  ptcache.point_caches, "active_index", rows=2, maxrows=3)
1768
1769         if not pe.is_editable:
1770             layout.label(text="Point cache must be baked")
1771             layout.label(text="in memory to enable editing!")
1772
1773         col = layout.column(align=True)
1774         col.active = pe.is_editable
1775         col.prop(ob.data, "use_mirror_x")
1776         col.separator()
1777         col.prop(pe, "use_preserve_length", text="Preserve Strand Lengths")
1778         col.prop(pe, "use_preserve_root", text="Preserve Root Positions")
1779         if not pe.is_hair:
1780             col.prop(pe, "use_auto_velocity", text="Auto-Velocity")
1781
1782
1783 class VIEW3D_PT_tools_particlemode_options_shapecut(View3DPanel, Panel):
1784     """Default tools for particle mode"""
1785     bl_category = "Tool"
1786     bl_parent_id = "VIEW3D_PT_tools_particlemode_options"
1787     bl_label = "Cut Particles to Shape"
1788     bl_options = {'DEFAULT_CLOSED'}
1789
1790     def draw(self, context):
1791         layout = self.layout
1792
1793         layout.use_property_split = True
1794         layout.use_property_decorate = False  # No animation.
1795
1796         pe = context.tool_settings.particle_edit
1797
1798         layout.prop(pe, "shape_object")
1799         layout.operator("particle.shape_cut", text="Cut")
1800
1801
1802 class VIEW3D_PT_tools_particlemode_options_display(View3DPanel, Panel):
1803     """Default tools for particle mode"""
1804     bl_category = "Tool"
1805     bl_parent_id = "VIEW3D_PT_tools_particlemode_options"
1806     bl_label = "Viewport Display"
1807
1808     def draw(self, context):
1809         layout = self.layout
1810
1811         layout.use_property_split = True
1812         layout.use_property_decorate = False  # No animation.
1813
1814         pe = context.tool_settings.particle_edit
1815
1816         col = layout.column()
1817         col.active = pe.is_editable
1818         col.prop(pe, "display_step", text="Path Steps")
1819         if pe.is_hair:
1820             col.prop(pe, "show_particles", text="Children")
1821         else:
1822             if pe.type == 'PARTICLES':
1823                 col.prop(pe, "show_particles", text="Particles")
1824             col.prop(pe, "use_fade_time")
1825             sub = col.row(align=True)
1826             sub.active = pe.use_fade_time
1827             sub.prop(pe, "fade_frames", slider=True)
1828
1829
1830 # ********** grease pencil object tool panels ****************
1831
1832 # Grease Pencil drawing brushes
1833
1834
1835 class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
1836     bl_context = ".greasepencil_paint"
1837     bl_label = "Brush"
1838     bl_category = "Tool"
1839
1840     @classmethod
1841     def poll(cls, context):
1842         is_3d_view = context.space_data.type == 'VIEW_3D'
1843         if is_3d_view:
1844             if context.gpencil_data is None:
1845                 return False
1846
1847             gpd = context.gpencil_data
1848             return bool(gpd.is_stroke_paint_mode)
1849         else:
1850             return True
1851
1852     def draw(self, context):
1853         layout = self.layout
1854         layout.use_property_split = True
1855         layout.use_property_decorate = False
1856
1857         tool_settings = context.scene.tool_settings
1858         gpencil_paint = tool_settings.gpencil_paint
1859
1860         row = layout.row()
1861         col = row.column()
1862         col.template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8)
1863
1864         col = row.column()
1865         brush = gpencil_paint.brush
1866
1867         sub = col.column(align=True)
1868         sub.operator("gpencil.brush_presets_create", icon='PRESET_NEW', text="")
1869
1870         if brush is not None:
1871             gp_settings = brush.gpencil_settings
1872
1873             if brush.gpencil_tool in {'DRAW', 'FILL'}:
1874                 row = layout.row(align=True)
1875                 row_mat = row.row()
1876                 if gp_settings.use_material_pin:
1877                     row_mat.template_ID(gp_settings, "material", live_icon=True)
1878                 else:
1879                     row_mat.template_ID(context.active_object, "active_material", live_icon=True)
1880                     row_mat.enabled = False  # will otherwise allow to change material in active slot
1881
1882                 row.prop(gp_settings, "use_material_pin", text="")
1883
1884             if not self.is_popover:
1885                 from bl_ui.properties_paint_common import (
1886                     brush_basic_gpencil_paint_settings,
1887                 )
1888                 tool = context.workspace.tools.from_space_view3d_mode(context.mode, create=False)
1889                 brush_basic_gpencil_paint_settings(layout, context, brush, tool, compact=True, is_toolbar=False)
1890
1891
1892 # Grease Pencil drawing brushes options
1893 class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
1894     bl_context = ".greasepencil_paint"
1895     bl_label = "Options"
1896     bl_category = "Tool"
1897
1898     @classmethod
1899     def poll(cls, context):
1900         brush = context.tool_settings.gpencil_paint.brush
1901         return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
1902
1903     def draw_header_preset(self, _context):
1904         VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout)
1905
1906     def draw(self, context):
1907         layout = self.layout
1908         layout.use_property_split = True
1909         layout.use_property_decorate = False
1910
1911         brush = context.tool_settings.gpencil_paint.brush
1912
1913         if brush is not None:
1914             gp_settings = brush.gpencil_settings
1915             col = layout.column(align=True)
1916             col.prop(gp_settings, "input_samples")
1917             col.separator()
1918
1919             col.prop(gp_settings, "active_smooth_factor")
1920             col.separator()
1921
1922             col.prop(gp_settings, "angle", slider=True)
1923             col.prop(gp_settings, "angle_factor", text="Factor", slider=True)
1924
1925             ob = context.object
1926             if ob and brush.gpencil_settings.use_material_pin is False:
1927                 ma = ob.active_material
1928             elif brush.gpencil_settings.material:
1929                 ma = brush.gpencil_settings.material
1930             else:
1931                 ma = None
1932
1933             col.separator()
1934             subcol = col.column(align=True)
1935             if ma and ma.grease_pencil.mode == 'LINE':
1936                 subcol.enabled = False
1937             subcol.prop(gp_settings, "gradient_factor", slider=True)
1938             subcol.prop(gp_settings, "gradient_shape")
1939
1940
1941 class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
1942     bl_context = ".greasepencil_paint"
1943     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
1944     bl_label = "Stabilize"
1945     bl_category = "Tool"
1946     bl_options = {'DEFAULT_CLOSED'}
1947
1948     @classmethod
1949     def poll(cls, context):
1950         brush = context.tool_settings.gpencil_paint.brush
1951         return brush is not None and brush.gpencil_tool == 'DRAW'
1952
1953     def draw_header(self, context):
1954         brush = context.tool_settings.gpencil_paint.brush
1955         gp_settings = brush.gpencil_settings
1956         self.layout.prop(gp_settings, "use_settings_stabilizer", text="")
1957
1958     def draw(self, context):
1959         layout = self.layout
1960         layout.use_property_split = True
1961         layout.use_property_decorate = False
1962
1963         brush = context.tool_settings.gpencil_paint.brush
1964         gp_settings = brush.gpencil_settings
1965         layout.active = gp_settings.use_settings_stabilizer
1966
1967         layout.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
1968         layout.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
1969
1970
1971 class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
1972     bl_context = ".greasepencil_paint"
1973     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
1974     bl_label = "Post-Processing"
1975     bl_category = "Tool"
1976
1977     @classmethod
1978     def poll(cls, context):
1979         brush = context.tool_settings.gpencil_paint.brush
1980         return brush is not None and brush.gpencil_tool != 'ERASE'
1981
1982     def draw_header(self, context):
1983         brush = context.tool_settings.gpencil_paint.brush
1984         gp_settings = brush.gpencil_settings
1985         self.layout.prop(gp_settings, "use_settings_postprocess", text="")
1986
1987     def draw(self, context):
1988         layout = self.layout
1989         layout.use_property_split = True
1990         layout.use_property_decorate = False
1991
1992         brush = context.tool_settings.gpencil_paint.brush
1993         gp_settings = brush.gpencil_settings
1994         layout.active = gp_settings.use_settings_postprocess
1995
1996         col = layout.column(align=True)
1997         col.prop(gp_settings, "pen_smooth_factor")
1998         col.prop(gp_settings, "pen_smooth_steps")
1999
2000         col = layout.column(align=True)
2001         col.prop(gp_settings, "pen_thick_smooth_factor")
2002         col.prop(gp_settings, "pen_thick_smooth_steps", text="Iterations")
2003
2004         col = layout.column(align=True)
2005         col.prop(gp_settings, "pen_subdivision_steps")
2006         col.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
2007
2008         col = layout.column(align=True)
2009         col.prop(gp_settings, "simplify_factor")
2010
2011         col = layout.column(align=True)
2012         col.prop(gp_settings, "trim")
2013
2014
2015 class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
2016     bl_context = ".greasepencil_paint"
2017     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
2018     bl_label = "Randomize"
2019     bl_category = "Tool"
2020     bl_options = {'DEFAULT_CLOSED'}
2021
2022     @classmethod
2023     def poll(cls, context):
2024         brush = context.tool_settings.gpencil_paint.brush
2025         return brush is not None and brush.gpencil_tool != 'ERASE'
2026
2027     def draw_header(self, context):
2028         brush = context.tool_settings.gpencil_paint.brush
2029         gp_settings = brush.gpencil_settings
2030         self.layout.prop(gp_settings, "use_settings_random", text="")
2031
2032     def draw(self, context):
2033         layout = self.layout
2034         layout.use_property_split = True
2035         layout.use_property_decorate = False
2036
2037         brush = context.tool_settings.gpencil_paint.brush
2038         gp_settings = brush.gpencil_settings
2039         layout.active = gp_settings.use_settings_random
2040
2041         layout.prop(gp_settings, "random_pressure", text="Pressure", slider=True)
2042         layout.prop(gp_settings, "random_strength", text="Strength", slider=True)
2043         layout.prop(gp_settings, "uv_random", text="UV", slider=True)
2044
2045         row = layout.row(align=True)
2046         row.prop(gp_settings, "pen_jitter", slider=True)
2047         row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
2048
2049
2050 # Grease Pencil drawingcurves
2051 class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel):
2052     bl_context = ".greasepencil_paint"
2053     bl_label = "Curves"
2054     bl_category = "Tool"
2055     bl_options = {'DEFAULT_CLOSED'}
2056
2057     @classmethod
2058     def poll(cls, context):
2059         brush = context.tool_settings.gpencil_paint.brush
2060         return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
2061
2062     def draw(self, context):
2063         pass
2064
2065
2066 class VIEW3D_PT_tools_grease_pencil_brushcurves_sensitivity(View3DPanel, Panel):
2067     bl_context = ".greasepencil_paint"
2068     bl_label = "Sensitivity"
2069     bl_category = "Tool"
2070     bl_parent_id = "VIEW3D_PT_tools_grease_pencil_brushcurves"
2071
2072     def draw(self, context):
2073         layout = self.layout
2074         layout.use_property_split = True
2075
2076         brush = context.tool_settings.gpencil_paint.brush
2077         gp_settings = brush.gpencil_settings
2078
2079         layout.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True,
2080                                       use_negative_slope=True)
2081
2082
2083 class VIEW3D_PT_tools_grease_pencil_brushcurves_strength(View3DPanel, Panel):
2084     bl_context = ".greasepencil_paint"
2085     bl_label = "Strength"
2086     bl_category = "Tool"
2087     bl_parent_id = "VIEW3D_PT_tools_grease_pencil_brushcurves"
2088
2089     def draw(self, context):
2090         layout = self.layout
2091         layout.use_property_split = True
2092
2093         brush = context.tool_settings.gpencil_paint.brush
2094         gp_settings = brush.gpencil_settings
2095
2096         layout.template_curve_mapping(gp_settings, "curve_strength", brush=True,
2097                                       use_negative_slope=True)
2098
2099
2100 class VIEW3D_PT_tools_grease_pencil_brushcurves_jitter(View3DPanel, Panel):
2101     bl_context = ".greasepencil_paint"
2102     bl_label = "Jitter"
2103     bl_category = "Tool"
2104     bl_parent_id = "VIEW3D_PT_tools_grease_pencil_brushcurves"
2105
2106     def draw(self, context):
2107         layout = self.layout
2108         layout.use_property_split = True
2109
2110         brush = context.tool_settings.gpencil_paint.brush
2111         gp_settings = brush.gpencil_settings
2112
2113         layout.template_curve_mapping(gp_settings, "curve_jitter", brush=True,
2114                                       use_negative_slope=True)
2115
2116
2117 # Grease Pencil stroke editing tools
2118 class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
2119     bl_space_type = 'VIEW_3D'
2120     bl_category = "Tool"
2121
2122
2123 # Grease Pencil stroke interpolation tools
2124 class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
2125     bl_space_type = 'VIEW_3D'
2126     bl_region_type = 'HEADER'
2127     bl_label = "Interpolate"
2128
2129     @classmethod
2130     def poll(cls, context):
2131         if context.gpencil_data is None:
2132             return False
2133
2134         gpd = context.gpencil_data
2135         return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
2136
2137     def draw(self, context):
2138         layout = self.layout
2139         settings = context.tool_settings.gpencil_interpolate
2140
2141         col = layout.column(align=True)
2142         col.label(text="Interpolate Strokes")
2143         col.operator("gpencil.interpolate", text="Interpolate")
2144         col.operator("gpencil.interpolate_sequence", text="Sequence")
2145         col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns")
2146
2147         col = layout.column(align=True)
2148         col.label(text="Options:")
2149         col.prop(settings, "interpolate_all_layers")
2150         col.prop(settings, "interpolate_selected_only")
2151
2152         col = layout.column(align=True)
2153         col.label(text="Sequence Options:")
2154         col.prop(settings, "type")
2155         if settings.type == 'CUSTOM':
2156             # TODO: Options for loading/saving curve presets?
2157             col.template_curve_mapping(settings, "interpolation_curve", brush=True,
2158                                        use_negative_slope=True)
2159         elif settings.type != 'LINEAR':
2160             col.prop(settings, "easing")
2161
2162             if settings.type == 'BACK':
2163                 layout.prop(settings, "back")
2164             elif settings.type == 'ELASTIC':
2165                 sub = layout.column(align=True)
2166                 sub.prop(settings, "amplitude")
2167                 sub.prop(settings, "period")
2168
2169
2170 # Grease Pencil stroke sculpting tools
2171 class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, View3DPanel, Panel):
2172     bl_context = ".greasepencil_sculpt"
2173     bl_category = "Tools"
2174     bl_label = "Brush"
2175     bl_category = "Tool"
2176
2177
2178 # Grease Pencil weight painting tools
2179 class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel):
2180     bl_context = ".greasepencil_weight"
2181     bl_category = "Tools"
2182     bl_label = "Brush"
2183     bl_category = "Tool"
2184
2185     def draw(self, context):
2186         layout = self.layout
2187         layout.use_property_split = True
2188         layout.use_property_decorate = False
2189
2190         settings = context.tool_settings.gpencil_sculpt
2191         brush = settings.brush
2192
2193         layout.template_icon_view(settings, "weight_tool", show_labels=True)
2194
2195         col = layout.column()
2196
2197         if not self.is_popover:
2198             from bl_ui.properties_paint_common import (
2199                 brush_basic_gpencil_weight_settings,
2200             )
2201             brush_basic_gpencil_weight_settings(col, context, brush)
2202
2203
2204 # Grease Pencil Brush Appearance (one for each mode)
2205 class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
2206     bl_context = ".greasepencil_paint"
2207     bl_label = "Display"
2208     bl_category = "Tool"
2209
2210
2211 class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
2212     bl_context = ".greasepencil_sculpt"
2213     bl_label = "Display"
2214     bl_category = "Tool"
2215
2216
2217 class VIEW3D_PT_tools_grease_pencil_sculpt_options(GreasePencilSculptOptionsPanel, View3DPanel, Panel):
2218     bl_context = ".greasepencil_sculpt"
2219     bl_label = "Sculpt Strokes"
2220     bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt'
2221     bl_category = "Tool"
2222
2223
2224 class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
2225     bl_context = ".greasepencil_weight"
2226     bl_label = "Display"
2227     bl_category = "Tool"
2228
2229
2230 class VIEW3D_PT_gpencil_brush_presets(PresetPanel, Panel):
2231     """Brush settings"""
2232     bl_label = "Brush Presets"
2233     preset_subdir = "gpencil_brush"
2234     preset_operator = "script.execute_preset"
2235     preset_add_operator = "scene.gpencil_brush_preset_add"
2236
2237
2238 classes = (
2239     VIEW3D_MT_brush_context_menu,
2240     VIEW3D_MT_brush_context_menu_paint_modes,
2241     VIEW3D_PT_tools_object_options,
2242     VIEW3D_PT_tools_object_options_transform,
2243     VIEW3D_PT_tools_meshedit_options,
2244     VIEW3D_PT_tools_meshedit_options_automerge,
2245     VIEW3D_PT_tools_curveedit_options_stroke,
2246     VIEW3D_PT_tools_armatureedit_options,
2247     VIEW3D_PT_tools_posemode_options,
2248     VIEW3D_PT_slots_projectpaint,
2249     VIEW3D_PT_tools_brush,
2250     VIEW3D_PT_tools_brush_color,
2251     VIEW3D_PT_tools_brush_swatches,
2252     VIEW3D_PT_tools_brush_clone,
2253     VIEW3D_PT_tools_brush_options,
2254     TEXTURE_UL_texpaintslots,
2255     VIEW3D_MT_tools_projectpaint_uvlayer,
2256     VIEW3D_PT_stencil_projectpaint,
2257     VIEW3D_PT_tools_brush_texture,
2258     VIEW3D_PT_tools_mask_texture,
2259     VIEW3D_PT_tools_brush_stroke,
2260     VIEW3D_PT_tools_brush_stroke_smooth_stroke,
2261     VIEW3D_PT_tools_brush_falloff,
2262     VIEW3D_PT_tools_brush_falloff_frontface,
2263     VIEW3D_PT_tools_brush_falloff_normal,
2264     VIEW3D_PT_tools_brush_display,
2265     VIEW3D_PT_tools_brush_display_show_brush,
2266     VIEW3D_PT_tools_brush_display_custom_icon,
2267     VIEW3D_PT_sculpt_dyntopo,
2268     VIEW3D_PT_sculpt_dyntopo_remesh,
2269     VIEW3D_PT_sculpt_voxel_remesh,
2270     VIEW3D_PT_sculpt_symmetry,
2271     VIEW3D_PT_sculpt_symmetry_for_topbar,
2272     VIEW3D_PT_sculpt_options,
2273     VIEW3D_PT_sculpt_options_unified,
2274     VIEW3D_PT_sculpt_options_gravity,
2275     VIEW3D_PT_tools_weightpaint_symmetry,
2276     VIEW3D_PT_tools_weightpaint_symmetry_for_topbar,
2277     VIEW3D_PT_tools_weightpaint_options,
2278     VIEW3D_PT_tools_weightpaint_options_unified,
2279     VIEW3D_PT_tools_vertexpaint_symmetry,
2280     VIEW3D_PT_tools_vertexpaint_symmetry_for_topbar,
2281     VIEW3D_PT_tools_vertexpaint_options,
2282     VIEW3D_PT_tools_imagepaint_symmetry,
2283     VIEW3D_PT_tools_imagepaint_options,
2284     VIEW3D_PT_tools_imagepaint_options_cavity,
2285     VIEW3D_PT_tools_imagepaint_options_unified,
2286     VIEW3D_PT_tools_imagepaint_options_external,
2287     VIEW3D_MT_tools_projectpaint_stencil,
2288     VIEW3D_PT_tools_particlemode,
2289     VIEW3D_PT_tools_particlemode_options,
2290     VIEW3D_PT_tools_particlemode_options_shapecut,
2291     VIEW3D_PT_tools_particlemode_options_display,
2292
2293     VIEW3D_PT_gpencil_brush_presets,
2294     VIEW3D_PT_tools_grease_pencil_brush,
2295     VIEW3D_PT_tools_grease_pencil_brush_option,
2296     VIEW3D_PT_tools_grease_pencil_brush_settings,
2297     VIEW3D_PT_tools_grease_pencil_brush_stabilizer,
2298     VIEW3D_PT_tools_grease_pencil_brush_random,
2299     VIEW3D_PT_tools_grease_pencil_brushcurves,
2300     VIEW3D_PT_tools_grease_pencil_brushcurves_sensitivity,
2301     VIEW3D_PT_tools_grease_pencil_brushcurves_strength,
2302     VIEW3D_PT_tools_grease_pencil_brushcurves_jitter,
2303     VIEW3D_PT_tools_grease_pencil_sculpt,
2304     VIEW3D_PT_tools_grease_pencil_weight_paint,
2305     VIEW3D_PT_tools_grease_pencil_paint_appearance,
2306     VIEW3D_PT_tools_grease_pencil_sculpt_options,
2307     VIEW3D_PT_tools_grease_pencil_sculpt_appearance,
2308     VIEW3D_PT_tools_grease_pencil_weight_appearance,
2309     VIEW3D_PT_tools_grease_pencil_interpolate,
2310 )
2311
2312 if __name__ == "__main__":  # only for live edit.
2313     from bpy.utils import register_class
2314     for cls in classes:
2315         register_class(cls)