[LyX/master] Unbreak foreground/background color adaptation with transparent backgrounds
Juergen Spitzmueller
spitz at lyx.org
Sun Jul 5 11:19:11 UTC 2026
commit efec7bd2e2b56c24a089c4c4d3188635ae33fdf5
Author: Juergen Spitzmueller <spitz at lyx.org>
Date: Sun Jul 5 13:18:09 2026 +0200
Unbreak foreground/background color adaptation with transparent backgrounds
---
src/RowPainter.cpp | 9 ++++++---
src/frontends/Application.h | 5 +++--
src/frontends/qt/ColorCache.cpp | 27 +++++++++++++++++++++++----
src/frontends/qt/ColorCache.h | 5 ++++-
src/frontends/qt/GuiApplication.cpp | 4 ++--
src/frontends/qt/GuiApplication.h | 2 +-
src/frontends/qt/GuiWorkArea.cpp | 12 +++++++-----
src/insets/Inset.cpp | 21 ++++++++++++++-------
8 files changed, 60 insertions(+), 25 deletions(-)
diff --git a/src/RowPainter.cpp b/src/RowPainter.cpp
index 0d01ac1bcc..fae564ce3b 100644
--- a/src/RowPainter.cpp
+++ b/src/RowPainter.cpp
@@ -258,12 +258,15 @@ void RowPainter::paintStringAndSel(Row::Element const & e) const
bool invert = false;
if (theApp() && theApp()->isInDarkMode()) {
+ ColorCode cc = pi_.backgroundColor(&pi_.base.bv->buffer().inset());
if (e.font.fontInfo().color() == Color_none
- && theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(pi_.background_color, true))))
+ && theApp()->isLightColor(argbFromHexName(lcolor.get32bitHexName(cc, true)),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
invert = true;
- else if (pi_.background_color == Color_background
+ else if (cc == Color_background
&& lcolor.isStaticColor(e.font.fontInfo().color())
- && !theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(e.font.fontInfo().color()))))
+ && !theApp()->isLightColor(argbFromHexName(lcolor.get32bitHexName(e.font.fontInfo().color())),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
invert = true;
}
diff --git a/src/frontends/Application.h b/src/frontends/Application.h
index 3fa4fa4482..931de7849a 100644
--- a/src/frontends/Application.h
+++ b/src/frontends/Application.h
@@ -220,9 +220,10 @@ public:
/**
* @return true this is a relatively light color
- * depending on relative luminance
+ * depending on relative luminance.
+ * Transparent colors are overlayed with the background.
*/
- virtual bool isLightColor(RGBColor const & rgb) = 0;
+ virtual bool isLightColor(ARGBColor const & fg, ARGBColor const & bg) = 0;
/** Eg, passing Color_black returns "000000",
* passing Color_white returns "ffffff".
diff --git a/src/frontends/qt/ColorCache.cpp b/src/frontends/qt/ColorCache.cpp
index 5cd1207e48..fadaa153c6 100644
--- a/src/frontends/qt/ColorCache.cpp
+++ b/src/frontends/qt/ColorCache.cpp
@@ -169,20 +169,23 @@ bool ColorCache::isDarkMode() const
}
-bool ColorCache::isLightColor(RGBColor const & rgb)
+bool ColorCache::isLightColor(ARGBColor const & fg, ARGBColor const & bg)
{
+ // Overlay on background (necessary with transparency)
+ ARGBColor const & argb = colorOverlay(fg, bg);
+
// RGB to sRGB
- double r = rgb.r / 255.0;
+ double r = argb.r / 255.0;
if (r <= 0.04045)
r = r / 12.92;
else
r = pow((r + 0.055) / 1.055, 2.4);
- double g = rgb.g / 255.0;
+ double g = argb.g / 255.0;
if (g <= 0.04045)
g = g / 12.92;
else
g = pow((g + 0.055) / 1.055, 2.4);
- double b = rgb.b / 255.0;
+ double b = argb.b / 255.0;
if (b <= 0.04045)
b = b / 12.92;
else
@@ -224,6 +227,22 @@ QPixmap ColorCache::mergePixmaps(QPixmap const *fg, QPixmap const *bg)
}
+ARGBColor ColorCache::colorOverlay(ARGBColor const & fg, ARGBColor const & bg)
+{
+ int red, green, blue, alpha;
+
+ auto fg_weight = fg.a;
+ auto bg_weight = 1 - fg.a;
+
+ red = std::round((fg_weight * fg.r + bg_weight * bg.r) * 255);
+ green = std::round((fg_weight * fg.g + bg_weight * bg.g) * 255);
+ blue = std::round((fg_weight*fg.b + bg_weight * bg.b) * 255);
+ alpha = std::round((1 - (1 - fg.a) * (1 - bg.a) * 255));
+
+ return ARGBColor(red, green, blue, alpha);
+}
+
+
QColor const rgb2qcolor(RGBColor const & rgb)
{
return QColor(rgb.r, rgb.g, rgb.b);
diff --git a/src/frontends/qt/ColorCache.h b/src/frontends/qt/ColorCache.h
index 617bae8e56..81644f03c0 100644
--- a/src/frontends/qt/ColorCache.h
+++ b/src/frontends/qt/ColorCache.h
@@ -52,7 +52,7 @@ public:
* a dark one as contrast) depending on relative luminance
* (cf. https://www.w3.org/TR/WCAG20/#relativeluminancedef)
*/
- bool isLightColor(RGBColor const & rgb);
+ bool isLightColor(ARGBColor const & fg, ARGBColor const & bg);
/// change the undelying palette
void setPalette(QPalette const pal) { pal_ = pal; clear(); }
@@ -72,6 +72,9 @@ private:
bool initialized_;
///
QPalette pal_;
+ /// Overlay fg color on bg color
+ /// This is necessary with transparency in fg color
+ ARGBColor colorOverlay(ARGBColor const & fg, ARGBColor const & bg);
};
///
diff --git a/src/frontends/qt/GuiApplication.cpp b/src/frontends/qt/GuiApplication.cpp
index 532388a888..e48087bba6 100644
--- a/src/frontends/qt/GuiApplication.cpp
+++ b/src/frontends/qt/GuiApplication.cpp
@@ -3084,9 +3084,9 @@ bool GuiApplication::isInDarkMode()
}
-bool GuiApplication::isLightColor(RGBColor const & rgb)
+bool GuiApplication::isLightColor(ARGBColor const & fg, ARGBColor const & bg)
{
- return colorCache().isLightColor(rgb);
+ return colorCache().isLightColor(fg, bg);
}
diff --git a/src/frontends/qt/GuiApplication.h b/src/frontends/qt/GuiApplication.h
index 3f03ad1458..eff522eb3c 100644
--- a/src/frontends/qt/GuiApplication.h
+++ b/src/frontends/qt/GuiApplication.h
@@ -76,7 +76,7 @@ public:
bool getRgbColor(ColorCode col, RGBColor & rgbcol) override;
bool getArgbColor(ColorCode col, ARGBColor & argbcol) override;
bool isInDarkMode() override;
- bool isLightColor(RGBColor const & rgb) override;
+ bool isLightColor(ARGBColor const & fg, ARGBColor const & bg) override;
std::string const hexName(ColorCode col) override;
void registerSocketCallback(int fd, SocketCallback func) override;
void unregisterSocketCallback(int fd) override;
diff --git a/src/frontends/qt/GuiWorkArea.cpp b/src/frontends/qt/GuiWorkArea.cpp
index 3fb3f26e79..b4b4b7e401 100644
--- a/src/frontends/qt/GuiWorkArea.cpp
+++ b/src/frontends/qt/GuiWorkArea.cpp
@@ -581,12 +581,14 @@ void GuiWorkArea::Private::drawCaret(QPainter & painter, int horiz_offset) const
&& buffer_view_->getCaretBackground() != "none"
&& ((guiApp->colorCache().isDarkMode()
&& guiApp->colorCache().isLightColor(
- rgbFromHexName(lcolor.getX11HexName(
- buffer_view_->getCaretBackground(), true))))
+ argbFromHexName(lcolor.get32bitHexName(
+ buffer_view_->getCaretBackground(), true)),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
|| (!guiApp->colorCache().isDarkMode()
- && !guiApp->colorCache().isLightColor(rgbFromHexName(
- lcolor.getX11HexName(
- buffer_view_->getCaretBackground()))))))
+ && !guiApp->colorCache().isLightColor(argbFromHexName(
+ lcolor.get32bitHexName(
+ buffer_view_->getCaretBackground())),
+ argbFromHexName(lcolor.get32bitHexName("background"))))))
? guiApp->colorCache().get(Color_cursor_inverted)
: guiApp->colorCache().get(Color_cursor);
painter.setPen(color);
diff --git a/src/insets/Inset.cpp b/src/insets/Inset.cpp
index 14f93c9d2b..0924136107 100644
--- a/src/insets/Inset.cpp
+++ b/src/insets/Inset.cpp
@@ -308,12 +308,15 @@ Color Inset::getModeDependentColor(PainterInfo & pi) const
FontInfo font = pi.base.font;
bool invert = false;
if (theApp() && theApp()->isInDarkMode()) {
+ ColorCode cc = pi.backgroundColor(this);
if (font.color() == Color_none
- && theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(pi.background_color, true))))
+ && theApp()->isLightColor(argbFromHexName(lcolor.get32bitHexName(cc, true)),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
invert = true;
- else if (pi.background_color == Color_background
+ else if (cc == Color_background
&& font.color() != Color_none
- && !theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(font.color()))))
+ && !theApp()->isLightColor(argbFromHexName(lcolor.get32bitHexName(font.color())),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
invert = true;
}
Color rc = font.realColor(invert);
@@ -331,16 +334,20 @@ Color Inset::getModeDependentColor(ColorCode const fgc, ColorCode const bgc) con
bool darken = false;
if (theApp() && theApp()->isInDarkMode()) {
if (fgc == Color_none
- && theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(bgc, true))))
+ && theApp()->isLightColor(argbFromHexName(lcolor.getX11HexName(bgc, true)),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
invert = true;
else if (bgc == Color_background
&& fgc != Color_none
- && !theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(fgc, true))))
+ && !theApp()->isLightColor(argbFromHexName(lcolor.getX11HexName(fgc, true)),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
invert = true;
else if (bgc != Color_background
&& fgc != Color_none
- && theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(fgc, true)))
- && theApp()->isLightColor(rgbFromHexName(lcolor.getX11HexName(bgc, true))))
+ && theApp()->isLightColor(argbFromHexName(lcolor.getX11HexName(fgc, true)),
+ argbFromHexName(lcolor.get32bitHexName(bgc, true)))
+ && theApp()->isLightColor(argbFromHexName(lcolor.getX11HexName(bgc, true)),
+ argbFromHexName(lcolor.get32bitHexName("background", true))))
darken = true;
}
Color res = fgc;
More information about the lyx-cvs
mailing list