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