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