[LyX/master] Make system IM focus color shown when IM focus color is set transparent

Koji Yokota <[email protected]> Thu, 11 Jun 2026 10:04:19 +0000
Newsgroups gmane.editors.lyx.cvs
Message-ID <[email protected]>
commit ac81d8173fde58254c7ed1ce02bcb2d7bbee6927
Author: Koji Yokota <[email protected]>
Date:   Thu Jun 11 18:59:14 2026 +0900

    Make system IM focus color shown when IM focus color is set transparent
    
    and other small fixes
---
 src/frontends/qt/ColorCache.cpp     | 19 ++++++++-
 src/frontends/qt/ColorCache.h       |  2 +
 src/frontends/qt/GuiInputMethod.cpp | 80 +++++++++++++++++++++----------------
 3 files changed, 64 insertions(+), 37 deletions(-)

diff --git a/src/frontends/qt/ColorCache.cpp b/src/frontends/qt/ColorCache.cpp
index a666c529bd..0949c2f3da 100644
--- a/src/frontends/qt/ColorCache.cpp
+++ b/src/frontends/qt/ColorCache.cpp
@@ -35,6 +35,7 @@ QPalette::ColorRole role(ColorCode col)
 	case Color_mathmacrobg:
 	case Color_mathcorners:
 	case Color_preeditbg:
+	case Color_preeditfocus:
 		return QPalette::Base;
 		break;
 
@@ -44,16 +45,15 @@ QPalette::ColorRole role(ColorCode col)
 	case Color_tabularline:
 	case Color_previewframe:
 	case Color_preedittext:
+	case lyx::Color_preeditfocustext:
 		return QPalette::Text;
 		break;
 
 	case Color_selection:
-	case Color_preeditfocus:
 		return QPalette::Highlight;
 		break;
 	case Color_selectionmath:
 	case Color_selectiontext:
-	case lyx::Color_preeditfocustext:
 		return QPalette::HighlightedText;
 		break;
 	case Color_urllabel:
@@ -233,5 +233,20 @@ QColor const argb2qcolor(ARGBColor const & argb)
 	return QColor(argb.r, argb.g, argb.b, argb.a);
 }
 
+const QColor qcolorOverlay(const QColor &fg, const QColor &bg)
+{
+	int red, green, blue, alpha;
+
+	float fg_weight = fg.alphaF();
+	float bg_weight = (1 - fg.alphaF()) * bg.alphaF();
+
+	red   = std::round((fg_weight*fg.redF()   + bg_weight*bg.redF()  ) * 255);
+	green = std::round((fg_weight*fg.greenF() + bg_weight*bg.greenF()) * 255);
+	blue  = std::round((fg_weight*fg.blueF()  + bg_weight*bg.blueF() ) * 255);
+	alpha = std::round((1 - (1 - fg.alphaF()) * (1 - bg.alphaF())) * 255);
+
+	return QColor(red, green, blue, alpha);
+}
+
 
 } // namespace lyx
diff --git a/src/frontends/qt/ColorCache.h b/src/frontends/qt/ColorCache.h
index b0d140e147..617bae8e56 100644
--- a/src/frontends/qt/ColorCache.h
+++ b/src/frontends/qt/ColorCache.h
@@ -78,6 +78,8 @@ private:
 QColor const rgb2qcolor(RGBColor const &);
 ///
 QColor const argb2qcolor(ARGBColor const &);
+///
+QColor const qcolorOverlay(QColor const & fg, QColor const & bg);
 
 } // namespace lyx
 
diff --git a/src/frontends/qt/GuiInputMethod.cpp b/src/frontends/qt/GuiInputMethod.cpp
index 43059024ac..e36fa31475 100644
--- a/src/frontends/qt/GuiInputMethod.cpp
+++ b/src/frontends/qt/GuiInputMethod.cpp
@@ -205,7 +205,7 @@ void GuiInputMethod::inputMethodEvent(QInputMethodEvent* ev)
 	d->font_color_ = d->color_cache_.get(fg);
 	d->font_brush_.setColor(d->font_color_);
 	LYXERR(Debug::KEY,
-	       "Preedit font color is set to " << d->font_color_.name());
+	       "Preedit font color is set to " << d->font_color_.name(QColor::HexArgb));
 
 	d->locale_ = d->sys_im_->locale();
 	d->style_.lang_ = d->locale_;
