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