[LyX/master] Let branch color accept alpha values

Koji Yokota <[email protected]> Sun, 07 Jun 2026 02:24:21 +0000
Newsgroups gmane.editors.lyx.cvs
Message-ID <[email protected]>
commit ff4a7c4c53b4104c827fe7e6999d61699b3a341f
Author: Koji Yokota <[email protected]>
Date:   Fri Jun 5 21:07:34 2026 +0900

    Let branch color accept alpha values
---
 src/BranchList.cpp                  | 15 +++++++++------
 src/BranchList.h                    |  2 +-
 src/Color.cpp                       | 11 +++++++++++
 src/Color.h                         |  2 ++
 src/frontends/Application.h         |  2 ++
 src/frontends/qt/ColorCache.cpp     |  6 ++++++
 src/frontends/qt/ColorCache.h       |  2 ++
 src/frontends/qt/GuiApplication.cpp | 17 +++++++++++++++++
 src/frontends/qt/GuiApplication.h   |  1 +
 src/frontends/qt/GuiBranches.cpp    | 29 +++++++++++++++++------------
 src/frontends/qt/GuiBranches.h      |  2 ++
 src/frontends/qt/GuiDocument.cpp    | 10 +++++-----
 12 files changed, 75 insertions(+), 24 deletions(-)

diff --git a/src/BranchList.cpp b/src/BranchList.cpp
index 557a36175e..66b5bbc3bb 100644
--- a/src/BranchList.cpp
+++ b/src/BranchList.cpp
@@ -104,11 +104,11 @@ void Branch::setColor(string const & col)
 void Branch::setColors(string const & lmcol, string const & dmcol)
 {
 	if (lmcol.empty() && lmcolor_ == "background" && support::prefixIs(dmcol, "#"))
-		lmcolor_ = X11hexname(inverseRGBColor(rgbFromHexName(dmcol)));
+		lmcolor_ = X11hexname(inverseARGBColor(argbFromHexName(dmcol)));
 	else if (!lmcol.empty())
 		lmcolor_ = lmcol;
 	if (dmcol.empty() && dmcolor_ == "background" && support::prefixIs(lmcol, "#"))
-		dmcolor_ = X11hexname(inverseRGBColor(rgbFromHexName(lmcol)));
+		dmcolor_ = X11hexname(inverseARGBColor(argbFromHexName(lmcol)));
 	else if (!dmcol.empty())
 		dmcolor_ = dmcol;
 
@@ -118,13 +118,16 @@ void Branch::setColors(string const & lmcol, string const & dmcol)
 	if (lmcolor == "none")
 		lmcolor = "background";
 	// if we have background color, keep semantic value, as system colors might vary
-	else if (lmcolor != "background" && (lmcolor.size() != 7 || lmcolor[0] != '#'))
-		lmcolor = lcolor.getX11HexName(lcolor.getFromLyXName(lmcolor));
+	else if (lmcolor != "background" &&
+	         ((lmcolor.size() != 7 && lmcolor.size() != 9) || lmcolor[0] != '#'))
+		lmcolor = lcolor.get32bitHexName(lcolor.getFromLyXName(lmcolor));
 	if (dmcolor == "none")
 		dmcolor = "background";
 	// if we have background color, keep semantic value, as system colors might vary
-	else if (dmcolor != "background" && (dmcolor.size() != 7 || dmcolor[0] != '#'))
-		dmcolor = lcolor.getX11HexName(lcolor.getFromLyXName(dmcolor), true);
+	else if (dmcolor != "background" &&
+	         ((dmcolor.size() != 7 && dmcolor.size() != 9) || dmcolor[0] != '#')) {
+		dmcolor = lcolor.get32bitHexName(lcolor.getFromLyXName(dmcolor), true);
+	}
 
 	// FIXME UNICODE
 	lcolor.setColor("branch" + convert<string>(branch_list_id_)
diff --git a/src/BranchList.h b/src/BranchList.h
index 0678563cb7..7d6d3874e6 100644
--- a/src/BranchList.h
+++ b/src/BranchList.h
@@ -67,7 +67,7 @@ public:
 	///
 	std::string const & darkModeColor() const;
 	/**
-	 * Set background color from a hexcolor string "#rrggbb" or a lyx color name.
+	 * Set background color from a hexcolor string "#aarrggbb" or a lyx color name.
 	 * Use Color:background if the string is no valid color.
 	 * This ensures compatibility with LyX 1.4.0 that had the symbolic
 	 * color "none" that was displayed as Color:background.
diff --git a/src/Color.cpp b/src/Color.cpp
index a032fa8f20..df20600729 100644
--- a/src/Color.cpp
+++ b/src/Color.cpp
@@ -207,6 +207,17 @@ RGBColor const inverseRGBColor(RGBColor color)
 }
 
 
+ARGBColor const inverseARGBColor(ARGBColor color)
+{
+	// color.a is unchanged
+	color.r = 255 - color.r;
+	color.g = 255 - color.g;
+	color.b = 255 - color.b;
+
+	return color;
+}
+
+
 Color::Color(ColorCode base_color) : baseColor(base_color),
 	mergeColor(Color_ignore)
 {}
diff --git a/src/Color.h b/src/Color.h
index 94df2bff3b..186f16563d 100644
--- a/src/Color.h
+++ b/src/Color.h
@@ -72,6 +72,8 @@ std::string const outputLaTeXColor(RGBColor const & color);
 RGBColor const RGBColorFromLaTeX(std::string const & color);
 /// Inverted color
 RGBColor const inverseRGBColor(RGBColor color);
+/// Inverted color: alpha value is unchanged
+ARGBColor const inverseARGBColor(ARGBColor color);
 
 } // namespace lyx
 
diff --git a/src/frontends/Application.h b/src/frontends/Application.h
index 615cca5150..58daba8c81 100644
--- a/src/frontends/Application.h
+++ b/src/frontends/Application.h
@@ -201,6 +201,8 @@ public:
 	* It returns false on failure and sets r, g, b to 0.
 	*/
 	virtual bool getRgbColor(ColorCode col, RGBColor & rgbcol) = 0;
+	/// ARGB version
+	virtual bool getArgbColor(ColorCode col, ARGBColor & argbcol) = 0;
 	/// Like getRgbColor(), but static and slower
 	static bool getRgbColorUncached(ColorCode col, RGBColor & rgbcol);
 
diff --git a/src/frontends/qt/ColorCache.cpp b/src/frontends/qt/ColorCache.cpp
index 4955aaf3ce..357548f27f 100644
--- a/src/frontends/qt/ColorCache.cpp
+++ b/src/frontends/qt/ColorCache.cpp
@@ -218,4 +218,10 @@ QColor const rgb2qcolor(RGBColor const & rgb)
 }
 
 
+QColor const argb2qcolor(ARGBColor const & argb)
+{
+	return QColor(argb.r, argb.g, argb.b, argb.a);
+}
+
+
 } // namespace lyx