@@ -524,11 +524,11 @@ pos_type GuiInputMethod::setTextFormat(const QInputMethodEvent::Attribute & it,
 
 	LYXERR(Debug::KEY,
 	       "QInputMethodEvent::TextFormat start: " << it.start <<
-	       " end: " << it.start + it.length - 1 <<
+	       " length: " << it.length <<
 	       " underline? " << char_format.font().underline() <<
 	       " UnderlineStyle: " << char_format.underlineStyle() <<
-	       " fg: " << char_format.foreground().color().name() <<
-	       " bg: " << char_format.background().color().name());
+	       " fg: " << char_format.foreground().color().name(QColor::HexArgb) <<
+	       " bg: " << char_format.background().color().name(QColor::HexArgb));
 
 	//
 	// Fit and adjust arrived text formats
@@ -541,18 +541,28 @@ pos_type GuiInputMethod::setTextFormat(const QInputMethodEvent::Attribute & it,
 #endif
 
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
-	// set the style of a focused sector as specified by color themes
-	// it uses a system color if "Use system colors" is checked
+	QColor fg, bg;
+	QColor im_fg = char_format.foreground().color();
+	QColor im_bg = char_format.background().color();
+	// if incoming char_format doesn't specify the color (#000000)
+	// just use the text background as a base color
+	if (im_bg == QColorConstants::Black)
+		im_bg = guiApp->colorCache().get(Color_background);
+
+	// overlay theme's color on char_format's base color
+	// theme's color is the system color if "Use system colors" is checked
 	// NOTE: brush size is assumed to be four
 	//       if it is to be changed, change the declaration of array in
 	//       setPreeditStyle()
 	if (it.start == d->caret_rel_pos_) {
-		char_format.setForeground(brush[0]);
-		char_format.setBackground(brush[1]);
+		fg = qcolorOverlay(brush[0].color(), im_fg);
+		bg = qcolorOverlay(brush[1].color(), im_bg);
 	} else {
-		char_format.setForeground(brush[2]);
-		char_format.setBackground(brush[3]);
+		fg = qcolorOverlay(brush[2].color(), im_fg);
+		bg = qcolorOverlay(brush[3].color(), im_bg);
 	}
+	char_format.setForeground(fg);
+	char_format.setBackground(bg);
 #else
 	// avoid unused-parameter warning.
 	(void) brush;
@@ -567,9 +577,9 @@ pos_type GuiInputMethod::setTextFormat(const QInputMethodEvent::Attribute & it,
 			        pickNextSegFromTurnout(next_seg_pos, &char_format);
 			if (updated_pos == next_seg_pos) {
 				// no matching segment in the turnout
-				LYXERR(Debug::KEY, "Pushing to preedit register: (" << it.start
-				       << ", " << it.start + it.length - 1 << ") bg color: "
-				       << char_format.background().color().name());
+				LYXERR(Debug::KEY, "Pushing to preedit register: [" << it.start
+				       << ", " << it.start + it.length << ") bg color: "
+				       << char_format.background().color().name(QColor::HexArgb));
 				next_seg_pos = registerSegment(it.start, (size_type)it.length,
 				                               char_format);
 			} else
@@ -577,19 +587,19 @@ pos_type GuiInputMethod::setTextFormat(const QInputMethodEvent::Attribute & it,
 		} else {
 			// push the constructed char format together with start and length
 			// to the list
-			LYXERR(Debug::KEY, "Pushing to preedit register: (" << it.start
-			       << ", " << it.start + it.length - 1
+			LYXERR(Debug::KEY, "Pushing to preedit register: [" << it.start
+			       << ", " << it.start + it.length
 			       << ") fg: "
-			       << char_format.foreground().color().name()
+			       << char_format.foreground().color().name(QColor::HexArgb)
 			       << " bg: "
-			       << char_format.background().color().name());
+			       << char_format.background().color().name(QColor::HexArgb));
 			next_seg_pos =
 			        registerSegment(it.start, (size_type)it.length, char_format);
 		}
 		next_seg_pos = pickNextSegFromTurnout(next_seg_pos);
 	} else if ((it.start > next_seg_pos || d->initial_tf_entry_) && it.length > 0) {
-		LYXERR(Debug::KEY, "Pushing to preedit turnout:  (" << it.start << ", "
-				<< it.start + it.length - 1 << ")");
+		LYXERR(Debug::KEY, "Pushing to preedit turnout: [" << it.start << ", "
+				<< it.start + it.length << ")");
 		PreeditSegment turnout = {it.start, (size_type)it.length, char_format};
 		d->seg_turnout_.push_back(turnout);
 		d->initial_tf_entry_ = false;
@@ -608,25 +618,25 @@ pos_type GuiInputMethod::pickNextSegFromTurnout(pos_type next_seg_pos,
 	// but typically only one is used
 	for (auto past_attr = d->seg_turnout_.begin();
 	     past_attr != d->seg_turnout_.end(); past_attr++) {
-		if ((*past_attr).start_ == next_seg_pos) {
+		if (past_attr->start_ == next_seg_pos) {
 			PreeditSegment seg;
 			if (cf != nullptr) {
-				cf->merge((*past_attr).char_format_);
-				seg = {(*past_attr).start_,
-								  (size_type)(*past_attr).length_, *cf};
+				cf->merge(past_attr->char_format_);
+				seg = {past_attr->start_,
+								  (size_type)past_attr->length_, *cf};
 			} else
-				seg = {(*past_attr).start_,
-								  (size_type)(*past_attr).length_,
-								  (*past_attr).char_format_};
+				seg = {past_attr->start_,
+								  (size_type)past_attr->length_,
+								  past_attr->char_format_};
 			LYXERR(Debug::KEY,
-			       "Pushing to preedit register: (" << (*past_attr).start_
-			        << ", " << (*past_attr).start_ + (*past_attr).length_ - 1
+			       "Pushing to preedit register: [" << past_attr->start_
+			        << ", " << past_attr->start_ + past_attr->length_
 			        << ") fg: "
-			        << (*past_attr).char_format_.foreground().color().name()
+			        << past_attr->char_format_.foreground().color().name(QColor::HexArgb)
 			        << " bg: "
-			        << (*past_attr).char_format_.background().color().name());
+			        << past_attr->char_format_.background().color().name(QColor::HexArgb));
 			d->style_.segments_.push_back(seg);
-			next_seg_pos += (*past_attr).length_;
+			next_seg_pos += past_attr->length_;
 			if (d->seg_turnout_.size() > 1)
 				to_erase = past_attr;
 			is_matched = true;
@@ -636,15 +646,15 @@ pos_type GuiInputMethod::pickNextSegFromTurnout(pos_type next_seg_pos,
 	// Clear d->seg_turnout_
 	if (is_matched) {
 		if (d->seg_turnout_.size() == 1) {
-			LYXERR(Debug::KEY, "Preedit turnout clearing:    ("
+			LYXERR(Debug::KEY, "Preedit turnout clearing:    ["
 			        << d->seg_turnout_.back().start_ << ", "
 			        << d->seg_turnout_.back().start_
-			               + d->seg_turnout_.back().length_ - 1 << ")");
+			               + d->seg_turnout_.back().length_ << ")");
 			d->seg_turnout_.pop_back();
 		} else if (d->seg_turnout_.size() > 1) {
-			LYXERR(Debug::KEY, "Preedit turnout clearing: ("
+			LYXERR(Debug::KEY, "Preedit turnout clearing: ["
 			        << (*to_erase).start_ << ", "
-			        << (*to_erase).start_ + (*to_erase).length_ - 1 << ")");
+			        << (*to_erase).start_ + (*to_erase).length_ << ")");
 			d->seg_turnout_.erase(to_erase);
 		}
 	}
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs