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