diff --git a/src/frontends/qt/ColorCache.h b/src/frontends/qt/ColorCache.h
index 17e70a737d..b0d140e147 100644
--- a/src/frontends/qt/ColorCache.h
+++ b/src/frontends/qt/ColorCache.h
@@ -76,6 +76,8 @@ private:
 
 ///
 QColor const rgb2qcolor(RGBColor const &);
+///
+QColor const argb2qcolor(ARGBColor const &);
 
 } // namespace lyx
 
diff --git a/src/frontends/qt/GuiApplication.cpp b/src/frontends/qt/GuiApplication.cpp
index f3070c525d..535404ccc0 100644
--- a/src/frontends/qt/GuiApplication.cpp
+++ b/src/frontends/qt/GuiApplication.cpp
@@ -3112,6 +3112,23 @@ bool GuiApplication::getRgbColor(ColorCode col, RGBColor & rgbcol)
 	return true;
 }
 
+bool GuiApplication::getArgbColor(ColorCode col, ARGBColor &argbcol)
+{
+	QColor const & qcol = d->color_cache_.get(col);
+	if (!qcol.isValid()) {
+		argbcol.a = 0;
+		argbcol.r = 0;
+		argbcol.g = 0;
+		argbcol.b = 0;
+		return false;
+	}
+	argbcol.a = qcol.alpha();
+	argbcol.r = qcol.red();
+	argbcol.g = qcol.green();
+	argbcol.b = qcol.blue();
+	return true;
+}
+
 
 bool Application::getRgbColorUncached(ColorCode col, RGBColor & rgbcol)
 {
diff --git a/src/frontends/qt/GuiApplication.h b/src/frontends/qt/GuiApplication.h
index db84925ca9..3f03ad1458 100644
--- a/src/frontends/qt/GuiApplication.h
+++ b/src/frontends/qt/GuiApplication.h
@@ -74,6 +74,7 @@ public:
 	void exit(int status) override;
 	bool event(QEvent * e) override;
 	bool getRgbColor(ColorCode col, RGBColor & rgbcol) override;
+	bool getArgbColor(ColorCode col, ARGBColor & argbcol) override;
 	bool isInDarkMode() override;
 	bool isLightColor(RGBColor const & rgb) override;
 	std::string const hexName(ColorCode col) override;
diff --git a/src/frontends/qt/GuiBranches.cpp b/src/frontends/qt/GuiBranches.cpp
index c85eb6789f..5d6d88a687 100644
--- a/src/frontends/qt/GuiBranches.cpp
+++ b/src/frontends/qt/GuiBranches.cpp
@@ -76,6 +76,8 @@ GuiBranches::GuiBranches(QWidget * parent)
 
 	newBranchLE->installEventFilter(this);
 	newBranchLE->setValidator(new NoNewLineValidator(newBranchLE));
+
+	colorbg_ = ColorCache::setSwatchBackground(30, 10);
 }
 
 
@@ -134,15 +136,16 @@ void GuiBranches::updateView()
 		newItem->setText(1, it->isSelected() ? qt_("Yes") : qt_("No"));
 
 		std::string bcolor = it->color();
-		RGBColor rgbcol;
-		if (bcolor.size() == 7 && bcolor[0] == '#')
-			rgbcol = lyx::rgbFromHexName(bcolor);
+		ARGBColor argbcol;
+		if ((bcolor.size() == 7 || bcolor.size() == 9) && bcolor[0] == '#')
+			argbcol = lyx::argbFromHexName(bcolor);
 		else
-			guiApp->getRgbColor(lcolor.getFromLyXName(bcolor), rgbcol);
-		QColor const itemcolor = rgb2qcolor(rgbcol);
+			guiApp->getArgbColor(lcolor.getFromLyXName(bcolor), argbcol);
+		QColor const itemcolor = argb2qcolor(argbcol);
 		if (itemcolor.isValid()) {
 			QPixmap coloritem(30, 10);
 			coloritem.fill(itemcolor);
+			coloritem = ColorCache::mergePixmaps(&coloritem, &colorbg_);
 			newItem->setIcon(2, QIcon(coloritem));
 		}
 		newItem->setText(3, it->hasFileNameSuffix() ? qt_("Yes") : qt_("No"));
@@ -371,19 +374,21 @@ void GuiBranches::toggleColor(QTreeWidgetItem * item)
 	if (!branch)
 		return;
 
+	// bcolor can be 16bit- or 32bit-hex for backward compatibility
 	std::string bcolor = branch->color();
-	RGBColor rgbcol;
-	if (bcolor.size() == 7 && bcolor[0] == '#')
-		rgbcol = lyx::rgbFromHexName(bcolor);
+	ARGBColor argbcol;
+	if ((bcolor.size() == 9 || bcolor.size() == 7) && bcolor[0] == '#')
+		argbcol = lyx::argbFromHexName(bcolor);
 	else
-		guiApp->getRgbColor(lcolor.getFromLyXName(bcolor), rgbcol);
-	QColor const initial = rgb2qcolor(rgbcol);
-	QColor ncol = GuiDialog::getColor(initial, this);
+		guiApp->getArgbColor(lcolor.getFromLyXName(bcolor), argbcol);
+	QColor const initial = argb2qcolor(argbcol);
+	QColor ncol = GuiDialog::getColor(initial, this, QString(),
+	                                  QColorDialog::ShowAlphaChannel);
 	if (!ncol.isValid())
 		return;
 
 	// add the color to the branchlist
-	branch->setColor(fromqstr(ncol.name()));
+	branch->setColor(fromqstr(ncol.name(QColor::HexArgb)));
 	newBranchLE->clear();
 	updateView();
 }
diff --git a/src/frontends/qt/GuiBranches.h b/src/frontends/qt/GuiBranches.h
index 64cf83f889..684161d3b1 100644
--- a/src/frontends/qt/GuiBranches.h
+++ b/src/frontends/qt/GuiBranches.h
@@ -87,6 +87,8 @@ private:
 	ButtonController undef_bc_;
 	///
 	QStringList unknown_branches_;
+	///
+	QPixmap colorbg_;
 };
 
 } // namespace frontend
diff --git a/src/frontends/qt/GuiDocument.cpp b/src/frontends/qt/GuiDocument.cpp
index ea19171bf3..65e5239b1f 100644
--- a/src/frontends/qt/GuiDocument.cpp
+++ b/src/frontends/qt/GuiDocument.cpp
@@ -5353,12 +5353,12 @@ void GuiDocument::dispatchParams()
 			docstring const & current_branch = it->branch();
 			Branch const * branch = branchlist.find(current_branch);
 			string const bcolor = branch->color();
-			RGBColor rgbcol;
-			if (bcolor.size() == 7 && bcolor[0] == '#')
-				rgbcol = lyx::rgbFromHexName(bcolor);
+			ARGBColor argbcol;
+			if ((bcolor.size() == 7 || bcolor.size() ==9) && bcolor[0] == '#')
+				argbcol = lyx::argbFromHexName(bcolor);
 			else
-				guiApp->getRgbColor(lcolor.getFromLyXName(bcolor), rgbcol);
-			string const x11hexname = X11hexname(rgbcol);
+				guiApp->getArgbColor(lcolor.getFromLyXName(bcolor), argbcol);
+			string const x11hexname = X11hexname(argbcol);
 			// display the new color
 			docstring const str = current_branch + ' ' + from_ascii(x11hexname);
 			dispatch(FuncRequest(LFUN_SET_COLOR, str));
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs