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