UI: Re-organize Brush Properties

- Consolidate each brush section (Color, Palette, Gradient) and make them distinct
 - Remove the lock icons and move these items into an Options sub-panel, together with other toggles
  - They now have more descriptive names
  - Use an enum for view vs scene brush unit
 - Use Property Split layout and sub-panels in line with the rest of 2.8
 - Rename Curve panel to Falloff

Reviewed by: campbellbarton, pablovazquez

Maniphest Tasks: D4529

Differential Revision: https://developer.blender.org/D4529
This commit is contained in:
William Reynish 2019-03-19 18:17:50 +01:00
parent c590e80466
commit 83fc8342d8
Notes: blender-bot 2023-02-14 10:32:59 +01:00
Referenced by commit 2b5575cc35, Fix error displaying brush panel (sidebar) in Vertex Paint mode
5 changed files with 498 additions and 221 deletions

View File

@ -52,18 +52,18 @@ class UnifiedPaintPanel:
flow = parent.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
col = flow.column()
col.prop(ups, "use_unified_size", text="Size")
col.prop(ups, "use_unified_size", text="Unified Size")
col = flow.column()
col.prop(ups, "use_unified_strength", text="Strength")
col.prop(ups, "use_unified_strength", text="Unified Strength")
if context.weight_paint_object:
col = flow.column()
col.prop(ups, "use_unified_weight", text="Weight")
col.prop(ups, "use_unified_weight", text="Unified Weight")
elif context.vertex_paint_object or context.image_paint_object:
col = flow.column()
col.prop(ups, "use_unified_color", text="Color")
col.prop(ups, "use_unified_color", text="Unified Color")
else:
col = flow.column()
col.prop(ups, "use_unified_color", text="Color")
col.prop(ups, "use_unified_color", text="Unified Color")
@staticmethod
def prop_unified_size(parent, context, brush, prop_name, *, icon='NONE', text=None, slider=False):
@ -114,109 +114,102 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal
col = layout.column()
if capabilities.has_color:
if brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}:
if not brush.use_gradient:
panel.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
if settings.palette:
col.template_palette(settings, "palette", color=True)
if brush.use_gradient:
col.label(text="Gradient Colors")
col.template_color_ramp(brush, "gradient", expand=True)
if brush.image_tool == 'DRAW':
col.label(text="Background Color")
row = col.row(align=True)
panel.prop_unified_color(row, context, brush, "secondary_color", text="")
col.prop(brush, "gradient_stroke_mode", text="Mode")
if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
col.prop(brush, "grad_spacing")
else: # if brush.image_tool == 'FILL':
col.prop(brush, "gradient_fill_mode")
else:
row = col.row(align=True)
panel.prop_unified_color(row, context, brush, "color", text="")
if brush.image_tool == 'FILL' and not projpaint:
col.prop(brush, "fill_threshold")
else:
panel.prop_unified_color(row, context, brush, "secondary_color", text="")
row.separator()
row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
else:
if brush.blend in {'ERASE_ALPHA', 'ADD_ALPHA'}:
if brush.image_tool == 'FILL' and not projpaint:
col.prop(brush, "fill_threshold")
elif brush.image_tool == 'SOFTEN':
col = layout.column(align=True)
col.row().prop(brush, "direction", expand=True)
col.separator()
col.prop(brush, "sharp_threshold")
if not projpaint:
col.prop(brush, "blur_kernel_radius")
col.separator()
col.prop(brush, "blur_mode")
elif brush.image_tool == 'MASK':
col.prop(brush, "weight", text="Mask Value", slider=True)
elif brush.image_tool == 'CLONE':
col.separator()
if projpaint:
if settings.mode == 'MATERIAL':
col.prop(settings, "use_clone_layer", text="Clone from Paint Slot")
elif settings.mode == 'IMAGE':
col.prop(settings, "use_clone_layer", text="Clone from Image/UV Map")
if settings.use_clone_layer:
ob = context.active_object
col = layout.column()
if settings.mode == 'MATERIAL':
if len(ob.material_slots) > 1:
col.label(text="Materials")
col.template_list("MATERIAL_UL_matslots", "",
ob, "material_slots",
ob, "active_material_index", rows=2)
mat = ob.active_material
if mat:
col.label(text="Source Clone Slot")
col.template_list("TEXTURE_UL_texpaintslots", "",
mat, "texture_paint_images",
mat, "paint_clone_slot", rows=2)
elif settings.mode == 'IMAGE':
mesh = ob.data
clone_text = mesh.uv_layer_clone.name if mesh.uv_layer_clone else ""
col.label(text="Source Clone Image")
col.template_ID(settings, "clone_image")
col.label(text="Source Clone UV Map")
col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
else:
if not projpaint:
col.prop(brush, "clone_image", text="Image")
col.prop(brush, "clone_alpha", text="Alpha")
col.separator()
if not panel.is_popover:
brush_basic_texpaint_settings(col, context, brush)
def brush_texpaint_common_clone(panel, context, layout, brush, settings, projpaint=False):
capabilities = brush.image_paint_capabilities
ob = context.active_object
col = layout.column()
if settings.mode == 'MATERIAL':
if len(ob.material_slots) > 1:
col.label(text="Materials")
col.template_list("MATERIAL_UL_matslots", "",
ob, "material_slots",
ob, "active_material_index", rows=2)
mat = ob.active_material
if mat:
col.label(text="Source Clone Slot")
col.template_list("TEXTURE_UL_texpaintslots", "",
mat, "texture_paint_images",
mat, "paint_clone_slot", rows=2)
elif settings.mode == 'IMAGE':
mesh = ob.data
clone_text = mesh.uv_layer_clone.name if mesh.uv_layer_clone else ""
col.label(text="Source Clone Image")
col.template_ID(settings, "clone_image")
col.label(text="Source Clone UV Map")
col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
def brush_texpaint_common_color(panel, context, layout, brush, settings, projpaint=False):
capabilities = brush.image_paint_capabilities
UnifiedPaintPanel.prop_unified_color_picker(layout, context, brush, "color", value_slider=True)
row = layout.row(align=True)
UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="")
UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="")
row.separator()
row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="", emboss=False)
def brush_texpaint_common_gradient(panel, context, layout, brush, settings, projpaint=False):
capabilities = brush.image_paint_capabilities
layout.template_color_ramp(brush, "gradient", expand=True)
layout.use_property_split = True
col = layout.column()
if brush.image_tool == 'DRAW':
UnifiedPaintPanel.prop_unified_color(col, context, brush, "secondary_color", text="Background Color")
col.prop(brush, "gradient_stroke_mode", text="Mode")
if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
col.prop(brush, "grad_spacing")
else: # if brush.image_tool == 'FILL':
col.prop(brush, "gradient_fill_mode")
def brush_texpaint_common_options(panel, context, layout, brush, settings, projpaint=False):
capabilities = brush.image_paint_capabilities
col = layout.column()
# use_accumulate
if capabilities.has_accumulate:
col = layout.column(align=True)
col.prop(brush, "use_accumulate")
if capabilities.has_space_attenuation:
col.prop(brush, "use_space_attenuation")
if projpaint:
col.prop(brush, "use_alpha")
col.prop(brush, "use_gradient")
col.separator()
col.template_ID(settings, "palette", new="palette.new")
# Used in both the View3D toolbar and texture properties
def brush_texture_settings(layout, brush, sculpt):
@ -316,7 +309,6 @@ def brush_basic_wpaint_settings(layout, context, brush, *, compact=False):
UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength")
UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
layout.separator()
layout.prop(brush, "blend", text="" if compact else "Blend")
@ -333,7 +325,6 @@ def brush_basic_vpaint_settings(layout, context, brush, *, compact=False):
if capabilities.has_color:
layout.separator()
layout.prop(brush, "blend", text="" if compact else "Blend")
@ -347,28 +338,25 @@ def brush_basic_texpaint_settings(layout, context, brush, *, compact=False):
row = layout.row(align=True)
if capabilities.has_space_attenuation:
row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength")
UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
if capabilities.has_color:
layout.separator()
layout.prop(brush, "blend", text="" if compact else "Blend")
def brush_basic_sculpt_settings(layout, context, brush, *, compact=False):
tool_settings = context.tool_settings
capabilities = brush.sculpt_capabilities
settings = tool_settings.gpencil_sculpt
tool = settings.sculpt_tool
row = layout.row(align=True)
UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_locked_size", text="")
ups = tool_settings.unified_paint_settings
if (
(ups.use_unified_size and ups.use_locked_size) or
((not ups.use_unified_size) and brush.use_locked_size)
(ups.use_unified_size and ups.use_locked_size == 'SCENE') or
((not ups.use_unified_size) and brush.use_locked_size == 'SCENE')
):
UnifiedPaintPanel.prop_unified_size(row, context, brush, "unprojected_radius", slider=True, text="Radius")
else:
@ -377,20 +365,16 @@ def brush_basic_sculpt_settings(layout, context, brush, *, compact=False):
UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
# strength, use_strength_pressure, and use_strength_attenuation
layout.separator()
row = layout.row(align=True)
if capabilities.has_space_attenuation:
row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength")
if capabilities.has_strength_pressure:
UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
# direction
layout.separator()
layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {}))
if capabilities.has_direction == False:
layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {}))
def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=True):

View File

@ -28,6 +28,10 @@ from .properties_paint_common import (
UnifiedPaintPanel,
brush_texture_settings,
brush_texpaint_common,
brush_texpaint_common_color,
brush_texpaint_common_gradient,
brush_texpaint_common_clone,
brush_texpaint_common_options,
brush_mask_texture_settings,
)
from .properties_grease_pencil_common import (
@ -842,6 +846,9 @@ class IMAGE_PT_paint(Panel, ImagePaintPanel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.tool_settings.image_paint
brush = settings.brush
@ -852,6 +859,135 @@ class IMAGE_PT_paint(Panel, ImagePaintPanel):
brush_texpaint_common(self, context, layout, brush, settings)
class IMAGE_PT_paint_color(Panel, ImagePaintPanel):
bl_context = ".paint_common_2d"
bl_parent_id = "IMAGE_PT_paint"
bl_label = "Color Picker"
@classmethod
def poll(self, context):
settings = context.tool_settings.image_paint
brush = settings.brush
capabilities = brush.image_paint_capabilities
return capabilities.has_color
def draw(self, context):
layout = self.layout
settings = context.tool_settings.image_paint
brush = settings.brush
layout.active = brush.use_gradient == False
brush_texpaint_common_color(self, context, layout, brush, settings, True)
class IMAGE_PT_paint_swatches(Panel, ImagePaintPanel):
bl_context = ".paint_common_2d"
bl_parent_id = "IMAGE_PT_paint"
bl_label = "Color Palette"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, context):
settings = context.tool_settings.image_paint
brush = settings.brush
capabilities = brush.image_paint_capabilities
return capabilities.has_color
def draw(self, context):
layout = self.layout
settings = context.tool_settings.image_paint
layout.template_ID(settings, "palette", new="palette.new")
if settings.palette:
layout.template_palette(settings, "palette", color=True)
class IMAGE_PT_paint_gradient(Panel, ImagePaintPanel):
bl_context = ".paint_common_2d"
bl_parent_id = "IMAGE_PT_paint"
bl_label = "Gradient"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, context):
settings = context.tool_settings.image_paint
brush = settings.brush
capabilities = brush.image_paint_capabilities
return capabilities.has_color
def draw_header(self, context):
settings = self.paint_settings(context)
brush = settings.brush
self.layout.prop(brush, "use_gradient", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = False
layout.use_property_decorate = False # No animation.
settings = context.tool_settings.image_paint
brush = settings.brush
layout.active = brush.use_gradient
brush_texpaint_common_gradient(self, context, layout, brush, settings, True)
class IMAGE_PT_paint_clone(Panel, ImagePaintPanel):
bl_context = ".paint_common_2d"
bl_parent_id = "IMAGE_PT_paint"
bl_label = "Clone from Image/UV Map"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, context):
settings = self.paint_settings(context)
brush = settings.brush
return brush.image_tool == 'CLONE'
def draw_header(self, context):
settings = context.tool_settings.image_paint
self.layout.prop(settings, "use_clone_layer", text="")
def draw(self, context):
layout = self.layout
settings = context.tool_settings.image_paint
brush = settings.brush
layout.active = settings.use_clone_layer
brush_texpaint_common_clone(self, context, layout, brush, settings, True)
class IMAGE_PT_paint_options(Panel, ImagePaintPanel):
bl_context = ".paint_common_2d"
bl_parent_id = "IMAGE_PT_paint"
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, context):
settings = context.tool_settings.image_paint
brush = settings.brush
capabilities = brush.image_paint_capabilities
return capabilities.has_color
def draw(self, context):
layout = self.layout
settings = context.tool_settings.image_paint
brush = settings.brush
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
brush_texpaint_common_options(self, context, layout, brush, settings, True)
class IMAGE_PT_tools_brush_display(BrushButtonsPanel, Panel):
bl_label = "Display"
bl_context = ".paint_common_2d"
@ -1022,7 +1158,7 @@ class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel):
class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
bl_label = "Curve"
bl_label = "Falloff"
bl_context = ".paint_common_2d"
bl_options = {'DEFAULT_CLOSED'}
bl_category = "Tools"
@ -1351,11 +1487,16 @@ classes = (
IMAGE_PT_view_display_uv_edit_overlays,
IMAGE_PT_view_display_uv_edit_overlays_advanced,
IMAGE_PT_paint,
IMAGE_PT_tools_brush_display,
IMAGE_PT_paint_color,
IMAGE_PT_paint_swatches,
IMAGE_PT_paint_gradient,
IMAGE_PT_paint_clone,
IMAGE_PT_paint_options,
IMAGE_PT_tools_brush_texture,
IMAGE_PT_tools_mask_texture,
IMAGE_PT_paint_stroke,
IMAGE_PT_paint_curve,
IMAGE_PT_tools_brush_display,
IMAGE_PT_tools_imagepaint_symmetry,
IMAGE_PT_tools_brush_appearance,
IMAGE_PT_uv_sculpt,

View File

@ -29,6 +29,10 @@ from .properties_paint_common import (
UnifiedPaintPanel,
brush_mask_texture_settings,
brush_texpaint_common,
brush_texpaint_common_color,
brush_texpaint_common_gradient,
brush_texpaint_common_clone,
brush_texpaint_common_options,
brush_texture_settings,
)
from bl_ui.utils import PresetPanel
@ -273,12 +277,16 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
tool_settings = context.tool_settings
settings = self.paint_settings(context)
brush = settings.brush
col = layout.split().column()
col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
if not self.is_popover:
col = layout.split().column()
col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8)
# Sculpt Mode #
if context.sculpt_object and brush:
@ -290,8 +298,6 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
col = layout.column()
col.separator()
if not self.is_popover:
brush_basic_sculpt_settings(col, context, brush)
@ -299,47 +305,32 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
if (capabilities.has_topology_rake and
context.sculpt_object.use_dynamic_topology_sculpting
):
col.separator()
row = col.row()
row.prop(brush, "topology_rake_factor", slider=True)
# auto_smooth_factor and use_inverse_smooth_pressure
if capabilities.has_auto_smooth:
col.separator()
row = col.row(align=True)
row.prop(brush, "auto_smooth_factor", slider=True)
row.prop(brush, "use_inverse_smooth_pressure", toggle=True, text="")
# normal_weight
if capabilities.has_normal_weight:
col.separator()
row = col.row(align=True)
row.prop(brush, "normal_weight", slider=True)
# crease_pinch_factor
if capabilities.has_pinch_factor:
col.separator()
row = col.row(align=True)
row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
# rake_factor
if capabilities.has_rake_factor:
col.separator()
row = col.row(align=True)
row.prop(brush, "rake_factor", slider=True)
# use_original_normal and sculpt_plane
if capabilities.has_sculpt_plane:
col.separator()
row = col.row(align=True)
row.prop(brush, "use_original_normal", toggle=True, icon_only=True)
row.prop(brush, "sculpt_plane", text="")
if brush.sculpt_tool == 'MASK':
col.prop(brush, "mask_tool", text="")
col.prop(brush, "mask_tool")
# plane_offset, use_offset_pressure, use_plane_trim, plane_trim
if capabilities.has_plane_offset:
@ -350,7 +341,7 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
col.separator()
row = col.row()
row.prop(brush, "use_plane_trim", text="Trim")
row.prop(brush, "use_plane_trim", text="Plane Trim")
row = col.row()
row.active = brush.use_plane_trim
row.prop(brush, "plane_trim", slider=True, text="Distance")
@ -360,21 +351,8 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
row = col.row()
row.prop(brush, "height", slider=True, text="Height")
# use_frontface
col.separator()
col.prop(brush, "use_frontface", text="Front Faces Only")
col.prop(brush, "use_projected")
# use_accumulate
if capabilities.has_accumulate:
col.separator()
col.prop(brush, "use_accumulate")
# use_persistent, set_persistent_base
if capabilities.has_persistence:
col.separator()
ob = context.sculpt_object
do_persistent = True
@ -404,62 +382,178 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
if not self.is_popover:
brush_basic_wpaint_settings(col, context, brush)
if brush.weight_tool != 'SMEAR':
col.prop(brush, "use_accumulate")
col.separator()
col.prop(brush, "use_frontface", text="Front Faces Only")
row = col.row()
row.prop(brush, "use_frontface_falloff", text="Falloff Angle")
sub = row.row()
sub.active = brush.use_frontface_falloff
sub.prop(brush, "falloff_angle", text="")
col.prop(brush, "use_projected")
col = layout.column()
col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize")
col.prop(tool_settings, "use_multipaint", text="Multi-Paint")
# Vertex Paint Mode #
elif context.vertex_paint_object and brush:
from .properties_paint_common import (
brush_basic_vpaint_settings,
)
col = layout.column()
self.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
if settings.palette:
col.template_palette(settings, "palette", color=True)
row = col.row(align=True)
self.prop_unified_color(row, context, brush, "color", text="")
self.prop_unified_color(row, context, brush, "secondary_color", text="")
row.separator()
row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
col.separator()
if not self.is_popover:
brush_basic_vpaint_settings(col, context, brush)
col.prop(brush, "use_alpha")
class VIEW3D_PT_tools_brush_color(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_parent_id = "VIEW3D_PT_tools_brush"
bl_label = "Color Picker"
@classmethod
def poll(self, context):
settings = self.paint_settings(context)
brush = settings.brush
capabilities = brush.image_paint_capabilities
return capabilities.has_color and (context.image_paint_object or context.vertex_paint_object)
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
brush = settings.brush
layout.active = brush.use_gradient == False
brush_texpaint_common_color(self, context, layout, brush, settings, True)
class VIEW3D_PT_tools_brush_swatches(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_parent_id = "VIEW3D_PT_tools_brush"
bl_label = "Color Palette"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, context):
settings = self.paint_settings(context)
brush = settings.brush
capabilities = brush.image_paint_capabilities
return capabilities.has_color and (context.image_paint_object or context.vertex_paint_object)
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
layout.template_ID(settings, "palette", new="palette.new")
if settings.palette:
layout.template_palette(settings, "palette", color=True)
class VIEW3D_PT_tools_brush_gradient(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_parent_id = "VIEW3D_PT_tools_brush"
bl_label = "Gradient"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, context):
settings = self.paint_settings(context)
brush = settings.brush
capabilities = brush.image_paint_capabilities
return capabilities.has_color and context.image_paint_object
def draw_header(self, context):
settings = self.paint_settings(context)
brush = settings.brush
self.layout.prop(brush, "use_gradient", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = False
layout.use_property_decorate = False # No animation.
settings = self.paint_settings(context)
brush = settings.brush
layout.active = brush.use_gradient
brush_texpaint_common_gradient(self, context, layout, brush, settings, True)
class VIEW3D_PT_tools_brush_clone(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_parent_id = "VIEW3D_PT_tools_brush"
bl_label = "Clone from Paint Slot"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(self, context):
settings = self.paint_settings(context)
brush = settings.brush
return brush.image_tool == 'CLONE'
def draw_header(self, context):
settings = self.paint_settings(context)
self.layout.prop(settings, "use_clone_layer", text="")
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
brush = settings.brush
layout.active = settings.use_clone_layer
brush_texpaint_common_clone(self, context, layout, brush, settings, True)
class VIEW3D_PT_tools_brush_options(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_parent_id = "VIEW3D_PT_tools_brush"
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
tool_settings = context.tool_settings
settings = self.paint_settings(context)
brush = settings.brush
capabilities = brush.sculpt_capabilities
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
col = layout.column()
if context.image_paint_object and brush:
brush_texpaint_common_options(self, context, layout, brush, settings, True)
elif context.sculpt_object and brush:
if capabilities.has_accumulate:
col.prop(brush, "use_accumulate", text="Airbrush")
UnifiedPaintPanel.prop_unified_size(col, context, brush, "use_locked_size")
if capabilities.has_sculpt_plane:
col.prop(brush, "sculpt_plane")
col.prop(brush, "use_original_normal")
if capabilities.has_space_attenuation:
col.prop(brush, "use_space_attenuation")
col.prop(brush, "use_frontface", text="Front Faces Only")
col.prop(brush, "use_projected")
elif context.weight_paint_object and brush:
if brush.weight_tool != 'SMEAR':
col.prop(brush, "use_accumulate")
col.prop(brush, "use_frontface", text="Front Faces Only")
col.prop(brush, "use_projected")
col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize")
col.prop(tool_settings, "use_multipaint", text="Multi-Paint")
elif context.vertex_paint_object and brush:
if brush.vertex_tool != 'SMEAR':
col.prop(brush, "use_accumulate")
col.separator()
col.prop(brush, "use_alpha")
col.prop(brush, "use_frontface", text="Front Faces Only")
row = col.row()
row.prop(brush, "use_frontface_falloff", text="Falloff Angle")
sub = row.row()
sub.active = brush.use_frontface_falloff
sub.prop(brush, "falloff_angle", text="")
col.prop(brush, "use_projected")
col.separator()
col.template_ID(settings, "palette", new="palette.new")
class TEXTURE_UL_texpaintslots(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
@ -826,9 +920,9 @@ class VIEW3D_PT_tools_brush_stroke_smooth_stroke(Panel, View3DPaintPanel):
# TODO, move to space_view3d.py
class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel):
class VIEW3D_PT_tools_brush_falloff(Panel, View3DPaintPanel):
bl_context = ".paint_common" # dot on purpose (access from topbar)
bl_label = "Curve"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
@ -838,9 +932,7 @@ class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel):
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
brush = settings.brush
layout.template_curve_mapping(brush, "curve", brush=True)
@ -855,6 +947,64 @@ class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel):
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
class VIEW3D_PT_tools_brush_falloff_frontface(View3DPaintPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Frontface Falloff"
bl_parent_id = "VIEW3D_PT_tools_brush_falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.weight_paint_object or context.vertex_paint_object)
def draw_header(self, context):
settings = self.paint_settings(context)
brush = settings.brush
self.layout.prop(brush, "use_frontface_falloff", text="")
def draw(self, context):
settings = self.paint_settings(context)
brush = settings.brush
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
layout.active = brush.use_frontface_falloff
layout.prop(brush, "falloff_angle", text="Angle")
class VIEW3D_PT_tools_brush_falloff_normal(View3DPaintPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Normal Falloff"
bl_parent_id = "VIEW3D_PT_tools_brush_falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return context.image_paint_object
def draw_header(self, context):
tool_settings = context.tool_settings
ipaint = tool_settings.image_paint
self.layout.prop(ipaint, "use_normal_falloff", text="")
def draw(self, context):
tool_settings = context.tool_settings
ipaint = tool_settings.image_paint
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
layout.active = ipaint.use_normal_falloff
layout.prop(ipaint, "normal_angle", text="Angle")
# TODO, move to space_view3d.py
class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel):
bl_context = ".sculpt_mode" # dot on purpose (access from topbar)
@ -1173,6 +1323,7 @@ class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel):
class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
bl_context = ".weightpaint"
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
@ -1200,9 +1351,11 @@ class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
class VIEW3D_PT_tools_vertexpaint(Panel, View3DPaintPanel):
bl_context = ".vertexpaint" # dot on purpose (access from topbar)
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
col = layout.column()
@ -1310,31 +1463,6 @@ class VIEW3D_PT_tools_projectpaint(View3DPaintPanel, Panel):
col.prop(ipaint, "use_backface_culling", text="Backface Culling")
class VIEW3D_PT_tools_projectpaint_normal(View3DPaintPanel, Panel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_label = "Normal"
bl_parent_id = "VIEW3D_PT_tools_projectpaint"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
tool_settings = context.tool_settings
ipaint = tool_settings.image_paint
self.layout.prop(ipaint, "use_normal_falloff", text="")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
tool_settings = context.tool_settings
ipaint = tool_settings.image_paint
layout.active = ipaint.use_normal_falloff
layout.prop(ipaint, "normal_angle", text="Angle")
class VIEW3D_PT_tools_projectpaint_unified(Panel, View3DPaintPanel):
bl_context = ".imagepaint" # dot on purpose (access from topbar)
bl_parent_id = "VIEW3D_PT_tools_projectpaint"
@ -1879,15 +2007,22 @@ classes = (
VIEW3D_PT_tools_posemode_options,
VIEW3D_PT_slots_projectpaint,
VIEW3D_PT_tools_brush,
VIEW3D_PT_tools_brush_color,
VIEW3D_PT_tools_brush_swatches,
VIEW3D_PT_tools_brush_gradient,
VIEW3D_PT_tools_brush_clone,
VIEW3D_PT_tools_brush_options,
TEXTURE_UL_texpaintslots,
VIEW3D_MT_tools_projectpaint_uvlayer,
VIEW3D_PT_stencil_projectpaint,
VIEW3D_PT_tools_brush_display,
VIEW3D_PT_tools_brush_texture,
VIEW3D_PT_tools_mask_texture,
VIEW3D_PT_tools_brush_stroke,
VIEW3D_PT_tools_brush_stroke_smooth_stroke,
VIEW3D_PT_tools_brush_curve,
VIEW3D_PT_tools_brush_falloff,
VIEW3D_PT_tools_brush_falloff_frontface,
VIEW3D_PT_tools_brush_falloff_normal,
VIEW3D_PT_tools_brush_display,
VIEW3D_PT_sculpt_dyntopo,
VIEW3D_PT_sculpt_dyntopo_remesh,
VIEW3D_PT_sculpt_options,
@ -1904,7 +2039,6 @@ classes = (
VIEW3D_PT_tools_imagepaint_external,
VIEW3D_PT_tools_imagepaint_symmetry,
VIEW3D_PT_tools_projectpaint,
VIEW3D_PT_tools_projectpaint_normal,
VIEW3D_PT_tools_projectpaint_cavity,
VIEW3D_MT_tools_projectpaint_stencil,
VIEW3D_PT_tools_projectpaint_unified,

View File

@ -346,6 +346,16 @@ static bool rna_TextureCapabilities_has_texture_angle_get(PointerRNA *ptr)
return mtex->brush_map_mode != MTEX_MAP_MODE_3D;
}
static bool rna_BrushCapabilitiesSculpt_has_direction_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
return !ELEM(br->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_CLAY,
SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE,
SCULPT_TOOL_BLOB, SCULPT_TOOL_CREASE, SCULPT_TOOL_FLATTEN,
SCULPT_TOOL_FILL, SCULPT_TOOL_SCRAPE, SCULPT_TOOL_CLAY,
SCULPT_TOOL_PINCH, SCULPT_TOOL_MASK);
}
static bool rna_BrushCapabilitiesSculpt_has_gravity_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
@ -880,6 +890,7 @@ static void rna_def_sculpt_capabilities(BlenderRNA *brna)
SCULPT_TOOL_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke");
SCULPT_TOOL_CAPABILITY(has_space_attenuation, "Has Space Attenuation");
SCULPT_TOOL_CAPABILITY(has_strength_pressure, "Has Strength Pressure");
SCULPT_TOOL_CAPABILITY(has_direction, "Has Direction");
SCULPT_TOOL_CAPABILITY(has_gravity, "Has Gravity");
#undef SCULPT_CAPABILITY
@ -1423,6 +1434,12 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem brush_size_unit_items[] = {
{0, "VIEW", 0, "View", "Measure brush size relateve to the view"},
{BRUSH_LOCK_SIZE, "SCENE", 0, "Scene", "Measure brush size relateve to the scene"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(srna, "Brush", "Brush data-block for storing brush settings for painting and sculpting");
RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
@ -1723,7 +1740,6 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_original_normal", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ORIGINAL_NORMAL);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true);
RNA_def_property_ui_text(prop, "Original Normal",
"When locked keep using normal of surface where stroke was initiated");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@ -1829,13 +1845,12 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_accumulate", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ACCUMULATE);
RNA_def_property_ui_text(prop, "Accumulate", "Accumulate stroke daubs on top of each other");
RNA_def_property_ui_text(prop, "Airbrush", "Accumulate stroke daubs on top of each other");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_space_attenuation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SPACE_ATTEN);
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true);
RNA_def_property_ui_text(prop, "Use Automatic Strength Adjustment",
RNA_def_property_ui_text(prop, "Adjust Strength for Spacing",
"Automatically adjust strength to give consistent results for different spacings");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@ -1846,12 +1861,10 @@ static void rna_def_brush(BlenderRNA *brna)
"Space daubs according to surface orientation instead of screen space");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_locked_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_LOCK_SIZE);
RNA_def_property_ui_text(prop, "Use Blender Units",
"When locked brush stays same size relative to object; when unlocked brush size is "
"given in pixels");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true);
prop = RNA_def_property(srna, "use_locked_size", PROP_ENUM, PROP_NONE); /* as an enum */
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, brush_size_unit_items);
RNA_def_property_ui_text(prop, "Radius Unit", "Measure brush size relative to the view or the scene");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_edge_to_edge", PROP_BOOLEAN, PROP_NONE);
@ -1867,7 +1880,7 @@ static void rna_def_brush(BlenderRNA *brna)
/* only for projection paint & vertex paint, TODO, other paint modes */
prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BRUSH_LOCK_ALPHA);
RNA_def_property_ui_text(prop, "Alpha", "When this is disabled, lock alpha while painting");
RNA_def_property_ui_text(prop, "Affect Alpha", "When this is disabled, lock alpha while painting");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);

View File

@ -2931,6 +2931,12 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem brush_size_unit_items[] = {
{0, "VIEW", 0, "View", "Measure brush size relateve to the view"},
{UNIFIED_PAINT_BRUSH_LOCK_SIZE, "SCENE", 0, "Scene", "Measure brush size relateve to the scene"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "UnifiedPaintSettings", NULL);
RNA_def_struct_path_func(srna, "rna_UnifiedPaintSettings_path");
RNA_def_struct_ui_text(srna, "Unified Paint Settings", "Overrides for some of the active brush's settings");
@ -3016,12 +3022,11 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength");
prop = RNA_def_property(srna, "use_locked_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_BRUSH_LOCK_SIZE);
RNA_def_property_ui_text(prop, "Use Blender Units",
"When locked brush stays same size relative to object; "
"when unlocked brush size is given in pixels");
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true);
prop = RNA_def_property(srna, "use_locked_size", PROP_ENUM, PROP_NONE); /* as an enum */
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, brush_size_unit_items);
RNA_def_property_ui_text(prop, "Radius Unit", "Measure brush size relative to the view or the scene ");
}