commit 78754b0d9c09dafe551ed719c976792173065a01
Author: Juergen Spitzmueller <[email protected]>
Date:   Sat May 16 09:03:41 2026 +0200

    Adapt cursor color to background color (part of #13312)
    
    I.e., in dark mode with a light inset background, use a dark cursor
    
    Co-production with JMarc
---
 src/BufferView.cpp               | 13 +++++++++++++
 src/BufferView.h                 |  3 +++
 src/Color.cpp                    |  1 +
 src/ColorCode.h                  |  2 ++
 src/Cursor.cpp                   |  6 +++---
 src/CursorSlice.cpp              | 14 +++++++++++++-
 src/CursorSlice.h                |  4 +++-
 src/DocIterator.cpp              | 22 ++++++++++------------
 src/DocIterator.h                |  5 ++++-
 src/frontends/qt/GuiWorkArea.cpp | 16 ++++++++++++++--
 src/insets/InsetText.cpp         |  4 ++--
 src/mathed/InsetMath.h           |  2 ++
 src/mathed/InsetMathHull.cpp     |  2 +-
 13 files changed, 71 insertions(+), 23 deletions(-)

diff --git a/src/BufferView.cpp b/src/BufferView.cpp
index 995ea8a85d..c64eb8a8ae 100644
--- a/src/BufferView.cpp
+++ b/src/BufferView.cpp
@@ -21,6 +21,7 @@
 #include "BufferList.h"
 #include "BufferParams.h"
 #include "BiblioInfo.h"
+#include "ColorSet.h"
 #include "CoordCache.h"
 #include "Cursor.h"
 #include "CutAndPaste.h"
@@ -3479,6 +3480,18 @@ int BufferView::updateMetrics(bool force)
 }
 
 
