UI: Theme: Add new Outline Selected property

Allow theming the outline of selected elements. This helps to make
active elements more prominent, and allows for flat theme combinations
not possible before.

Pull Request: https://projects.blender.org/blender/blender/pulls/139850
This commit is contained in:
Pablo Vazquez
2025-06-11 23:20:50 +02:00
committed by Harley Acheson
parent 14a42c0928
commit 23fb5752ed
7 changed files with 79 additions and 9 deletions

View File

@@ -27,6 +27,7 @@ const bTheme U_theme_default = {
.tui = {
.wcol_regular = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x545454ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0x1d1d1d80),
@@ -36,6 +37,7 @@ const bTheme U_theme_default = {
},
.wcol_tool = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x545454ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xffffffff),
@@ -45,6 +47,7 @@ const bTheme U_theme_default = {
},
.wcol_toolbar_item = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x282828ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xffffffb3),
@@ -54,6 +57,7 @@ const bTheme U_theme_default = {
},
.wcol_text = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x1d1d1dff),
.inner_sel = RGBA(0x181818ff),
.item = RGBA(0xffffff33),
@@ -63,6 +67,7 @@ const bTheme U_theme_default = {
},
.wcol_radio = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x545454ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0x252525ff),
@@ -72,6 +77,7 @@ const bTheme U_theme_default = {
},
.wcol_option = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x545454ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xffffffff),
@@ -81,6 +87,7 @@ const bTheme U_theme_default = {
},
.wcol_toggle = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x545454ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0x252525ff),
@@ -90,6 +97,7 @@ const bTheme U_theme_default = {
},
.wcol_num = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x545454ff),
.inner_sel = RGBA(0x222222ff),
.item = RGBA(0x4772b3ff),
@@ -99,6 +107,7 @@ const bTheme U_theme_default = {
},
.wcol_numslider = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x545454ff),
.inner_sel = RGBA(0x222222ff),
.item = RGBA(0x4772b3ff),
@@ -108,6 +117,7 @@ const bTheme U_theme_default = {
},
.wcol_tab = {
.outline = RGBA(0x1d1d1dff),
.outline_sel = RGBA(0x1d1d1dff),
.inner = RGBA(0x1d1d1dff),
.inner_sel = RGBA(0x303030ff),
.item = RGBA(0x1d1d1dff),
@@ -117,6 +127,7 @@ const bTheme U_theme_default = {
},
.wcol_menu = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x282828ff),
.inner_sel = RGBA(0x4772b3b3),
.item = RGBA(0xd9d9d9ff),
@@ -126,6 +137,7 @@ const bTheme U_theme_default = {
},
.wcol_pulldown = {
.outline = RGBA(0x3d3d3d00),
.outline_sel = RGBA(0x3d3d3d00),
.inner = RGBA(0x22222200),
.inner_sel = RGBA(0xffffff1a),
.item = RGBA(0xffffff8f),
@@ -135,6 +147,7 @@ const bTheme U_theme_default = {
},
.wcol_menu_back = {
.outline = RGBA(0x242424ff),
.outline_sel = RGBA(0x242424ff),
.inner = RGBA(0x181818ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xd9d9d9ff),
@@ -144,6 +157,7 @@ const bTheme U_theme_default = {
},
.wcol_menu_item = {
.outline = RGBA(0x3d3d3d00),
.outline_sel = RGBA(0x3d3d3d00),
.inner = RGBA(0x18181800),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xffffff8f),
@@ -153,6 +167,7 @@ const bTheme U_theme_default = {
},
.wcol_tooltip = {
.outline = RGBA(0x242424ff),
.outline_sel = RGBA(0x242424ff),
.inner = RGBA(0x1d1d1dff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xd9d9d9ff),
@@ -162,6 +177,7 @@ const bTheme U_theme_default = {
},
.wcol_box = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x1d1d1d80),
.inner_sel = RGBA(0x545454ff),
.item = RGBA(0x191919ff),
@@ -171,6 +187,7 @@ const bTheme U_theme_default = {
},
.wcol_scroll = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x22222200),
.inner_sel = RGBA(0xffffffff),
.item = RGBA(0x545454ff),
@@ -180,6 +197,7 @@ const bTheme U_theme_default = {
},
.wcol_progress = {
.outline = RGBA(0x3d3d3dff),
.outline_sel = RGBA(0x3d3d3dff),
.inner = RGBA(0x222222ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0x4772b3ff),
@@ -189,6 +207,7 @@ const bTheme U_theme_default = {
},
.wcol_list_item = {
.outline = RGBA(0x2d2d2dff),
.outline_sel = RGBA(0x2d2d2dff),
.inner = RGBA(0xffffff00),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0xffffff33),
@@ -198,6 +217,7 @@ const bTheme U_theme_default = {
},
.wcol_pie_menu = {
.outline = RGBA(0x242424ff),
.outline_sel = RGBA(0x242424ff),
.inner = RGBA(0x181818ff),
.inner_sel = RGBA(0x4772b3ff),
.item = RGBA(0x545454ff),

View File

@@ -1061,7 +1061,7 @@ class PreferenceThemeWidgetColorPanel:
layout.use_property_split = True
flow = layout.grid_flow(row_major=False, columns=2, even_columns=True, even_rows=False, align=False)
flow = layout.grid_flow(row_major=True, columns=3, even_columns=True, even_rows=False, align=False)
col = flow.column(align=True)
col.prop(widget_style, "text")
@@ -1071,7 +1071,10 @@ class PreferenceThemeWidgetColorPanel:
col = flow.column(align=True)
col.prop(widget_style, "inner", slider=True)
col.prop(widget_style, "inner_sel", text="Selected", slider=True)
col = flow.column(align=True)
col.prop(widget_style, "outline")
col.prop(widget_style, "outline_sel", text="Selected", slider=True)
col.separator()

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 5
#define BLENDER_FILE_SUBVERSION 6
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -260,6 +260,40 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_spreadsheet.tab_back);
}
if (!USER_VERSION_ATLEAST(500, 6)) {
/* Match the selected/unselected outline colors. */
copy_v4_v4_uchar(btheme->tui.wcol_box.outline_sel, U_theme_default.tui.wcol_box.outline);
copy_v4_v4_uchar(btheme->tui.wcol_list_item.outline_sel,
U_theme_default.tui.wcol_list_item.outline);
copy_v4_v4_uchar(btheme->tui.wcol_menu.outline_sel, U_theme_default.tui.wcol_menu.outline);
copy_v4_v4_uchar(btheme->tui.wcol_menu_back.outline_sel,
U_theme_default.tui.wcol_menu_back.outline);
copy_v4_v4_uchar(btheme->tui.wcol_menu_item.outline_sel,
U_theme_default.tui.wcol_menu_item.outline);
copy_v4_v4_uchar(btheme->tui.wcol_num.outline_sel, U_theme_default.tui.wcol_num.outline);
copy_v4_v4_uchar(btheme->tui.wcol_numslider.outline_sel,
U_theme_default.tui.wcol_numslider.outline);
copy_v4_v4_uchar(btheme->tui.wcol_option.outline_sel, U_theme_default.tui.wcol_option.outline);
copy_v4_v4_uchar(btheme->tui.wcol_pie_menu.outline_sel,
U_theme_default.tui.wcol_pie_menu.outline);
copy_v4_v4_uchar(btheme->tui.wcol_progress.outline_sel,
U_theme_default.tui.wcol_progress.outline);
copy_v4_v4_uchar(btheme->tui.wcol_pulldown.outline_sel,
U_theme_default.tui.wcol_pulldown.outline);
copy_v4_v4_uchar(btheme->tui.wcol_radio.outline_sel, U_theme_default.tui.wcol_radio.outline);
copy_v4_v4_uchar(btheme->tui.wcol_regular.outline_sel,
U_theme_default.tui.wcol_regular.outline);
copy_v4_v4_uchar(btheme->tui.wcol_scroll.outline_sel, U_theme_default.tui.wcol_scroll.outline);
copy_v4_v4_uchar(btheme->tui.wcol_tab.outline_sel, U_theme_default.tui.wcol_tab.outline);
copy_v4_v4_uchar(btheme->tui.wcol_text.outline_sel, U_theme_default.tui.wcol_text.outline);
copy_v4_v4_uchar(btheme->tui.wcol_toggle.outline_sel, U_theme_default.tui.wcol_toggle.outline);
copy_v4_v4_uchar(btheme->tui.wcol_tool.outline_sel, U_theme_default.tui.wcol_tool.outline);
copy_v4_v4_uchar(btheme->tui.wcol_toolbar_item.outline_sel,
U_theme_default.tui.wcol_toolbar_item.outline);
copy_v4_v4_uchar(btheme->tui.wcol_tooltip.outline_sel,
U_theme_default.tui.wcol_tooltip.outline);
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a USER_VERSION_ATLEAST check.

View File

@@ -2553,6 +2553,7 @@ static void ui_widget_color_disabled(uiWidgetType *wt, const uiWidgetStateInfo *
const float factor = widget_alpha_factor(state);
wcol_theme_s.outline[3] *= factor;
wcol_theme_s.outline_sel[3] *= factor;
wcol_theme_s.inner[3] *= factor;
wcol_theme_s.inner_sel[3] *= factor;
wcol_theme_s.item[3] *= factor;
@@ -2566,7 +2567,8 @@ static void widget_active_color(uiWidgetColors *wcol)
{
const bool dark = (srgb_to_grayscale_byte(wcol->text) > srgb_to_grayscale_byte(wcol->inner));
color_mul_hsl_v3(wcol->inner, 1.0f, 1.15f, dark ? 1.2f : 1.1f);
color_mul_hsl_v3(wcol->outline, 1.0f, 1.15f, 1.15f);
color_blend_v4_v4v4(wcol->outline, wcol->outline, wcol->outline_sel, 0.5f);
color_mul_hsl_v3(wcol->outline_sel, 1.0f, 1.15f, 1.15f);
color_mul_hsl_v3(wcol->text, 1.0f, 1.15f, dark ? 1.25f : 0.8f);
}
@@ -2621,6 +2623,7 @@ static void widget_state(uiWidgetType *wt,
if (state->but_flag & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.outline, wt->wcol.outline_sel);
if (color_blend != nullptr) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
@@ -2632,6 +2635,7 @@ static void widget_state(uiWidgetType *wt,
else {
if (state->but_flag & UI_BUT_ACTIVE_DEFAULT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.outline, wt->wcol.outline_sel);
copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
}
if (color_blend != nullptr) {
@@ -2662,6 +2666,7 @@ static void widget_state(uiWidgetType *wt,
if (state->but_flag & UI_BUT_DRAG_MULTI) {
/* the button isn't SELECT but we're editing this so draw with sel color */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.outline, wt->wcol.outline_sel);
std::swap(wt->wcol.shadetop, wt->wcol.shadedown);
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
}
@@ -2794,6 +2799,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
if ((state->but_flag & UI_BUT_DISABLED) && (state->but_flag & UI_HOVER)) {
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
color_blend_v3_v3(wt->wcol.outline, wt->wcol.outline_sel, 0.5f);
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
@@ -2803,6 +2809,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
/* regular active */
if (state->but_flag & (UI_SELECT | UI_HOVER)) {
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
copy_v3_v3_uchar(wt->wcol.outline, wt->wcol.outline_sel);
}
else if (state->but_flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
@@ -2811,9 +2818,11 @@ static void widget_state_pie_menu_item(uiWidgetType *wt,
if (state->but_flag & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.outline, wt->wcol.outline_sel);
}
else if (state->but_flag & UI_HOVER) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
color_blend_v3_v3(wt->wcol.outline, wt->wcol.outline_sel, 0.5f);
}
}
}
@@ -2847,6 +2856,7 @@ static void widget_state_menu_item(uiWidgetType *wt,
else if (state->but_flag & (UI_BUT_ACTIVE_DEFAULT | UI_SELECT_DRAW)) {
/* Currently-selected item. */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.outline, wt->wcol.outline_sel);
copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
}
else if ((state->but_flag & (UI_SELECT | UI_BUT_ICON_PREVIEW)) ==
@@ -2854,11 +2864,13 @@ static void widget_state_menu_item(uiWidgetType *wt,
{
/* Currently-selected list or menu item that is large icon preview. */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.outline, wt->wcol.outline_sel);
copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
}
else if (state->but_flag & UI_HOVER) {
/* Regular hover. */
color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.2f);
color_blend_v3_v3(wt->wcol.outline, wt->wcol.outline_sel, 0.5f);
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
wt->wcol.inner[3] = 255;
wt->wcol.text[3] = 255;
@@ -4286,9 +4298,6 @@ static void widget_menu_itembut(uiWidgetColors *wcol,
rect->xmin += padding;
rect->xmax -= padding;
/* No outline. */
wtb.draw_outline = false;
const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
@@ -4366,8 +4375,6 @@ static void widget_list_itembut(uiBut *but,
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
const float rad = widget_radius_from_zoom(zoom, wcol);
round_box_edges(&wtb, UI_CNR_ALL, &draw_rect, rad);

View File

@@ -108,13 +108,14 @@ typedef struct uiStyle {
typedef struct uiWidgetColors {
unsigned char outline[4];
unsigned char outline_sel[4];
unsigned char inner[4];
unsigned char inner_sel[4];
unsigned char item[4];
unsigned char text[4];
unsigned char text_sel[4];
unsigned char shaded;
char _pad0[7];
char _pad0[3];
short shadetop, shadedown;
float roundness;
} uiWidgetColors;

View File

@@ -1606,6 +1606,11 @@ static void rna_def_userdef_theme_ui_wcol(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Outline", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "outline_sel", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Outline Selected", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "inner", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Inner", "");