diff options
author | Neil <nyamatongwe@gmail.com> | 2021-05-12 09:13:07 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2021-05-12 09:13:07 +1000 |
commit | 2feaeaf738851055a79ffcfb9027a3637610faca (patch) | |
tree | 6039c295b12073a5269ac667bbb886cf440d737b | |
parent | 5468995af334359c04625dbd374658bbf91b0449 (diff) | |
download | scintilla-mirror-2feaeaf738851055a79ffcfb9027a3637610faca.tar.gz |
Switch caret line background colour to SC_ELEMENT_CARET_LINE_BACK element and
add SetCaretLineLayer.
Older caret line APIs SCI_SETCARETLINEVISIBLE, SCI_SETCARETLINEBACK,
SCI_SETCARETLINEBACKALPHA now discouraged.
-rw-r--r-- | doc/ScintillaDoc.html | 68 | ||||
-rw-r--r-- | doc/ScintillaHistory.html | 6 | ||||
-rw-r--r-- | include/Scintilla.h | 3 | ||||
-rw-r--r-- | include/Scintilla.iface | 7 | ||||
-rw-r--r-- | src/EditView.cxx | 51 | ||||
-rw-r--r-- | src/Editor.cxx | 50 | ||||
-rw-r--r-- | src/Geometry.h | 4 | ||||
-rw-r--r-- | src/ViewStyle.cxx | 19 | ||||
-rw-r--r-- | src/ViewStyle.h | 10 | ||||
-rw-r--r-- | test/simpleTests.py | 101 |
10 files changed, 240 insertions, 79 deletions
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index fcce51dd0..2ba53c837 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -3408,6 +3408,13 @@ struct Sci_TextToFind { <td>All</td> <td>Colour of carets when another window has focus</td> </tr> + <tr> + <th align="left"><code>SC_ELEMENT_CARET_LINE_BACK</code></th> + <td>50</td> + <td>Translucent</td> + <td>All</td> + <td>Colour of caret line background</td> + </tr> </tbody> </table> @@ -3454,12 +3461,15 @@ struct Sci_TextToFind { <a class="element" href="#SC_ELEMENT_SELECTION_NO_FOCUS_TEXT">SC_ELEMENT_SELECTION_NO_FOCUS_TEXT : colouralpha</a><br /> <a class="element" href="#SC_ELEMENT_SELECTION_NO_FOCUS_BACK">SC_ELEMENT_SELECTION_NO_FOCUS_BACK : colouralpha</a><br /> <br /> - <a class="message" href="#SCI_SETCARETLINEVISIBLE">SCI_SETCARETLINEVISIBLE(bool show)</a><br /> - <a class="message" href="#SCI_GETCARETLINEVISIBLE">SCI_GETCARETLINEVISIBLE → bool</a><br /> - <a class="message" href="#SCI_SETCARETLINEBACK">SCI_SETCARETLINEBACK(colour back)</a><br /> - <a class="message" href="#SCI_GETCARETLINEBACK">SCI_GETCARETLINEBACK → colour</a><br /> - <a class="message" href="#SCI_SETCARETLINEBACKALPHA">SCI_SETCARETLINEBACKALPHA(alpha alpha)</a><br /> - <a class="message" href="#SCI_GETCARETLINEBACKALPHA">SCI_GETCARETLINEBACKALPHA → int</a><br /> + <a class="element" href="#SC_ELEMENT_CARET_LINE_BACK">SC_ELEMENT_CARET_LINE_BACK : colouralpha</a><br /> + <a class="message" href="#SCI_SETCARETLINELAYER">SCI_SETCARETLINELAYER(int layer)</a><br /> + <a class="message" href="#SCI_GETCARETLINELAYER">SCI_GETCARETLINELAYER → int</a><br /> + <a class="discouraged message" href="#SCI_SETCARETLINEVISIBLE">SCI_SETCARETLINEVISIBLE(bool show)</a><br /> + <a class="discouraged message" href="#SCI_GETCARETLINEVISIBLE">SCI_GETCARETLINEVISIBLE → bool</a><br /> + <a class="discouraged message" href="#SCI_SETCARETLINEBACK">SCI_SETCARETLINEBACK(colour back)</a><br /> + <a class="discouraged message" href="#SCI_GETCARETLINEBACK">SCI_GETCARETLINEBACK → colour</a><br /> + <a class="discouraged message" href="#SCI_SETCARETLINEBACKALPHA">SCI_SETCARETLINEBACKALPHA(alpha alpha)</a><br /> + <a class="discouraged message" href="#SCI_GETCARETLINEBACKALPHA">SCI_GETCARETLINEBACKALPHA → int</a><br /> <a class="message" href="#SCI_SETCARETLINEFRAME">SCI_SETCARETLINEFRAME(int width)</a><br /> <a class="message" href="#SCI_GETCARETLINEFRAME">SCI_GETCARETLINEFRAME → int</a><br /> <a class="message" href="#SCI_SETCARETLINEVISIBLEALWAYS">SCI_SETCARETLINEVISIBLEALWAYS(bool alwaysVisible)</a><br /> @@ -3565,14 +3575,47 @@ struct Sci_TextToFind { These elements define the colours to be used for selections without focus. </p> + <p> + <b id="SC_ELEMENT_CARET_LINE_BACK">SC_ELEMENT_CARET_LINE_BACK : colouralpha</b><br /> + <b id="SCI_SETCARETLINELAYER">SCI_SETCARETLINELAYER(int layer)</b><br /> + <b id="SCI_GETCARETLINELAYER">SCI_GETCARETLINELAYER → int</b><br /> + You can choose to make the background colour of the line containing the caret different by setting the + <code>SC_ELEMENT_CARET_LINE_BACK</code> element with + <a class="message" href="#SCI_SETELEMENTCOLOUR"><code>SCI_SETELEMENTCOLOUR(SC_ELEMENT_CARET_LINE_BACK)</code></a>. + This effect may be drawn translucently over the text or opaquely on the base layer with <code>SCI_SETCARETLINELAYER</code>. + Background colouring has highest priority when a line has markers that would otherwise change + the background colour. When drawn translucently other background colours can show through. + The <code class="parameter">layer</code> argument can be one of:</p> + + <table class="standard" summary="Layer"> + <tbody valign="top"> + <tr> + <th align="left"><code>SC_LAYER_BASE</code></th> + + <td>0</td> + + <td>Draw the caret line background opaquely on the base layer</td> + </tr> + + <tr> + <th align="left"><code>SC_LAYER_OVER_TEXT</code></th> + + <td>10</td> + + <td>Draw the caret line background translucently over the text</td> + </tr> + + </tbody> + </table> + <p><b id="SCI_SETCARETLINEVISIBLE">SCI_SETCARETLINEVISIBLE(bool show)</b><br /> <b id="SCI_GETCARETLINEVISIBLE">SCI_GETCARETLINEVISIBLE → bool</b><br /> <b id="SCI_SETCARETLINEBACK">SCI_SETCARETLINEBACK(<a class="jump" href="#colour">colour</a> back)</b><br /> <b id="SCI_GETCARETLINEBACK">SCI_GETCARETLINEBACK → colour</b><br /> <b id="SCI_SETCARETLINEBACKALPHA">SCI_SETCARETLINEBACKALPHA(<a class="jump" href="#alpha">alpha</a> alpha)</b><br /> <b id="SCI_GETCARETLINEBACKALPHA">SCI_GETCARETLINEBACKALPHA → int</b><br /> - <b id="SCI_SETCARETLINEFRAME">SCI_SETCARETLINEFRAME(int width)</b><br /> - <b id="SCI_GETCARETLINEFRAME">SCI_GETCARETLINEFRAME → int</b><br /> + These APIs are discouraged. It is better to use the <code>SC_ELEMENT_CARET_LINE_BACK</code> + element mentioned in the previous section.<br /> You can choose to make the background colour of the line containing the caret different with these messages. To do this, set the desired background colour with <code>SCI_SETCARETLINEBACK</code>, then use <code>SCI_SETCARETLINEVISIBLE(true)</code> to @@ -3584,10 +3627,15 @@ struct Sci_TextToFind { through. This is done by setting the alpha (translucency) value by calling SCI_SETCARETLINEBACKALPHA. When the alpha is not SC_ALPHA_NOALPHA, the caret line is drawn after all other features so will affect the colour of all other features. - Alternatively <code>SCI_SETCARETLINEFRAME</code> can be used to display the caret line framed - instead of filling the whole background. Set width != 0 to enable this option and width = 0 to disable it. </p> + <p> + <b id="SCI_SETCARETLINEFRAME">SCI_SETCARETLINEFRAME(int width)</b><br /> + <b id="SCI_GETCARETLINEFRAME">SCI_GETCARETLINEFRAME → int</b><br /> + <code>SCI_SETCARETLINEFRAME</code> can be used to display the caret line framed + instead of filling the whole background. Set width != 0 to enable this option and width = 0 to disable it. + </p> + <p><b id="SCI_SETCARETLINEVISIBLEALWAYS">SCI_SETCARETLINEVISIBLEALWAYS(bool alwaysVisible)</b><br /> <b id="SCI_GETCARETLINEVISIBLEALWAYS">SCI_GETCARETLINEVISIBLEALWAYS → bool</b><br /> Choose to make the caret line always visible even when the window is not in focus. diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 64260aa88..6985807e1 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -586,6 +586,12 @@ translucently over text or opaquely underneath other drawing. </li> <li> + Change caret line drawing to use SC_ELEMENT_CARET_LINE_BACK element and + SCI_SETCARETLINELAYER method. + Older caret line APIs SCI_SETCARETLINEVISIBLE, SCI_SETCARETLINEBACK, + SCI_SETCARETLINEBACKALPHA now discouraged. + </li> + <li> Add SCI_GETELEMENTBASECOLOUR to return the default values for element colours. </li> <li> diff --git a/include/Scintilla.h b/include/Scintilla.h index 820dc470a..d48ad6c5a 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -284,6 +284,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_ELEMENT_CARET 40 #define SC_ELEMENT_CARET_ADDITIONAL 41 #define SC_ELEMENT_CARET_SECONDARY 42 +#define SC_ELEMENT_CARET_LINE_BACK 50 #define SCI_SETELEMENTCOLOUR 2753 #define SCI_GETELEMENTCOLOUR 2754 #define SCI_RESETELEMENTCOLOUR 2755 @@ -300,6 +301,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_LAYER_OVER_TEXT 10 #define SCI_GETSELECTIONLAYER 2762 #define SCI_SETSELECTIONLAYER 2763 +#define SCI_GETCARETLINELAYER 2764 +#define SCI_SETCARETLINELAYER 2765 #define SCI_SETCARETFORE 2069 #define SCI_ASSIGNCMDKEY 2070 #define SCI_CLEARCMDKEY 2071 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index a51c0d611..8a2b0de66 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -687,6 +687,7 @@ val SC_ELEMENT_SELECTION_NO_FOCUS_BACK=17 val SC_ELEMENT_CARET=40 val SC_ELEMENT_CARET_ADDITIONAL=41 val SC_ELEMENT_CARET_SECONDARY=42 +val SC_ELEMENT_CARET_LINE_BACK=50 # Set the colour of an element. Translucency (alpha) may or may not be significant # and this may depend on the platform. The alpha byte should commonly be 0xff for opaque. @@ -736,6 +737,12 @@ get Layer GetSelectionLayer=2762(,) # Set the layer for drawing selections: either opaquely on base layer or translucently over text set void SetSelectionLayer=2763(Layer layer,) +# Get the layer of the background of the line containing the caret. +get Layer GetCaretLineLayer=2764(,) + +# Set the layer of the background of the line containing the caret. +set void SetCaretLineLayer=2765(Layer layer,) + # Set the foreground colour of the caret. set void SetCaretFore=2069(colour fore,) diff --git a/src/EditView.cxx b/src/EditView.cxx index 5549e73db..2b389ecee 100644 --- a/src/EditView.cxx +++ b/src/EditView.cxx @@ -919,35 +919,35 @@ static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle r textBack, textFore); } -static void DrawFrame(Surface *surface, ColourAlpha colour, int alpha, PRectangle rcFrame) { - if (alpha != SC_ALPHA_NOALPHA) { - surface->AlphaRectangle(rcFrame, 0, FillStroke(ColourAlpha(colour, alpha))); - } else { - surface->FillRectangleAligned(rcFrame, Fill(colour)); +static void DrawCaretLineFramed(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, int subLine) { + const std::optional<ColourAlpha> caretlineBack = vsDraw.ElementColour(SC_ELEMENT_CARET_LINE_BACK); + if (!caretlineBack) { + return; } -} -static void DrawCaretLineFramed(Surface *surface, const ViewStyle &vsDraw, const LineLayout *ll, PRectangle rcLine, int subLine) { + const ColourAlpha colourFrame = (vsDraw.caretLine.layer == Layer::base) ? + caretlineBack->Opaque() : *caretlineBack; + const int width = vsDraw.GetFrameWidth(); - if (subLine == 0 || ll->wrapIndent == 0 || vsDraw.caretLine.alpha != SC_ALPHA_NOALPHA) { + + // Avoid double drawing the corners by removing the left and right sides when drawing top and bottom borders + const PRectangle rcWithoutLeftRight = rcLine.Inset(Point(width, 0.0)); + + if (subLine == 0 || ll->wrapIndent == 0 || vsDraw.caretLine.layer == Layer::over) { // Left - DrawFrame(surface, vsDraw.caretLine.background, vsDraw.caretLine.alpha, - PRectangle(rcLine.left, rcLine.top, rcLine.left + width, rcLine.bottom)); + surface->FillRectangleAligned(Side(rcLine, Edge::left, width), colourFrame); } if (subLine == 0) { // Top - DrawFrame(surface, vsDraw.caretLine.background, vsDraw.caretLine.alpha, - PRectangle(rcLine.left + width, rcLine.top, rcLine.right - width, rcLine.top + width)); + surface->FillRectangleAligned(Side(rcWithoutLeftRight, Edge::top, width), colourFrame); } - if (subLine == ll->lines - 1 || vsDraw.caretLine.alpha != SC_ALPHA_NOALPHA) { + if (subLine == ll->lines - 1 || vsDraw.caretLine.layer == Layer::over) { // Right - DrawFrame(surface, vsDraw.caretLine.background, vsDraw.caretLine.alpha, - PRectangle(rcLine.right - width, rcLine.top, rcLine.right, rcLine.bottom)); + surface->FillRectangleAligned(Side(rcLine, Edge::right, width), colourFrame); } if (subLine == ll->lines - 1) { // Bottom - DrawFrame(surface, vsDraw.caretLine.background, vsDraw.caretLine.alpha, - PRectangle(rcLine.left + width, rcLine.bottom - width, rcLine.right - width, rcLine.bottom)); + surface->FillRectangleAligned(Side(rcWithoutLeftRight, Edge::bottom, width), colourFrame); } } @@ -1082,10 +1082,9 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; } if (vsDraw.IsLineFrameOpaque(model.caret.active, ll->containsCaret)) { - const int width = vsDraw.GetFrameWidth(); // Draw right of frame under marker - DrawFrame(surface, vsDraw.caretLine.background, vsDraw.caretLine.alpha, - PRectangle(rcLine.right - width, rcLine.top, rcLine.right, rcLine.bottom)); + surface->FillRectangleAligned(Side(rcLine, Edge::right, vsDraw.GetFrameWidth()), + vsDraw.ElementColour(SC_ELEMENT_CARET_LINE_BACK)->Opaque()); } } @@ -1667,10 +1666,9 @@ static void DrawWrapIndentAndMarker(Surface *surface, const ViewStyle &vsDraw, c vsDraw.styles[STYLE_DEFAULT].back)); if (vsDraw.IsLineFrameOpaque(caretActive, ll->containsCaret)) { - const int width = vsDraw.GetFrameWidth(); // Draw left of frame under marker - DrawFrame(surface, vsDraw.caretLine.background, vsDraw.caretLine.alpha, - PRectangle(rcLine.left, rcLine.top, rcLine.left + width, rcLine.bottom)); + surface->FillRectangleAligned(Side(rcLine, Edge::left, vsDraw.GetFrameWidth()), + vsDraw.ElementColour(SC_ELEMENT_CARET_LINE_BACK)->Opaque()); } if (vsDraw.wrap.visualFlags & SC_WRAPVISUALFLAG_START) { @@ -1872,12 +1870,12 @@ static void DrawTranslucentSelection(Surface *surface, const EditModel &model, c // Draw any translucent whole line states static void DrawTranslucentLineState(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcLine, int subLine) { - if ((model.caret.active || vsDraw.caretLine.alwaysShow) && vsDraw.caretLine.show && ll->containsCaret && - vsDraw.caretLine.alpha != SC_ALPHA_NOALPHA) { + if ((model.caret.active || vsDraw.caretLine.alwaysShow) && vsDraw.ElementColour(SC_ELEMENT_CARET_LINE_BACK) && ll->containsCaret && + vsDraw.caretLine.layer == Layer::over) { if (vsDraw.caretLine.frame) { DrawCaretLineFramed(surface, vsDraw, ll, rcLine, subLine); } else { - SimpleAlphaRectangle(surface, rcLine, vsDraw.caretLine.background, vsDraw.caretLine.alpha); + surface->FillRectangleAligned(rcLine, *vsDraw.ElementColour(SC_ELEMENT_CARET_LINE_BACK)); } } const int marksOfLine = model.pdoc->GetMark(line); @@ -2526,7 +2524,6 @@ Sci::Position EditView::FormatRange(bool draw, const Sci_RangeToFormat *pfr, Sur vsPrint.elementBaseColours.clear(); vsPrint.whitespaceColours.back.reset(); vsPrint.whitespaceColours.fore.reset(); - vsPrint.caretLine.show = false; vsPrint.caretLine.alwaysShow = false; // Don't highlight matching braces using indicators vsPrint.braceHighlightIndicatorSet = false; diff --git a/src/Editor.cxx b/src/Editor.cxx index 35ca7bb77..694ac2f5f 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -7248,10 +7248,18 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return pdoc->GetMaxLineState(); case SCI_GETCARETLINEVISIBLE: - return vs.caretLine.show; + return vs.ElementColour(SC_ELEMENT_CARET_LINE_BACK) ? 1 : 0; case SCI_SETCARETLINEVISIBLE: - vs.caretLine.show = wParam != 0; - InvalidateStyleRedraw(); + if (wParam) { + if (!vs.elementColours.count(SC_ELEMENT_CARET_LINE_BACK)) { + vs.elementColours[SC_ELEMENT_CARET_LINE_BACK] = ColourAlpha(0xFF, 0xFF, 0); + InvalidateStyleRedraw(); + } + } else { + if (vs.ResetElement(SC_ELEMENT_CARET_LINE_BACK)) { + InvalidateStyleRedraw(); + } + } break; case SCI_GETCARETLINEVISIBLEALWAYS: return vs.caretLine.alwaysShow; @@ -7267,16 +7275,38 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { InvalidateStyleRedraw(); break; case SCI_GETCARETLINEBACK: - return vs.caretLine.background.OpaqueRGB(); + if (vs.ElementColour(SC_ELEMENT_CARET_LINE_BACK)) + return vs.ElementColour(SC_ELEMENT_CARET_LINE_BACK)->OpaqueRGB(); + else + return 0; + case SCI_SETCARETLINEBACK: - vs.caretLine.background = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.SetElementRGB(SC_ELEMENT_CARET_LINE_BACK, static_cast<int>(wParam)); InvalidateStyleRedraw(); break; + + case SCI_GETCARETLINELAYER: + return static_cast<sptr_t>(vs.caretLine.layer); + + case SCI_SETCARETLINELAYER: + if (vs.caretLine.layer != static_cast<Layer>(wParam)) { + vs.caretLine.layer = static_cast<Layer>(wParam); + UpdateBaseElements(); + InvalidateStyleRedraw(); + } + break; + case SCI_GETCARETLINEBACKALPHA: - return vs.caretLine.alpha; - case SCI_SETCARETLINEBACKALPHA: - vs.caretLine.alpha = static_cast<int>(wParam); - InvalidateStyleRedraw(); + if (vs.caretLine.layer == Layer::base) + return SC_ALPHA_NOALPHA; + return vs.ElementColour(SC_ELEMENT_CARET_LINE_BACK).value_or(ColourAlpha()).GetAlpha(); + + case SCI_SETCARETLINEBACKALPHA: { + const Layer layerNew = (wParam == SC_ALPHA_NOALPHA) ? Layer::base : Layer::over; + vs.caretLine.layer = layerNew; + vs.SetElementAlpha(SC_ELEMENT_CARET_LINE_BACK, static_cast<int>(wParam)); + InvalidateStyleRedraw(); + } break; // Folding messages @@ -7441,7 +7471,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; case SCI_SETSELALPHA: { - Layer layerNew = (wParam == SC_ALPHA_NOALPHA) ? Layer::base : Layer::over; + const Layer layerNew = (wParam == SC_ALPHA_NOALPHA) ? Layer::base : Layer::over; if (vs.selection.layer != layerNew) { vs.selection.layer = layerNew; UpdateBaseElements(); diff --git a/src/Geometry.h b/src/Geometry.h index 01af92969..a6e49ad5b 100644 --- a/src/Geometry.h +++ b/src/Geometry.h @@ -129,6 +129,10 @@ public: return PRectangle(left + delta, top + delta, right - delta, bottom - delta); } + constexpr PRectangle Inset(Point delta) const noexcept { + return PRectangle(left + delta.x, top + delta.y, right - delta.x, bottom - delta.y); + } + constexpr Point Centre() const noexcept { return Point((left + right) / 2, (top + bottom) / 2); } diff --git a/src/ViewStyle.cxx b/src/ViewStyle.cxx index a8fcd2d8c..60334c2ea 100644 --- a/src/ViewStyle.cxx +++ b/src/ViewStyle.cxx @@ -243,10 +243,10 @@ void ViewStyle::Init(size_t stylesSize_) { caret.style = CARETSTYLE_LINE; caret.width = 1; - caretLine.background = ColourAlpha(0xff, 0xff, 0); - caretLine.show = false; + elementColours.erase(SC_ELEMENT_CARET_LINE_BACK); + elementAllowsTranslucent.insert(SC_ELEMENT_CARET_LINE_BACK); caretLine.alwaysShow = false; - caretLine.alpha = SC_ALPHA_NOALPHA; + caretLine.layer = Layer::base; caretLine.frame = 0; someStylesProtected = false; @@ -461,9 +461,10 @@ int ViewStyle::GetFrameWidth() const noexcept { return std::clamp(caretLine.frame, 1, lineHeight / 3); } -bool ViewStyle::IsLineFrameOpaque(bool caretActive, bool lineContainsCaret) const noexcept { - return caretLine.frame && (caretActive || caretLine.alwaysShow) && caretLine.show && - (caretLine.alpha == SC_ALPHA_NOALPHA) && lineContainsCaret; +bool ViewStyle::IsLineFrameOpaque(bool caretActive, bool lineContainsCaret) const { + return caretLine.frame && (caretActive || caretLine.alwaysShow) && + ElementColour(SC_ELEMENT_CARET_LINE_BACK) && + (caretLine.layer == Layer::base) && lineContainsCaret; } // See if something overrides the line background colour: Either if caret is on the line @@ -474,9 +475,9 @@ bool ViewStyle::IsLineFrameOpaque(bool caretActive, bool lineContainsCaret) cons // the colour for the highest numbered one is used. std::optional<ColourAlpha> ViewStyle::Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const { std::optional<ColourAlpha> background; - if (!caretLine.frame && (caretActive || caretLine.alwaysShow) && caretLine.show && - (caretLine.alpha == SC_ALPHA_NOALPHA) && lineContainsCaret) { - background = caretLine.background; + if (!caretLine.frame && (caretActive || caretLine.alwaysShow) && + (caretLine.layer == Layer::base) && lineContainsCaret) { + background = ElementColour(SC_ELEMENT_CARET_LINE_BACK); } if (!background && marksOfLine) { int marks = marksOfLine; diff --git a/src/ViewStyle.h b/src/ViewStyle.h index 13c489aa2..9f3cae123 100644 --- a/src/ViewStyle.h +++ b/src/ViewStyle.h @@ -73,14 +73,10 @@ struct SelectionAppearance { }; struct CaretLineAppearance { - // Colour of caret line - ColourAlpha background; - // Whether to show the caret line - bool show; + // Whether to draw on base layer or over text + Layer layer; // Also show when non-focused bool alwaysShow; - // Translucency. SC_ALPHA_NOALPHA: draw selection background beneath text - int alpha; // Non-0: draw a rectangle around line instead of filling line. Value is pixel width of frame int frame; }; @@ -222,7 +218,7 @@ public: bool ValidStyle(size_t styleIndex) const noexcept; void CalcLargestMarkerHeight() noexcept; int GetFrameWidth() const noexcept; - bool IsLineFrameOpaque(bool caretActive, bool lineContainsCaret) const noexcept; + bool IsLineFrameOpaque(bool caretActive, bool lineContainsCaret) const; std::optional<ColourAlpha> Background(int marksOfLine, bool caretActive, bool lineContainsCaret) const; bool SelectionBackgroundDrawn() const noexcept; bool SelectionTextDrawn() const; diff --git a/test/simpleTests.py b/test/simpleTests.py index c1407ad7c..9ac1c43fd 100644 --- a/test/simpleTests.py +++ b/test/simpleTests.py @@ -1933,50 +1933,119 @@ class TestElements(unittest.TestCase): self.ed.ClearAll() self.ed.EmptyUndoBuffer() self.testColourAlpha = 0x18171615 + self.opaque = 0xff000000 + self.dropAlpha = 0x00ffffff def tearDown(self): pass + + def ElementColour(self, element): + # & 0xffffffff prevents sign extension issues + return self.ed.GetElementColour(element) & 0xffffffff + + def RestoreCaretLine(self): + self.ed.CaretLineLayer = 0 + self.ed.CaretLineFrame = 0 + self.ed.ResetElementColour(self.ed.SC_ELEMENT_CARET_LINE_BACK) + self.ed.CaretLineVisibleAlways = False def testIsSet(self): - self.assertEquals(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_SELECTION_TEXT), 0) + self.assertFalse(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_SELECTION_TEXT)) def testAllowsTranslucent(self): - self.assertEquals(self.ed.GetElementAllowsTranslucent(self.ed.SC_ELEMENT_LIST), 0) - self.assertEquals(self.ed.GetElementAllowsTranslucent(self.ed.SC_ELEMENT_SELECTION_TEXT), 1) + self.assertFalse(self.ed.GetElementAllowsTranslucent(self.ed.SC_ELEMENT_LIST)) + self.assertTrue(self.ed.GetElementAllowsTranslucent(self.ed.SC_ELEMENT_SELECTION_TEXT)) def testChanging(self): self.ed.SetElementColour(self.ed.SC_ELEMENT_LIST_BACK, self.testColourAlpha) - self.assertEquals(self.ed.GetElementColour(self.ed.SC_ELEMENT_LIST_BACK), self.testColourAlpha) - self.assertEquals(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_LIST_BACK), 1) + self.assertEquals(self.ElementColour(self.ed.SC_ELEMENT_LIST_BACK), self.testColourAlpha) + self.assertTrue(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_LIST_BACK)) def testReset(self): self.ed.SetElementColour(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT, self.testColourAlpha) - self.assertEquals(self.ed.GetElementColour(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT), self.testColourAlpha) + self.assertEquals(self.ElementColour(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT), self.testColourAlpha) self.ed.ResetElementColour(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT) - self.assertEquals(self.ed.GetElementColour(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT), 0) - self.assertEquals(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT), 0) + self.assertEquals(self.ElementColour(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT), 0) + self.assertFalse(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_SELECTION_ADDITIONAL_TEXT)) def testBaseColour(self): if sys.platform == "win32": # SC_ELEMENT_LIST* base colours only currently implemented on Win32 - opaque = 0xff000000 - dropAlpha = 0x00ffffff text = self.ed.GetElementBaseColour(self.ed.SC_ELEMENT_LIST) back = self.ed.GetElementBaseColour(self.ed.SC_ELEMENT_LIST_BACK) - self.assertEquals(text & opaque, opaque) - self.assertEquals(back & opaque, opaque) - self.assertNotEquals(text & dropAlpha, back & dropAlpha) + self.assertEquals(text & self.opaque, self.opaque) + self.assertEquals(back & self.opaque, self.opaque) + self.assertNotEquals(text & self.dropAlpha, back & self.dropAlpha) selText = self.ed.GetElementBaseColour(self.ed.SC_ELEMENT_LIST_SELECTED) selBack = self.ed.GetElementBaseColour(self.ed.SC_ELEMENT_LIST_SELECTED_BACK) - self.assertEquals(selText & opaque, opaque) - self.assertEquals(selBack & opaque, opaque) - self.assertNotEquals(selText & dropAlpha, selBack & dropAlpha) + self.assertEquals(selText & self.opaque, self.opaque) + self.assertEquals(selBack & self.opaque, self.opaque) + self.assertNotEquals(selText & self.dropAlpha, selBack & self.dropAlpha) def testSelectionLayer(self): self.ed.SelectionLayer = self.ed.SC_LAYER_OVER_TEXT self.assertEquals(self.ed.SelectionLayer, self.ed.SC_LAYER_OVER_TEXT) self.ed.SelectionLayer = self.ed.SC_LAYER_BASE self.assertEquals(self.ed.SelectionLayer, self.ed.SC_LAYER_BASE) + + def testCaretLine(self): + # Newer Layer / ElementColour API + self.assertEquals(self.ed.CaretLineLayer, 0) + self.assertFalse(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_CARET_LINE_BACK)) + self.assertEquals(self.ed.CaretLineFrame, 0) + self.assertFalse(self.ed.CaretLineVisibleAlways) + + self.ed.CaretLineLayer = 10 + self.assertEquals(self.ed.CaretLineLayer, 10) + self.ed.CaretLineFrame = 2 + self.assertEquals(self.ed.CaretLineFrame, 2) + self.ed.CaretLineVisibleAlways = True + self.assertTrue(self.ed.CaretLineVisibleAlways) + self.ed.SetElementColour(self.ed.SC_ELEMENT_CARET_LINE_BACK, self.testColourAlpha) + self.assertEquals(self.ElementColour(self.ed.SC_ELEMENT_CARET_LINE_BACK), self.testColourAlpha) + + self.RestoreCaretLine() + + def testCaretLineLayerDiscouraged(self): + # Check old discouraged APIs + # This is s bit tricky as there is no clean mapping: parts of the old state are distributed to + # sometimes-multiple parts of the new state. + backColour = 0x102030 + backColourOpaque = backColour | self.opaque + self.assertEquals(self.ed.CaretLineVisible, 0) + self.ed.CaretLineVisible = 1 + self.assertTrue(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_CARET_LINE_BACK)) + self.assertEquals(self.ed.CaretLineVisible, 1) + self.ed.CaretLineBack = backColour + self.assertEquals(self.ed.CaretLineBack, backColour) + # Check with newer API + self.assertTrue(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_CARET_LINE_BACK)) + self.assertEquals(self.ElementColour(self.ed.SC_ELEMENT_CARET_LINE_BACK), backColourOpaque) + self.assertEquals(self.ed.CaretLineLayer, 0) + + alpha = 0x7f + self.ed.CaretLineBackAlpha = alpha + self.assertEquals(self.ed.CaretLineBackAlpha, alpha) + backColourTranslucent = backColour | (alpha << 24) + self.assertEquals(self.ElementColour(self.ed.SC_ELEMENT_CARET_LINE_BACK), backColourTranslucent) + self.assertEquals(self.ed.CaretLineLayer, 10) + + self.ed.CaretLineBackAlpha = 0x100 + self.assertEquals(self.ed.CaretLineBackAlpha, 0x100) + self.assertEquals(self.ed.CaretLineLayer, 0) # SC_ALPHA_NOALPHA moved to base layer + + self.RestoreCaretLine() + + # Try other orders + + self.ed.CaretLineBackAlpha = 0x100 + self.assertEquals(self.ed.CaretLineBackAlpha, 0x100) + self.assertEquals(self.ed.CaretLineLayer, 0) # SC_ALPHA_NOALPHA moved to base layer + self.assertTrue(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_CARET_LINE_BACK)) + self.ed.CaretLineVisible = 0 + self.assertFalse(self.ed.GetElementIsSet(self.ed.SC_ELEMENT_CARET_LINE_BACK)) + + self.RestoreCaretLine() class TestIndices(unittest.TestCase): def setUp(self): |