+string BufferView::getCaretBackground()
+{
+       Inset const * covering_inset = cursor().realInset();
+       if (!covering_inset)
+               return "background";
+
+       frontend::NullPainter np;
+       PainterInfo pi(this, np);
+       return lcolor.getLyXName(covering_inset->backgroundColor(pi));
+}
+
+
 void BufferView::updatePosCache()
 {
        // this is the "nodraw" drawing stage: only set the positions of the
diff --git a/src/BufferView.h b/src/BufferView.h
index 9823fccea7..91fe571b96 100644
--- a/src/BufferView.h
+++ b/src/BufferView.h
@@ -416,6 +416,9 @@ public:
        /// Inserted label from ref dialog
        std::string const & insertedLabel() const { return inserted_label_; }
 
+       ///
+       std::string getCaretBackground();
+
 private:
        /// noncopyable
        BufferView(BufferView const &);
diff --git a/src/Color.cpp b/src/Color.cpp
index 36629c015b..4e33541db8 100644
--- a/src/Color.cpp
+++ b/src/Color.cpp
@@ -261,6 +261,7 @@ ColorSet::ColorSet()
        { Color_violet, N_("violet"), "violet", violet, violet, "violet" },
        { Color_yellow, N_("yellow"), "yellow", yellow, yellow, "yellow" },
        { Color_cursor, N_("cursor"), "cursor", black, Linen, "cursor" },
+       { Color_cursor_inverted, N_("cursor (inverted background)"), 
"cursor_inverted", Linen, black, "cursor_inverted" },
        { Color_background, N_("background"), "background", Linen, black, 
"background" },
        { Color_foreground, N_("text"), "foreground", black, Linen, 
"foreground" },
        { Color_foreground_inverted, N_("text (inverted background)"), 
"foreground_inverted", Linen, black, "foreground_inverted" },
diff --git a/src/ColorCode.h b/src/ColorCode.h
index 60837a3c2c..4a20ca2955 100644
--- a/src/ColorCode.h
+++ b/src/ColorCode.h
@@ -65,6 +65,8 @@ enum ColorCode {
        Color_foreground,
        /// Foreground color in inverted background
        Color_foreground_inverted,
+       /// Cursor color on inverted background
+       Color_cursor_inverted,
        /// Background color of selected text
        Color_selection,
        /// Foreground color of selected math
diff --git a/src/Cursor.cpp b/src/Cursor.cpp
index 52c8bf2821..3141660515 100644
--- a/src/Cursor.cpp
+++ b/src/Cursor.cpp
@@ -2456,7 +2456,7 @@ bool notifyCursorLeavesOrEnters(Cursor const & old, 
Cursor & cur)
        // find inset in common
        size_type i;
        for (i = 0; i < old.depth() && i < cur.depth(); ++i) {
-               if (&old[i].inset() != &cur[i].inset())
+               if (old[i].realInset() != cur[i].realInset())
                        break;
        }
 
@@ -2473,14 +2473,14 @@ bool notifyCursorLeavesOrEnters(Cursor const & old, 
Cursor & cur)
        for (size_type j = i; j < old.depth(); ++j) {
                Cursor inset_pos = old;
                inset_pos.resize(j + 1);
-               if (old[j].inset().notifyCursorLeaves(inset_pos, cur))
+               if (old[j].realInset()->notifyCursorLeaves(inset_pos, cur))
                        return true;
        }
 
        // notify everything on top of the common part in new cursor,
        // but stop if the inset claims the cursor to be invalid now
        for (; i < cur.depth(); ++i) {
-               if (cur[i].inset().notifyCursorEnters(old, cur))
+               if (cur[i].realInset()->notifyCursorEnters(old, cur))
                        return true;
        }
 
diff --git a/src/CursorSlice.cpp b/src/CursorSlice.cpp
index 522e35b7b8..e6f941e1c5 100644
--- a/src/CursorSlice.cpp
+++ b/src/CursorSlice.cpp
@@ -19,12 +19,13 @@
 #include "Paragraph.h"
 #include "ParagraphList.h"
 
-#include "support/debug.h"
+#include "insets/InsetTabular.h"
 
 #include "mathed/InsetMath.h"
 #include "mathed/InsetMathMacro.h"
 #include "mathed/MathData.h"
 
+#include "support/debug.h"
 #include "support/lassert.h"
 
 #include <ostream>
@@ -52,6 +53,17 @@ MathData & CursorSlice::cell() const
 }
 
 
+Inset * CursorSlice::realInset() const
+{
+       // if we are in a tabular, we need the cell
+       if (inset().lyxCode() == TABULAR_CODE) {
+               InsetTabular * tabular = inset().asInsetTabular();
+               return tabular->cell(idx()).get();
+       }
+       return &inset();
+}
+
+
 Paragraph & CursorSlice::paragraph() const
 {
        return text()->getPar(pit_);
diff --git a/src/CursorSlice.h b/src/CursorSlice.h
index 6eb6ff5aba..794c5b1e91 100644
--- a/src/CursorSlice.h
+++ b/src/CursorSlice.h
@@ -59,8 +59,10 @@ public:
 
        /// return true if the slice has not been initialized
        bool empty() const { return !inset_; }
-       /// the current inset
+       /// the containing inset
        Inset & inset() const { return *inset_; }
+       /// the containing inset or the (tabular) cell, respectively
+       Inset * realInset() const;
        /// return the cell this cursor is in
        idx_type idx() const { return idx_; }
        /// return the cell this cursor is in
diff --git a/src/DocIterator.cpp b/src/DocIterator.cpp
index 7d18c36547..2024bcc00c 100644
--- a/src/DocIterator.cpp
+++ b/src/DocIterator.cpp
@@ -127,18 +127,6 @@ Inset * DocIterator::prevInset() const
 }
 
 
-Inset * DocIterator::realInset() const
-{
-       LASSERT(inTexted(), return nullptr);
-       // if we are in a tabular, we need the cell
-       if (inset().lyxCode() == TABULAR_CODE) {
-               InsetTabular * tabular = inset().asInsetTabular();
-               return tabular->cell(idx()).get();
-       }
-       return &inset();
-}
-
-
 InsetMath & DocIterator::nextMath()
 {
        return *nextAtom().nucleus();
@@ -714,6 +702,16 @@ size_type DocIterator::find(Inset const * inset) const
 }
 
 
+size_type DocIterator::findInsetOrRealInset(Inset const * inset) const
+{
+       for (size_t l = 0; l != slices_.size(); ++l) {
+               if (&slices_[l].inset() == inset || slices_[l].realInset() == 
inset)
+                       return l;
+       }
+       return lyx::npos;
+}
+
+
 void DocIterator::resize(size_type count, vector<CursorSlice> & cut)
 {
        LASSERT(count <= depth(), return);
diff --git a/src/DocIterator.h b/src/DocIterator.h
index f46d57598f..61ad46ab97 100644
--- a/src/DocIterator.h
+++ b/src/DocIterator.h
@@ -182,7 +182,7 @@ public:
        ///
        Text * text() const;
        /// the containing inset or the cell, respectively
-       Inset * realInset() const;
+       Inset * realInset() const { return top().realInset(); }
        ///
        Inset * innerInsetOfType(int code) const;
        ///
@@ -265,6 +265,9 @@ public:
        size_type find(MathData const & cell) const;
        /// find index of CursorSlice with inset() == inset (or lyx::npos of 
not found)
        size_type find(Inset const * inset) const;
+       /// find index of CursorSlice with inset() == inset or realInset() == 
inset
+       /// (or lyx::npos of not found)
+       size_type findInsetOrRealInset(Inset const * inset) const;
        /// push CursorSlices on top
        void append(std::vector<CursorSlice> const & x);
        /// push one CursorSlice on top and set its index and position
diff --git a/src/frontends/qt/GuiWorkArea.cpp b/src/frontends/qt/GuiWorkArea.cpp
index 9e1cbb4655..5a067ef9aa 100644
--- a/src/frontends/qt/GuiWorkArea.cpp
+++ b/src/frontends/qt/GuiWorkArea.cpp
@@ -15,7 +15,6 @@
 #include "GuiWorkArea.h"
 #include "GuiWorkArea_Private.h"
 
-#include "ColorCache.h"
 #include "GuiApplication.h"
 #include "GuiCompleter.h"
 #include "GuiKeySymbol.h"
@@ -28,6 +27,7 @@
 #include "BufferList.h"
 #include "BufferParams.h"
 #include "BufferView.h"
+#include "ColorCache.h"
 #include "CoordCache.h"
 #include "Cursor.h"
 #include "Font.h"
@@ -576,7 +576,19 @@ void GuiWorkArea::Private::drawCaret(QPainter & painter, 
int horiz_offset) const
        if (buffer_view_->caretGeometry().shapes.empty())
                return;
 
-       QColor const color = guiApp->colorCache().get(Color_cursor);
+       QColor const color = (
+               !buffer_view_->getCaretBackground().empty()
+               && buffer_view_->getCaretBackground() != "none"
+               && ((guiApp->colorCache().isDarkMode()
+                   && guiApp->colorCache().isLightColor(
+                          rgbFromHexName(lcolor.getX11HexName(
+                                                 
buffer_view_->getCaretBackground(), true))))
+               || (!guiApp->colorCache().isDarkMode()
+                   && !guiApp->colorCache().isLightColor(rgbFromHexName(
+                                                             
lcolor.getX11HexName(
+                                                                     
buffer_view_->getCaretBackground()))))))
+                       ? guiApp->colorCache().get(Color_cursor_inverted)
+                       : guiApp->colorCache().get(Color_cursor);
        painter.setPen(color);
        painter.setRenderHint(QPainter::Antialiasing, true);
        for (auto const & shape : buffer_view_->caretGeometry().shapes) {
diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp
index f01b0fbf3c..4e92a1236d 100644
--- a/src/insets/InsetText.cpp
+++ b/src/insets/InsetText.cpp
@@ -1324,12 +1324,12 @@ bool InsetText::notifyCursorLeaves(Cursor const & old, 
Cursor & cur)
 
        // find text inset in old cursor
        Cursor insetCur = old;
-       size_type scriptSlice = insetCur.find(this);
+       size_type scriptSlice = insetCur.findInsetOrRealInset(this);
        // we can try to continue here. returning true means
        // the cursor is "now" invalid. which it was.
        LASSERT(scriptSlice != lyx::npos, return true);
        insetCur.resize(scriptSlice + 1);
-       LASSERT(&insetCur.inset() == this, return true);
+       LASSERT(&insetCur.inset() == this || insetCur.realInset() == this, 
return true);
 
        // update the old paragraph's words
        insetCur.paragraph().updateWords();
diff --git a/src/mathed/InsetMath.h b/src/mathed/InsetMath.h
index 6f580c3def..03adeb820f 100644
--- a/src/mathed/InsetMath.h
+++ b/src/mathed/InsetMath.h
@@ -277,6 +277,8 @@ public:
        InsetCode lyxCode() const override { return MATH_CODE; }
        ///
        uid_type id() const { return this; }
+       ///
+       ColorCode backgroundColor(PainterInfo const &) const override { return 
Color_mathbg; };
 };
 
 ///
diff --git a/src/mathed/InsetMathHull.cpp b/src/mathed/InsetMathHull.cpp
index 8e98b75e46..9ba086a715 100644
--- a/src/mathed/InsetMathHull.cpp
+++ b/src/mathed/InsetMathHull.cpp
@@ -617,7 +617,7 @@ ColorCode InsetMathHull::backgroundColor(PainterInfo const 
& pi) const
                        return Color_error;
                return graphics::PreviewLoader::backgroundColor();
        }
-       return Color_mathbg;
+       return InsetMath::backgroundColor(pi);
 }
 
 
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to