Darken the hover ink on a light button face

QETStyle::hoverColor() lightened the highlight color until it read at
3.5:1 against the Light role. On a dark face that is the way to go; on a
light face lightening only fades the ink, so with a pale platform accent
that QET keeps (macOS's green selection color, black selection text) the
loop ran to white and every hovered line-art icon vanished. The ink now
moves away from the face, darker on a light face, lighter on a dark one,
and falls back to the button text color if twenty steps are not enough.

The hover test gets a row with that accent on each palette, and a new
test sweeps accents across hues and lightness on both palettes and
requires the hover ink to read at 3:1 on the face.

Fixes #962
This commit is contained in:
Jeff Patterson
2026-09-20 11:57:21 -05:00
parent 3245919c19
commit 04463f0954
2 changed files with 60 additions and 4 deletions
+49
View File
@@ -63,6 +63,8 @@ class tst_qeticons : public QObject
void toolbarIconIsReadable();
void hoverChangesTheIcon_data();
void hoverChangesTheIcon();
void hoverInkReadsWithAnyAccent_data();
void hoverInkReadsWithAnyAccent();
void coloredIconKeepsItsColorsOnHover();
void menuIconReadsOnHighlight_data();
void menuIconReadsOnHighlight();
@@ -107,6 +109,17 @@ namespace {
}
const QStringList kSizes = {"16x16", "22x22", "32x32", "48x48", "128x128"};
/// palette with the given selection colors, as QET::Palette::withPlatformAccent leaves them.
QPalette withAccent(QPalette palette, const QColor &highlight, const QColor &highlighted_text)
{
for (QPalette::ColorGroup group : {QPalette::Active, QPalette::Inactive})
{
palette.setColor(group, QPalette::Highlight, highlight);
palette.setColor(group, QPalette::HighlightedText, highlighted_text);
}
return palette;
}
}
void tst_qeticons::initTestCase()
@@ -334,6 +347,12 @@ void tst_qeticons::hoverChangesTheIcon_data()
// nothing in the frame, so the icon is the only hover signal there.
QTest::newRow("light-checked") << "qet" << QET::Palette::fusionLight() << true;
QTest::newRow("dark-checked") << "qet-dark" << QET::Palette::fusionDark() << true;
// A platform accent QET keeps because its selection text reads on
// it: macOS's green selection color comes with black text. Lightening
// it toward 3:1 against a white face can only end at white, which
// made every hovered line-art icon vanish on a light palette.
QTest::newRow("light-pale-accent") << "qet" << withAccent(QET::Palette::fusionLight(), QColor(198, 231, 188), Qt::black) << false;
QTest::newRow("dark-pale-accent") << "qet-dark" << withAccent(QET::Palette::fusionDark(), QColor(198, 231, 188), Qt::black) << false;
}
/**
@@ -502,6 +521,36 @@ void tst_qeticons::configPageIconsComeAtPageSize()
QVERIFY2(small.isEmpty(), qPrintable("page icons short of 128 pixels: " + small.join(", ")));
}
/**
Whatever accent the platform hands QET, the hover ink must read on the
hovered button face of both palettes: a sweep over hues at every
lightness, including the pale and the near-black ones.
*/
void tst_qeticons::hoverInkReadsWithAnyAccent_data()
{
QTest::addColumn<QPalette>("palette");
for (int lightness = 10; lightness <= 250; lightness += 40)
for (int hue = 0; hue < 360; hue += 60)
{
const QColor accent = QColor::fromHsl(hue, 200, lightness);
const QColor text = QET::Palette::contrastRatio(accent, Qt::white) >= 4.5 ? Qt::white : Qt::black;
QTest::newRow(qPrintable(QString("light-%1").arg(accent.name())))
<< withAccent(QET::Palette::fusionLight(), accent, text);
QTest::newRow(qPrintable(QString("dark-%1").arg(accent.name())))
<< withAccent(QET::Palette::fusionDark(), accent, text);
}
}
void tst_qeticons::hoverInkReadsWithAnyAccent()
{
QFETCH(QPalette, palette);
const QColor face = palette.color(QPalette::Active, QPalette::Light);
const QColor ink = QETStyle::hoverColor(palette);
const double contrast = QET::Palette::contrastRatio(ink, face);
QVERIFY2(contrast >= kIconRatio,
qPrintable(QString("hover ink %1 reads %2:1 on the face %3").arg(ink.name()).arg(contrast).arg(face.name())));
}
int main(int argc, char **argv)
{
if (qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM"))