UI: Add ability to collapse paint pressure curves

This commit builds off of 5f8311f596 to support collapsing the custom
paint curve to reduce the amount of information shown to the user.

To support this, a new field is added to the `Paint` struct for this
visibility flag. This value is stored on a per-mode level, not a
per-brush level, as a user editing this curve is likely to not need
the visibility granularity on a per-brush basis.

Additionally, changes are included here to draw the curve button
itself as inactive if the parent layout it is part of is inactive.
Notably, this does not make the curve read only - it only changes
the appearance.

Pull Request: https://projects.blender.org/blender/blender/pulls/145699
This commit is contained in:
Sean Kim
2025-09-15 14:45:50 +02:00
committed by Sean Kim
parent 433b61ccac
commit 5b02341a11
6 changed files with 96 additions and 21 deletions

View File

@@ -261,6 +261,7 @@ class UnifiedPaintPanel:
unified_paint_settings_override=None,
unified_name=None,
pressure_name=None,
curve_visibility_name=None,
icon='NONE',
text=None,
slider=False,
@@ -272,6 +273,7 @@ class UnifiedPaintPanel:
:param unified_paint_settings_override allows a caller to pass in a specific object for usage. Needed for
some 'brush-like' tools."""
row = layout.row(align=True)
paint = UnifiedPaintPanel.paint_settings(context)
if unified_paint_settings_override:
ups = unified_paint_settings_override
else:
@@ -282,13 +284,21 @@ class UnifiedPaintPanel:
row.prop(prop_owner, prop_name, icon=icon, text=text, slider=slider)
if pressure_name:
row.prop(brush, pressure_name, text="")
if unified_name and not header:
# NOTE: We don't draw UnifiedPaintSettings in the header to reduce clutter. D5928#136281
row.prop(ups, unified_name, text="", icon='BRUSHES_ALL')
if pressure_name:
row.prop(brush, pressure_name, text="")
if curve_visibility_name and not header:
is_active = getattr(paint, curve_visibility_name)
row.prop(
paint,
curve_visibility_name,
text="",
icon='DOWNARROW_HLT' if is_active else 'RIGHTARROW',
emboss=False)
return row
@staticmethod
@@ -551,10 +561,19 @@ class StrokePanel(BrushPanel):
else:
row.prop(brush, "jitter_absolute")
row.prop(brush, "use_pressure_jitter", toggle=True, text="")
col.row().prop(brush, "jitter_unit", expand=True)
if self.is_popover is False:
row.prop(
settings,
"show_jitter_curve",
icon='DOWNARROW_HLT' if settings.show_jitter_curve else 'RIGHTARROW',
text="",
emboss=False)
# Pen pressure mapping curve for Jitter.
if brush.use_pressure_jitter and self.is_popover is False:
col.template_curve_mapping(brush, "curve_jitter", brush=True)
if settings.show_jitter_curve and self.is_popover is False:
subcol = col.column()
subcol.active = brush.use_pressure_jitter
subcol.template_curve_mapping(brush, "curve_jitter", brush=True)
col.row().prop(brush, "jitter_unit", expand=True)
col.separator()
UnifiedPaintPanel.prop_unified(
@@ -1052,6 +1071,7 @@ def brush_settings(layout, context, brush, popover=False):
def brush_shared_settings(layout, context, brush, popover=False):
""" Draw simple brush settings that are shared between different paint modes. """
paint = UnifiedPaintPanel.paint_settings(context)
mode = UnifiedPaintPanel.get_brush_mode(context)
### Determine which settings to draw. ###
@@ -1146,18 +1166,22 @@ def brush_shared_settings(layout, context, brush, popover=False):
size_prop,
unified_name="use_unified_size",
pressure_name="use_pressure_size",
curve_visibility_name="show_size_curve",
text="Size",
slider=True,
)
if mode in {'PAINT_TEXTURE', 'PAINT_2D', 'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT', 'SCULPT_CURVES'}:
if brush.use_pressure_size:
layout.template_curve_mapping(brush, "curve_size", brush=True)
if paint.show_size_curve and not popover:
subcol = layout.column()
subcol.active = brush.use_pressure_size
subcol.template_curve_mapping(brush, "curve_size", brush=True)
if size_mode:
layout.row().prop(size_owner, "use_locked_size", expand=True)
layout.separator()
if strength:
pressure_name = "use_pressure_strength" if strength_pressure else None
curve_visibility_name = "show_strength_curve" if strength_pressure else None
UnifiedPaintPanel.prop_unified(
layout,
context,
@@ -1165,11 +1189,14 @@ def brush_shared_settings(layout, context, brush, popover=False):
"strength",
unified_name="use_unified_strength",
pressure_name=pressure_name,
curve_visibility_name=curve_visibility_name,
slider=True,
)
if mode in {'PAINT_TEXTURE', 'PAINT_2D', 'SCULPT', 'PAINT_VERTEX', 'PAINT_WEIGHT', 'SCULPT_CURVES'}:
if strength_pressure and brush.use_pressure_strength:
layout.template_curve_mapping(brush, "curve_strength", brush=True)
if paint.show_strength_curve and not popover:
subcol = layout.column()
subcol.active = brush.use_pressure_strength
subcol.template_curve_mapping(brush, "curve_strength", brush=True)
layout.separator()
if direction:

View File

@@ -1616,12 +1616,23 @@ static void gl_shaded_color(const uchar *color, int shade)
immUniformColor3ubv(color_shaded);
}
static void gl_shaded_color(const uchar *color, int shade, uchar alpha)
{
uchar color_shaded[3];
gl_shaded_color_get(color, shade, color_shaded);
immUniformColor3ubvAlpha(color_shaded, alpha);
}
void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
{
uiButCurveMapping *but_cumap = (uiButCurveMapping *)but;
CurveMapping *cumap = (but_cumap->edit_cumap == nullptr) ? (CurveMapping *)but->poin :
but_cumap->edit_cumap;
const bool inactive = but->flag & UI_BUT_INACTIVE;
const uchar alpha = inactive ? 192 : 255;
const float float_alpha = inactive ? 0.75f : 1.0f;
const float clip_size_x = BLI_rctf_size_x(&cumap->curr);
const float clip_size_y = BLI_rctf_size_y(&cumap->curr);
@@ -1682,20 +1693,19 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
/* backdrop */
float color_backdrop[4] = {0, 0, 0, 1};
GPU_blend(GPU_BLEND_ALPHA);
if (but_cumap->gradient_type == UI_GRAD_H) {
/* grid, hsv uses different grid */
GPU_blend(GPU_BLEND_ALPHA);
ARRAY_SET_ITEMS(color_backdrop, 0, 0, 0, 48.0 / 255.0);
immUniformColor4fv(color_backdrop);
ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.1666666f);
GPU_blend(GPU_BLEND_NONE);
}
else {
if (cumap->flag & CUMA_DO_CLIP) {
gl_shaded_color_get_fl(wcol->inner, -20, color_backdrop);
immUniformColor3fv(color_backdrop);
immUniformColor3fvAlpha(color_backdrop, float_alpha);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
immUniformColor3ubv(wcol->inner);
immUniformColor3ubvAlpha(wcol->inner, alpha);
immRectf(pos,
rect->xmin + zoomx * (cumap->clipr.xmin - offsx),
rect->ymin + zoomy * (cumap->clipr.ymin - offsy),
@@ -1704,18 +1714,18 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
}
else {
rgb_uchar_to_float(color_backdrop, wcol->inner);
immUniformColor3fv(color_backdrop);
immUniformColor3fvAlpha(color_backdrop, float_alpha);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
}
/* grid, every 0.25 step */
gl_shaded_color(wcol->inner, -16);
gl_shaded_color(wcol->inner, -16, alpha);
ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 0.25f);
/* grid, every 1.0 step */
gl_shaded_color(wcol->inner, -24);
gl_shaded_color(wcol->inner, -24, alpha);
ui_draw_but_curve_grid(pos, rect, zoomx, zoomy, offsx, offsy, 1.0f);
/* axes */
gl_shaded_color(wcol->inner, -50);
gl_shaded_color(wcol->inner, -50, alpha);
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, rect->xmin, rect->ymin + zoomy * (-offsy));
immVertex2f(pos, rect->xmax, rect->ymin + zoomy * (-offsy));
@@ -1723,6 +1733,7 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
immVertex2f(pos, rect->xmin + zoomx * (-offsx), rect->ymax);
immEnd();
}
GPU_blend(GPU_BLEND_NONE);
/* cfra option */
/* XXX 2.48 */
@@ -1800,11 +1811,12 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
line_range.ymax = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]);
}
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* Curve filled. */
immUniformColor3ubvAlpha(wcol->item, 128);
uchar filled_alpha = inactive ? 64 : 128;
immUniformColor3ubvAlpha(wcol->item, filled_alpha);
immBegin(GPU_PRIM_TRI_STRIP, (CM_TABLE * 2 + 2) + 4);
immVertex2f(pos, line_range.xmin, rect->ymin);
immVertex2f(pos, line_range.xmin, line_range.ymin);
@@ -1820,7 +1832,7 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
/* Curve line. */
GPU_line_width(1.0f);
immUniformColor3ubvAlpha(wcol->item, 255);
immUniformColor3ubvAlpha(wcol->item, alpha);
GPU_line_smooth(true);
immBegin(GPU_PRIM_LINE_STRIP, (CM_TABLE + 1) + 2);
immVertex2f(pos, line_range.xmin, line_range.ymin);
@@ -1851,6 +1863,10 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol,
float color_vert[4], color_vert_select[4];
UI_GetThemeColor4fv(TH_TEXT_HI, color_vert);
UI_GetThemeColor4fv(TH_TEXT, color_vert_select);
if (inactive) {
color_vert[3] *= float_alpha;
color_vert_select[3] *= float_alpha;
}
if (len_squared_v3v3(color_vert, color_vert_select) < 0.1f) {
interp_v3_v3v3(color_vert, color_vert_select, color_backdrop, 0.75f);
}

View File

@@ -580,6 +580,9 @@ static void curvemap_buttons_layout(uiLayout *layout,
1.0f,
"");
curve_but->gradient_type = bg;
if (!layout->active()) {
UI_but_flag_enable(curve_but, UI_BUT_INACTIVE);
}
/* Sliders for selected curve point. */
int i;

View File

@@ -64,3 +64,10 @@ typedef enum eUnifiedPaintSettingsFlags {
UNIFIED_PAINT_INPUT_SAMPLES = (1 << 7),
UNIFIED_PAINT_COLOR_JITTER = (1 << 8),
} eUnifiedPaintSettingsFlags;
/** Paint::curve_visibility_flag*/
typedef enum PaintCurveVisibilityFlags {
PAINT_CURVE_SHOW_STRENGTH = (1 << 0),
PAINT_CURVE_SHOW_SIZE = (1 << 1),
PAINT_CURVE_SHOW_JITTER = (1 << 2),
} PaintCurveVisibilityFlags;

View File

@@ -1189,6 +1189,12 @@ typedef struct Paint {
/** Flags used for symmetry. */
int symmetry_flags;
/**
* Collapsed state of a given pressure curve
* See #PaintCurveVisibilityFlags
*/
int curve_visibility_flags;
char _pad[4];
float tile_offset[3];
struct UnifiedPaintSettings unified_paint_settings;

View File

@@ -757,6 +757,22 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Tile Z", "Tile along Z axis");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
prop = RNA_def_property(srna, "show_strength_curve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, nullptr, "curve_visibility_flags", PAINT_CURVE_SHOW_STRENGTH);
RNA_def_property_ui_text(prop, "Show Strength Curve", "Show strength curve");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
prop = RNA_def_property(srna, "show_size_curve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "curve_visibility_flags", PAINT_CURVE_SHOW_SIZE);
RNA_def_property_ui_text(prop, "Show Size Curve", "Show size curve");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
prop = RNA_def_property(srna, "show_jitter_curve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "curve_visibility_flags", PAINT_CURVE_SHOW_JITTER);
RNA_def_property_ui_text(prop, "Show Jitter Curve", "Show jitter curve");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, nullptr);
/* Unified Paint Settings */
prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);