Merge branch 'ribbon-colours'

Fix white pressed-button text becoming illegible in dark ribbon themes.

See #26741.
This commit is contained in:
Vadim Zeitlin
2026-07-30 19:26:19 +02:00
8 changed files with 104 additions and 56 deletions
+70
View File
@@ -0,0 +1,70 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/private/colour.h
// Purpose: Private colour-related helper functions.
// Author: Vadim Zeitlin
// Created: 2026-07-29 (extracted src/aui/tabart.cpp)
// Copyright: (c) 2026 wxWidgets team
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PRIVATE_COLOUR_H_
#define _WX_PRIVATE_COLOUR_H_
#include "wx/colour.h"
#include <cmath>
// Helpers used only in this file itself.
namespace wxPrivate
{
inline float wxGetSRGB(float r)
{
return r <= 0.04045f ? r / 12.92f : std::pow((r + 0.055f) / 1.055f, 2.4f);
}
inline float wxGetRelativeLuminance(const wxColour& c)
{
// See https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
return
0.2126f * wxGetSRGB(c.Red() / 255.0f) +
0.7152f * wxGetSRGB(c.Green() / 255.0f) +
0.0722f * wxGetSRGB(c.Blue() / 255.0f);
}
inline float wxComputeContrast(const wxColour& c1, const wxColour& c2)
{
// See https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
float L1 = wxGetRelativeLuminance(c1);
float L2 = wxGetRelativeLuminance(c2);
return L1 > L2 ? (L1 + 0.05f) / (L2 + 0.05f) : (L2 + 0.05f) / (L1 + 0.05f);
}
} // anonymous namespace
// Return the colour if it has sufficient contrast ratio (4.5 recommended)
// with the background or return either white or black if it doesn't.
// (see https://www.w3.org/TR/WCAG21/#contrast-minimum)
inline wxColour
wxGetContrastingFgColour(const wxColour& fg, const wxColour& bg)
{
using namespace wxPrivate;
// No need to change the colour if it has sufficient contrast.
if ( wxComputeContrast(fg, bg) >= 4.5f )
return fg;
// Otherwise pick the colour that provides better contrast.
return wxComputeContrast(*wxWHITE, bg) > wxComputeContrast(*wxBLACK, bg)
? *wxWHITE
: *wxBLACK;
}
// Version of the above modifying the foregorund colour in place.
inline void
wxEnsureSufficientContrast(wxColour* fg, const wxColour& bg)
{
*fg = wxGetContrastingFgColour(*fg, bg);
}
#endif // _WX_PRIVATE_COLOUR_H_
+4
View File
@@ -644,6 +644,9 @@ protected:
void DrawDropdownArrow(wxDC& dc, int x, int y, const wxColour& colour);
void DrawGalleryBackgroundCommon(wxDC& dc, wxRibbonGallery* wnd,
const wxRect& rect);
// Picks the button bar label colour appropriate for the given
// wxRIBBON_BUTTONBAR_BUTTON_* state flags.
wxColour GetButtonBarLabelColour(long state) const;
virtual void DrawGalleryButton(wxDC& dc, wxRect rect,
wxRibbonGalleryButtonState state, wxBitmapBundle* bundles, wxWindow* wnd);
void DrawButtonBarButtonForeground(
@@ -674,6 +677,7 @@ protected:
wxColour m_button_bar_label_colour;
wxColour m_button_bar_label_disabled_colour;
wxColour m_button_bar_active_label_colour;
wxColour m_tab_label_colour;
wxColour m_tab_active_label_colour;
wxColour m_tab_hover_label_colour;
+1 -23
View File
@@ -48,8 +48,7 @@
#endif
#include "wx/private/aui.h"
#include <math.h>
#include "wx/private/colour.h"
wxColor wxAuiLightContrastColour(const wxColour& c)
{
@@ -63,27 +62,6 @@ wxColor wxAuiLightContrastColour(const wxColour& c)
return c.ChangeLightness(amount);
}
inline float wxAuiGetSRGB(float r) {
return r <= 0.03928f ? r / 12.92f : std::pow((r + 0.055f) / 1.055f, 2.4f);
}
float wxAuiGetRelativeLuminance(const wxColour& c)
{
// based on https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
return
0.2126f * wxAuiGetSRGB(c.Red() / 255.0f) +
0.7152f * wxAuiGetSRGB(c.Green() / 255.0f) +
0.0722f * wxAuiGetSRGB(c.Blue() / 255.0f);
}
float wxAuiGetColourContrast(const wxColour& c1, const wxColour& c2)
{
// based on https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast7.html
float L1 = wxAuiGetRelativeLuminance(c1);
float L2 = wxAuiGetRelativeLuminance(c2);
return L1 > L2 ? (L1 + 0.05f) / (L2 + 0.05f) : (L2 + 0.05f) / (L1 + 0.05f);
}
#ifdef wxHAS_SVG
wxBitmapBundle wxAuiCreateBitmap(const char* svgData, int w, int h,
const wxColour& color)
+3 -19
View File
@@ -36,31 +36,15 @@
#endif
#include "wx/private/aui.h"
#include "wx/private/colour.h"
// -- GUI helper classes and functions --
// these functions live in dockart.cpp -- they'll eventually
// be moved to a new utility cpp file
float wxAuiGetColourContrast(const wxColour& c1, const wxColour& c2);
wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size);
// Check if the given colour has sufficient contrast ratio (4.5 recommended)
// with the background and replace it with either white or black if it doesn't.
// (based on https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast7.html)
static void
wxAuiEnsureSufficientContrast(wxColour* fg, const wxColour& bg)
{
// No need to change the colour if it has sufficient contrast.
if ( wxAuiGetColourContrast(*fg, bg) >= 4.5f )
return;
// Otherwise pick the colour that provides better contrast.
*fg = wxAuiGetColourContrast(*wxWHITE, bg)
> wxAuiGetColourContrast(*wxBLACK, bg) ? *wxWHITE : *wxBLACK;
}
// Create a "disabled" version of the given colour by adjusting its lightness
// in the direction depending on the theme.
static wxColour wxAuiDimColour(wxColour colour, int delta = 30)
@@ -1263,7 +1247,7 @@ int wxAuiGenericTabArt::DrawPageTab(
// draw tab text
wxColor font_color = wxSystemSettings::GetColour(
page.active ? wxSYS_COLOUR_CAPTIONTEXT : wxSYS_COLOUR_INACTIVECAPTIONTEXT);
wxAuiEnsureSufficientContrast(&font_color, back_color);
wxEnsureSufficientContrast(&font_color, back_color);
dc.SetTextForeground(font_color);
dc.DrawText(draw_text,
text_offset,
@@ -1617,7 +1601,7 @@ void wxAuiSimpleTabArt::DrawTab(wxDC& dc,
wxColor back_color = dc.GetBrush().GetColour();
wxColor font_color = wxSystemSettings::GetColour(
page.active ? wxSYS_COLOUR_CAPTIONTEXT : wxSYS_COLOUR_INACTIVECAPTIONTEXT);
wxAuiEnsureSufficientContrast(&font_color, back_color);
wxEnsureSufficientContrast(&font_color, back_color);
dc.SetTextForeground(font_color);
const auto textY = tab_y + (tab_height - texty) / 2 + 1;
+5 -3
View File
@@ -29,6 +29,8 @@
#include "wx/osx/private.h"
#endif
#include "wx/private/colour.h"
wxRibbonAUIArtProvider::wxRibbonAUIArtProvider()
: wxRibbonMSWArtProvider(false)
{
@@ -287,6 +289,8 @@ void wxRibbonAUIArtProvider::SetColourScheme(
m_button_bar_hover_background_brush = LikeSecondary(1.7f);
m_button_bar_active_background_brush = LikeSecondary(1.4f);
m_button_bar_label_colour = m_tab_label_colour;
m_button_bar_active_label_colour = wxGetContrastingFgColour(
m_button_bar_label_colour, m_button_bar_active_background_brush.GetColour());
#ifdef __WXOSX__
m_button_bar_label_disabled_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_INACTIVECAPTIONTEXT);
#else
@@ -1145,9 +1149,7 @@ void wxRibbonAUIArtProvider::DrawButtonBarButton(
}
dc.SetFont(m_button_bar_label_font);
dc.SetTextForeground(state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED
? m_button_bar_label_disabled_colour
: m_button_bar_label_colour);
dc.SetTextForeground(GetButtonBarLabelColour(state));
DrawButtonBarButtonForeground(dc, rect, kind, state, label, bitmap_large,
bitmap_small);
}
-1
View File
@@ -9,7 +9,6 @@
#include "wx/wxprec.h"
#if wxUSE_RIBBON
#include "wx/ribbon/art.h"
+20 -7
View File
@@ -26,6 +26,8 @@
#include "wx/msw/private.h"
#endif
#include "wx/private/colour.h"
static const char* const gallery_up_xpm[] = {
"5 5 2 1",
" c None",
@@ -293,6 +295,12 @@ void wxRibbonMSWArtProvider::SetColourScheme(
m_button_bar_active_background_colour = LikeSecondary(-9.9f, 0.14f, -0.14f);
m_button_bar_active_background_gradient_colour = LikeSecondary(-8.7f, 0.17f, -0.03f);
// The active/pressed background can end up much lighter (or darker)
// than the normal button label colour was chosen for, so pick a label
// colour that stays legible against it specifically.
m_button_bar_active_label_colour = wxGetContrastingFgColour(
m_button_bar_label_colour, m_button_bar_active_background_colour);
m_toolbar_border_pen = LikePrimary(1.4f, -0.21f, -0.16f);
SetColour(wxRIBBON_ART_TOOLBAR_FACE_COLOUR, LikePrimary(1.4f, -0.17f, -0.22f));
m_tool_background_top_colour = LikePrimary(-1.9f, -0.07f, 0.06f);
@@ -366,6 +374,7 @@ void wxRibbonMSWArtProvider::CloneTo(wxRibbonMSWArtProvider* copy) const
copy->m_button_bar_label_colour = m_button_bar_label_colour;
copy->m_button_bar_label_disabled_colour = m_button_bar_label_disabled_colour;
copy->m_button_bar_active_label_colour = m_button_bar_active_label_colour;
copy->m_tab_label_colour = m_tab_label_colour;
copy->m_tab_active_label_colour = m_tab_active_label_colour;
copy->m_tab_hover_label_colour = m_tab_hover_label_colour;
@@ -2305,6 +2314,15 @@ void wxRibbonMSWArtProvider::DrawPartialPageBackground(
dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
}
wxColour wxRibbonMSWArtProvider::GetButtonBarLabelColour(long state) const
{
if(state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED)
return m_button_bar_label_disabled_colour;
if(state & wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK)
return m_button_bar_active_label_colour;
return m_button_bar_label_colour;
}
void wxRibbonMSWArtProvider::DrawButtonBarButton(
wxDC& dc,
wxWindow* WXUNUSED(wnd),
@@ -2425,9 +2443,7 @@ void wxRibbonMSWArtProvider::DrawButtonBarButton(
}
dc.SetFont(m_button_bar_label_font);
dc.SetTextForeground(state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED
? m_button_bar_label_disabled_colour
: m_button_bar_label_colour);
dc.SetTextForeground(GetButtonBarLabelColour(state));
DrawButtonBarButtonForeground(dc, rect, kind, state, label, bitmap_large,
bitmap_small);
}
@@ -2441,10 +2457,7 @@ void wxRibbonMSWArtProvider::DrawButtonBarButtonForeground(
const wxBitmap& bitmap_large,
const wxBitmap& bitmap_small)
{
const wxColour
arrowColour(state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED
? m_button_bar_label_disabled_colour
: m_button_bar_label_colour);
const wxColour arrowColour(GetButtonBarLabelColour(state));
switch(state & wxRIBBON_BUTTONBAR_BUTTON_SIZE_MASK)
{
+1 -3
View File
@@ -782,9 +782,7 @@ void wxRibbonMSWFlatArtProvider::DrawButtonBarButton(
}
dc.SetFont(m_button_bar_label_font);
dc.SetTextForeground(state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED
? m_button_bar_label_disabled_colour
: m_button_bar_label_colour);
dc.SetTextForeground(GetButtonBarLabelColour(state));
DrawButtonBarButtonForeground(dc, rect, kind, state, label, bitmap_large,
bitmap_small);
}