diff options
author | Neil <nyamatongwe@gmail.com> | 2021-05-10 17:40:27 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2021-05-10 17:40:27 +1000 |
commit | 8497317864816c0f7a4b5baf3229c7a3336f55d8 (patch) | |
tree | e0ddd75f8457358ed89d73d86fb00e770eaf9d05 /src | |
parent | e44364e1f30eb482cbf1502d6345a8d146c9be42 (diff) | |
download | scintilla-mirror-8497317864816c0f7a4b5baf3229c7a3336f55d8.tar.gz |
Change the way that selections and carets are drawn to use the element APIs.
Diffstat (limited to 'src')
-rw-r--r-- | src/EditView.cxx | 238 | ||||
-rw-r--r-- | src/Editor.cxx | 60 | ||||
-rw-r--r-- | src/ViewStyle.cxx | 42 | ||||
-rw-r--r-- | src/ViewStyle.h | 21 |
4 files changed, 195 insertions, 166 deletions
diff --git a/src/EditView.cxx b/src/EditView.cxx index 2d32c8997..5549e73db 100644 --- a/src/EditView.cxx +++ b/src/EditView.cxx @@ -826,42 +826,46 @@ namespace { constexpr ColourAlpha bugColour = ColourAlpha(0xff, 0, 0xff, 0xf0); -ColourAlpha SelectionBackground(const EditModel &model, const ViewStyle &vsDraw, InSelection inSelection) noexcept { +// Selection background colours are always defined, the value_or is to show if bug + +ColourAlpha SelectionBackground(const EditModel &model, const ViewStyle &vsDraw, InSelection inSelection) { if (inSelection == InSelection::inNone) return bugColour; // Not selected is a bug - if (!vsDraw.selection.colours.back) - return bugColour; // Not set -> bug - + int element = SC_ELEMENT_SELECTION_BACK; + if (inSelection == InSelection::inAdditional) + element = SC_ELEMENT_SELECTION_ADDITIONAL_BACK; if (!model.primarySelection) - return vsDraw.selection.background2; // Secondary selection - - if (inSelection == InSelection::inMain) - return *vsDraw.selection.colours.back; // Main selection - - return vsDraw.selection.additionalBackground; // Additional selection + element = SC_ELEMENT_SELECTION_SECONDARY_BACK; + if (!model.hasFocus && vsDraw.ElementColour(SC_ELEMENT_SELECTION_NO_FOCUS_BACK)) + element = SC_ELEMENT_SELECTION_NO_FOCUS_BACK; + return vsDraw.ElementColour(element).value_or(bugColour); } -std::optional<ColourAlpha> SelectionForeground(const ViewStyle &vsDraw, InSelection inSelection) noexcept { +std::optional<ColourAlpha> SelectionForeground(const EditModel &model, const ViewStyle &vsDraw, InSelection inSelection) { if (inSelection == InSelection::inNone) return {}; - if (inSelection == InSelection::inMain) - return vsDraw.selection.colours.fore; - if (!vsDraw.selection.colours.fore) // Main not set means don't use additional either - return {}; - return vsDraw.selection.additionalForeground; + int element = SC_ELEMENT_SELECTION_TEXT; + if (inSelection == InSelection::inAdditional) + element = SC_ELEMENT_SELECTION_ADDITIONAL_TEXT; + if (!model.primarySelection) // Secondary selection + element = SC_ELEMENT_SELECTION_SECONDARY_TEXT; + if (!model.hasFocus) { + if (vsDraw.ElementColour(SC_ELEMENT_SELECTION_NO_FOCUS_TEXT)) { + element = SC_ELEMENT_SELECTION_NO_FOCUS_TEXT; + } else { + return {}; + } + } + return vsDraw.ElementColour(element); } } static ColourAlpha TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - std::optional<ColourAlpha> background, InSelection inSelection, bool inHotspot, int styleMain, Sci::Position i) noexcept { - if (inSelection && vsDraw.selection.colours.back) { - if ((inSelection == InSelection::inMain) && (vsDraw.selection.alpha == SC_ALPHA_NOALPHA)) { - return SelectionBackground(model, vsDraw, inSelection); - } else if ((inSelection == InSelection::inAdditional) && (vsDraw.selection.additionalAlpha == SC_ALPHA_NOALPHA)) { - return SelectionBackground(model, vsDraw, inSelection); - } + std::optional<ColourAlpha> background, InSelection inSelection, bool inHotspot, int styleMain, Sci::Position i) { + if (inSelection && (vsDraw.selection.layer == Layer::base)) { + return SelectionBackground(model, vsDraw, inSelection).Opaque(); } if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll->edgeColumn) && @@ -968,34 +972,30 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle rcSegment.right = xEol + xStart + virtualSpace; const ColourAlpha backgroundFill = background.value_or(vsDraw.styles[ll->styles[ll->numCharsInLine]].back); surface->FillRectangleAligned(rcSegment, backgroundFill); - if (!hideSelection && ((vsDraw.selection.alpha == SC_ALPHA_NOALPHA) || (vsDraw.selection.additionalAlpha == SC_ALPHA_NOALPHA))) { + if (!hideSelection && (vsDraw.selection.layer == Layer::base)) { const SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)), SelectionPosition(model.pdoc->LineEnd(line), model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)))); for (size_t r = 0; r<model.sel.Count(); r++) { - const int alpha = (r == model.sel.Main()) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; - if (alpha == SC_ALPHA_NOALPHA) { - const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); - if (!portion.Empty()) { - const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth; - rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; - rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; - surface->FillRectangleAligned(rcSegment, Fill(SelectionBackground(model, vsDraw, model.sel.RangeType(r)))); - } + const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth; + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + surface->FillRectangleAligned(rcSegment, Fill( + SelectionBackground(model, vsDraw, model.sel.RangeType(r)).Opaque())); } } } } InSelection eolInSelection = InSelection::inNone; - int alpha = SC_ALPHA_NOALPHA; if (!hideSelection && lastSubLine) { eolInSelection = model.LineEndInSelection(line); - alpha = (eolInSelection == InSelection::inMain) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; } const ColourAlpha selectionBack = SelectionBackground(model, vsDraw, eolInSelection); @@ -1024,11 +1024,11 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle ctrlChar = hexits; } } - const std::optional<ColourAlpha> selectionFore = SelectionForeground(vsDraw, eolInSelection); + const std::optional<ColourAlpha> selectionFore = SelectionForeground(model, vsDraw, eolInSelection); const ColourAlpha textFore = selectionFore.value_or(vsDraw.styles[styleMain].fore); - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1)) { - if (alpha == SC_ALPHA_NOALPHA) { - surface->FillRectangleAligned(rcSegment, Fill(selectionBack)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1)) { + if (vsDraw.selection.layer == Layer::base) { + surface->FillRectangleAligned(rcSegment, Fill(selectionBack.Opaque())); } else { surface->FillRectangleAligned(rcSegment, Fill(textBack)); } @@ -1036,8 +1036,8 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle surface->FillRectangleAligned(rcSegment, Fill(textBack)); } DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == PhasesDraw::one); - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcSegment, ColourAlpha(selectionBack, alpha)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcSegment, selectionBack); } } } @@ -1046,8 +1046,8 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcSegment, Fill(selectionBack)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::base)) { + surface->FillRectangleAligned(rcSegment, Fill(selectionBack.Opaque())); } else { if (background) { surface->FillRectangleAligned(rcSegment, Fill(*background)); @@ -1058,8 +1058,8 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle } else { surface->FillRectangleAligned(rcSegment, Fill(vsDraw.styles[STYLE_DEFAULT].back)); } - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcSegment, ColourAlpha(selectionBack, alpha)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcSegment, selectionBack); } } @@ -1227,10 +1227,8 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con const int widthFoldDisplayText = static_cast<int>(surface->WidthText(fontText, foldDisplayText)); InSelection eolInSelection = InSelection::inNone; - int alpha = SC_ALPHA_NOALPHA; if (!hideSelection) { eolInSelection = model.LineEndInSelection(line); - alpha = (eolInSelection == InSelection::inMain) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; } const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; @@ -1240,7 +1238,7 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con rcSegment.right = rcSegment.left + static_cast<XYPOSITION>(widthFoldDisplayText); const std::optional<ColourAlpha> background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); - const std::optional<ColourAlpha> selectionFore = SelectionForeground(vsDraw, eolInSelection); + const std::optional<ColourAlpha> selectionFore = SelectionForeground(model, vsDraw, eolInSelection); const ColourAlpha textFore = selectionFore.value_or(vsDraw.styles[STYLE_FOLDDISPLAYTEXT].fore); const ColourAlpha textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, STYLE_FOLDDISPLAYTEXT, -1); @@ -1286,8 +1284,8 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con } if (FlagSet(phase, DrawPhase::selectionTranslucent)) { - if (eolInSelection && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && alpha != SC_ALPHA_NOALPHA) { - surface->FillRectangleAligned(rcSegment, ColourAlpha(SelectionBackground(model, vsDraw, eolInSelection), alpha)); + if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcSegment, SelectionBackground(model, vsDraw, eolInSelection)); } } } @@ -1644,8 +1642,11 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt rcCaret.left = std::round(xposCaret - caretWidthOffset); rcCaret.right = rcCaret.left + vsDraw.caret.width; } - const ColourAlpha caretColour = mainCaret ? vsDraw.caret.colour : vsDraw.caret.additionalColour; - assert(caretColour.IsOpaque()); + int elementCaret = mainCaret ? SC_ELEMENT_CARET : SC_ELEMENT_CARET_ADDITIONAL; + if (!model.primarySelection) + elementCaret = SC_ELEMENT_CARET_SECONDARY; + const ColourAlpha caretColour = *vsDraw.ElementColour(elementCaret); + //assert(caretColour.IsOpaque()); if (drawBlockCaret) { DrawBlockCaret(surface, model, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); } else { @@ -1808,7 +1809,7 @@ static void DrawMarkUnderline(Surface *surface, const EditModel &model, const Vi static void DrawTranslucentSelection(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcLine, int subLine, Range lineRange, int xStart, int tabWidthMinimumPixels) { - if ((vsDraw.selection.alpha != SC_ALPHA_NOALPHA) || (vsDraw.selection.additionalAlpha != SC_ALPHA_NOALPHA)) { + if (vsDraw.selection.layer == Layer::over) { const Sci::Position posLineStart = model.pdoc->LineStart(line); const XYACCUMULATOR subLineStart = ll->positions[lineRange.start]; // For each selection draw @@ -1820,51 +1821,48 @@ static void DrawTranslucentSelection(Surface *surface, const EditModel &model, c const SelectionPosition posEnd(posLineStart + lineRange.end, virtualSpaces); const SelectionSegment virtualSpaceRange(posStart, posEnd); for (size_t r = 0; r < model.sel.Count(); r++) { - const int alpha = (r == model.sel.Main()) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; - if (alpha != SC_ALPHA_NOALPHA) { - const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); - if (!portion.Empty()) { - const ColourAlpha selectionBack = ColourAlpha( - SelectionBackground(model, vsDraw, model.sel.RangeType(r)), alpha); - const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - if (model.BidirectionalEnabled()) { - const int selectionStart = static_cast<int>(portion.start.Position() - posLineStart - lineRange.start); - const int selectionEnd = static_cast<int>(portion.end.Position() - posLineStart - lineRange.start); - - const ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right, tabWidthMinimumPixels); - std::unique_ptr<IScreenLineLayout> slLayout = surface->Layout(&screenLine); - - const std::vector<Interval> intervals = slLayout->FindRangeIntervals(selectionStart, selectionEnd); - for (const Interval &interval : intervals) { - const XYPOSITION rcRight = interval.right + xStart; - const XYPOSITION rcLeft = interval.left + xStart; - const PRectangle rcSelection(rcLeft, rcLine.top, rcRight, rcLine.bottom); - surface->FillRectangleAligned(rcSelection, selectionBack); - } + const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const ColourAlpha selectionBack = SelectionBackground( + model, vsDraw, model.sel.RangeType(r)); + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + if (model.BidirectionalEnabled()) { + const int selectionStart = static_cast<int>(portion.start.Position() - posLineStart - lineRange.start); + const int selectionEnd = static_cast<int>(portion.end.Position() - posLineStart - lineRange.start); + + const ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right, tabWidthMinimumPixels); + std::unique_ptr<IScreenLineLayout> slLayout = surface->Layout(&screenLine); + + const std::vector<Interval> intervals = slLayout->FindRangeIntervals(selectionStart, selectionEnd); + for (const Interval &interval : intervals) { + const XYPOSITION rcRight = interval.right + xStart; + const XYPOSITION rcLeft = interval.left + xStart; + const PRectangle rcSelection(rcLeft, rcLine.top, rcRight, rcLine.bottom); + surface->FillRectangleAligned(rcSelection, selectionBack); + } - if (portion.end.VirtualSpace()) { - const XYPOSITION xStartVirtual = ll->positions[lineRange.end] - - static_cast<XYPOSITION>(subLineStart) + xStart; - PRectangle rcSegment = rcLine; - rcSegment.left = xStartVirtual + portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStartVirtual + portion.end.VirtualSpace() * spaceWidth; - surface->FillRectangleAligned(rcSegment, selectionBack); - } - } else { + if (portion.end.VirtualSpace()) { + const XYPOSITION xStartVirtual = ll->positions[lineRange.end] - + static_cast<XYPOSITION>(subLineStart) + xStart; PRectangle rcSegment = rcLine; - rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart) + portion.start.VirtualSpace() * spaceWidth; - rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - - static_cast<XYPOSITION>(subLineStart) + portion.end.VirtualSpace() * spaceWidth; - if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { - if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) - rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here - } - rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; - rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; - if (rcSegment.right > rcLine.left) - surface->FillRectangleAligned(rcSegment, selectionBack); + rcSegment.left = xStartVirtual + portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStartVirtual + portion.end.VirtualSpace() * spaceWidth; + surface->FillRectangleAligned(rcSegment, selectionBack); } + } else { + PRectangle rcSegment = rcLine; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart) + portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart) + portion.end.VirtualSpace() * spaceWidth; + if ((ll->wrapIndent != 0) && (lineRange.start != 0)) { + if ((portion.start.Position() - posLineStart) == lineRange.start && model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1)) + rcSegment.left -= static_cast<int>(ll->wrapIndent); // indentation added to xStart was truncated to int, so we do the same here + } + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + if (rcSegment.right > rcLine.left) + surface->FillRectangleAligned(rcSegment, selectionBack); } } } @@ -1972,7 +1970,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi } } const InSelection inSelection = hideSelection ? InSelection::inNone : model.sel.CharacterInSelection(iDoc); - const std::optional<ColourAlpha> selectionFore = SelectionForeground(vsDraw, inSelection); + const std::optional<ColourAlpha> selectionFore = SelectionForeground(model, vsDraw, inSelection); if (selectionFore) { textFore = *selectionFore; } @@ -2461,28 +2459,26 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, PRectan void EditView::FillLineRemainder(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, Sci::Line line, PRectangle rcArea, int subLine) const { InSelection eolInSelection = InSelection::inNone; - int alpha = SC_ALPHA_NOALPHA; - if ((!hideSelection) && (subLine == (ll->lines - 1))) { - eolInSelection = model.LineEndInSelection(line); - alpha = (eolInSelection == InSelection::inMain) ? vsDraw.selection.alpha : vsDraw.selection.additionalAlpha; - } + if ((!hideSelection) && (subLine == (ll->lines - 1))) { + eolInSelection = model.LineEndInSelection(line); + } - const std::optional<ColourAlpha> background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); + const std::optional<ColourAlpha> background = vsDraw.Background(model.pdoc->GetMark(line), model.caret.active, ll->containsCaret); - if (eolInSelection && vsDraw.selection.eolFilled && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcArea, Fill(SelectionBackground(model, vsDraw, eolInSelection))); + if (eolInSelection && vsDraw.selection.eolFilled && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::base)) { + surface->FillRectangleAligned(rcArea, Fill(SelectionBackground(model, vsDraw, eolInSelection).Opaque())); + } else { + if (background) { + surface->FillRectangleAligned(rcArea, Fill(*background)); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[ll->styles[ll->numCharsInLine]].back)); } else { - if (background) { - surface->FillRectangleAligned(rcArea, Fill(*background)); - } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { - surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[ll->styles[ll->numCharsInLine]].back)); - } else { - surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[STYLE_DEFAULT].back)); - } - if (eolInSelection && vsDraw.selection.eolFilled && vsDraw.selection.colours.back && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { - surface->FillRectangleAligned(rcArea, ColourAlpha(SelectionBackground(model, vsDraw, eolInSelection), alpha)); - } + surface->FillRectangleAligned(rcArea, Fill(vsDraw.styles[STYLE_DEFAULT].back)); } + if (eolInSelection && vsDraw.selection.eolFilled && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::over)) { + surface->FillRectangleAligned(rcArea, SelectionBackground(model, vsDraw, eolInSelection)); + } + } } // Space (3 space characters) between line numbers and text when printing. @@ -2526,10 +2522,8 @@ Sci::Position EditView::FormatRange(bool draw, const Sci_RangeToFormat *pfr, Sur // If this ever gets changed, cached pixmap would need to be recreated if technology != SC_TECHNOLOGY_DEFAULT vsPrint.viewIndentationGuides = IndentView::none; // Don't show the selection when printing - vsPrint.selection.colours.back.reset(); - vsPrint.selection.colours.fore.reset(); - vsPrint.selection.alpha = SC_ALPHA_NOALPHA; - vsPrint.selection.additionalAlpha = SC_ALPHA_NOALPHA; + vsPrint.elementColours.clear(); + vsPrint.elementBaseColours.clear(); vsPrint.whitespaceColours.back.reset(); vsPrint.whitespaceColours.fore.reset(); vsPrint.caretLine.show = false; diff --git a/src/Editor.cxx b/src/Editor.cxx index 477173c6b..e6a31f11a 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -7417,25 +7417,38 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return LinesOnScreen(); case SCI_SETSELFORE: - vs.selection.colours.fore = OptionalColour(wParam, lParam); - vs.selection.additionalForeground = ColourAlpha::FromRGB(static_cast<int>(lParam)); + vs.elementColours[SC_ELEMENT_SELECTION_TEXT] = OptionalColour(wParam, lParam); + vs.elementColours[SC_ELEMENT_SELECTION_ADDITIONAL_TEXT] = OptionalColour(wParam, lParam); InvalidateStyleRedraw(); break; case SCI_SETSELBACK: - vs.selection.colours.back = OptionalColour(wParam, lParam); - vs.selection.additionalBackground = ColourAlpha::FromRGB(static_cast<int>(lParam)); + if (wParam) { + vs.SetElementRGB(SC_ELEMENT_SELECTION_BACK, static_cast<int>(lParam)); + vs.SetElementRGB(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(lParam)); + } else { + vs.ResetElement(SC_ELEMENT_SELECTION_BACK); + vs.ResetElement(SC_ELEMENT_SELECTION_ADDITIONAL_BACK); + } InvalidateStyleRedraw(); break; - case SCI_SETSELALPHA: - vs.selection.alpha = static_cast<int>(wParam); - vs.selection.additionalAlpha = static_cast<int>(wParam); - InvalidateStyleRedraw(); + case SCI_SETSELALPHA: { + Layer layerNew = (wParam == SC_ALPHA_NOALPHA) ? Layer::base : Layer::over; + if (vs.selection.layer != layerNew) { + vs.selection.layer = layerNew; + UpdateBaseElements(); + } + vs.SetElementAlpha(SC_ELEMENT_SELECTION_BACK, static_cast<int>(wParam)); + vs.SetElementAlpha(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(wParam)); + InvalidateStyleRedraw(); + } break; case SCI_GETSELALPHA: - return vs.selection.alpha; + if (vs.selection.layer == Layer::base) + return SC_ALPHA_NOALPHA; + return vs.ElementColour(SC_ELEMENT_SELECTION_BACK)->GetAlpha(); case SCI_GETSELEOLFILLED: return vs.selection.eolFilled; @@ -7455,13 +7468,24 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { InvalidateStyleRedraw(); break; + case SCI_SETSELECTIONLAYER: + if (vs.selection.layer != static_cast<Layer>(wParam)) { + vs.selection.layer = static_cast<Layer>(wParam); + UpdateBaseElements(); + InvalidateStyleRedraw(); + } + break; + + case SCI_GETSELECTIONLAYER: + return static_cast<sptr_t>(vs.selection.layer); + case SCI_SETCARETFORE: - vs.caret.colour = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.elementColours[SC_ELEMENT_CARET] = ColourAlpha::FromRGB(static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_GETCARETFORE: - return vs.caret.colour.OpaqueRGB(); + return vs.ElementColour(SC_ELEMENT_CARET)->OpaqueRGB(); case SCI_SETCARETSTYLE: if (wParam <= (CARETSTYLE_BLOCK | CARETSTYLE_OVERSTRIKE_BLOCK | CARETSTYLE_BLOCK_AFTER)) @@ -8418,30 +8442,32 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return virtualSpaceOptions; case SCI_SETADDITIONALSELFORE: - vs.selection.additionalForeground = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.elementColours[SC_ELEMENT_SELECTION_ADDITIONAL_TEXT] = ColourAlpha::FromRGB(static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELBACK: - vs.selection.additionalBackground = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.SetElementRGB(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_SETADDITIONALSELALPHA: - vs.selection.additionalAlpha = static_cast<int>(wParam); + vs.SetElementAlpha(SC_ELEMENT_SELECTION_ADDITIONAL_BACK, static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_GETADDITIONALSELALPHA: - return vs.selection.additionalAlpha; + if (vs.selection.layer == Layer::base) + return SC_ALPHA_NOALPHA; + return vs.ElementColour(SC_ELEMENT_SELECTION_ADDITIONAL_BACK)->GetAlpha(); case SCI_SETADDITIONALCARETFORE: - vs.caret.additionalColour = ColourAlpha::FromRGB(static_cast<int>(wParam)); + vs.elementColours[SC_ELEMENT_CARET_ADDITIONAL] = ColourAlpha::FromRGB(static_cast<int>(wParam)); InvalidateStyleRedraw(); break; case SCI_GETADDITIONALCARETFORE: - return vs.caret.additionalColour.OpaqueRGB(); + return vs.ElementColour(SC_ELEMENT_CARET_ADDITIONAL)->OpaqueRGB(); case SCI_ROTATESELECTION: sel.RotateMain(); diff --git a/src/ViewStyle.cxx b/src/ViewStyle.cxx index 16701983e..ed08ad6ce 100644 --- a/src/ViewStyle.cxx +++ b/src/ViewStyle.cxx @@ -196,13 +196,17 @@ void ViewStyle::Init(size_t stylesSize_) { spaceWidth = 8; tabWidth = spaceWidth * 8; - selection.colours.fore.reset(); - selection.colours.back = ColourAlpha(0xc0, 0xc0, 0xc0); - selection.additionalForeground = ColourAlpha(0xff, 0, 0); - selection.additionalBackground = ColourAlpha(0xd7, 0xd7, 0xd7); - selection.background2 = ColourAlpha(0xb0, 0xb0, 0xb0); - selection.alpha = SC_ALPHA_NOALPHA; - selection.additionalAlpha = SC_ALPHA_NOALPHA; + // Default is for no selection foregrounds + elementColours.erase(SC_ELEMENT_SELECTION_TEXT); + elementColours.erase(SC_ELEMENT_SELECTION_ADDITIONAL_TEXT); + elementColours.erase(SC_ELEMENT_SELECTION_SECONDARY_TEXT); + elementColours.erase(SC_ELEMENT_SELECTION_NO_FOCUS_TEXT); + // Shades of grey for selection backgrounds + elementBaseColours[SC_ELEMENT_SELECTION_BACK] = ColourAlpha(0xc0, 0xc0, 0xc0, 0xff); + elementBaseColours[SC_ELEMENT_SELECTION_ADDITIONAL_BACK] = ColourAlpha(0xd7, 0xd7, 0xd7, 0xff); + elementBaseColours[SC_ELEMENT_SELECTION_SECONDARY_BACK] = ColourAlpha(0xb0, 0xb0, 0xb0, 0xff); + elementBaseColours[SC_ELEMENT_SELECTION_NO_FOCUS_BACK] = ColourAlpha(0x80, 0x80, 0x80, 0x3f); + selection.layer = Layer::base; selection.eolFilled = false; foldmarginColour.reset(); @@ -217,8 +221,9 @@ void ViewStyle::Init(size_t stylesSize_) { styles[STYLE_LINENUMBER].fore = ColourAlpha(0, 0, 0); styles[STYLE_LINENUMBER].back = Platform::Chrome(); - caret.colour = ColourAlpha(0, 0, 0); - caret.additionalColour = ColourAlpha(0x7f, 0x7f, 0x7f); + elementBaseColours[SC_ELEMENT_CARET] = ColourAlpha(0, 0, 0); + elementBaseColours[SC_ELEMENT_CARET_ADDITIONAL] = ColourAlpha(0x7f, 0x7f, 0x7f); + elementBaseColours[SC_ELEMENT_CARET_SECONDARY] = ColourAlpha(0, 0, 0, 0x40); caret.style = CARETSTYLE_LINE; caret.width = 1; @@ -483,12 +488,15 @@ std::optional<ColourAlpha> ViewStyle::Background(int marksOfLine, bool caretActi } bool ViewStyle::SelectionBackgroundDrawn() const noexcept { - return selection.colours.back && - ((selection.alpha == SC_ALPHA_NOALPHA) || (selection.additionalAlpha == SC_ALPHA_NOALPHA)); + return selection.layer == Layer::base; } bool ViewStyle::SelectionTextDrawn() const { - return selection.colours.fore.has_value(); + return + ElementIsSet(SC_ELEMENT_SELECTION_TEXT) || + ElementIsSet(SC_ELEMENT_SELECTION_ADDITIONAL_TEXT) || + ElementIsSet(SC_ELEMENT_SELECTION_SECONDARY_TEXT) || + ElementIsSet(SC_ELEMENT_SELECTION_NO_FOCUS_TEXT); } bool ViewStyle::WhitespaceBackgroundDrawn() const noexcept { @@ -540,6 +548,16 @@ void ViewStyle::ResetElement(int element) { elementColours.erase(element); } +void ViewStyle::SetElementRGB(int element, int rgb) { + const ColourAlpha current = ElementColour(element).value_or(ColourAlpha(0, 0, 0, 0)); + elementColours[element] = ColourAlpha(ColourAlpha(rgb), current.GetAlpha()); +} + +void ViewStyle::SetElementAlpha(int element, int alpha) { + const ColourAlpha current = ElementColour(element).value_or(ColourAlpha(0, 0, 0, 0)); + elementColours[element] = ColourAlpha(current, std::min(alpha, 0xff)); +} + bool ViewStyle::ElementIsSet(int element) const { ElementMap::const_iterator search = elementColours.find(element); if (search != elementColours.end()) { diff --git a/src/ViewStyle.h b/src/ViewStyle.h index a9fe58131..6aab53f64 100644 --- a/src/ViewStyle.h +++ b/src/ViewStyle.h @@ -63,18 +63,11 @@ struct ForeBackColours { std::optional<ColourAlpha> back; }; +enum class Layer { base=0, over=10 }; + struct SelectionAppearance { - // Colours of main selection - ForeBackColours colours; - // Colours of additional (non-main) selections - ColourAlpha additionalForeground; - ColourAlpha additionalBackground; - // Background colour on X when not primary selection - ColourAlpha background2; - // Translucency. SC_ALPHA_NOALPHA: draw selection background beneath text - int alpha; - // Translucency of additional selections - int additionalAlpha; + // Whether to draw on base layer or over text + Layer layer; // Draw selection past line end characters up to right border bool eolFilled; }; @@ -93,10 +86,6 @@ struct CaretLineAppearance { }; struct CaretAppearance { - // Colour of caret - ColourAlpha colour; - // Colour of additional (non-main) carets - ColourAlpha additionalColour; // Line, block, over-strike bar ... int style; // Width in pixels @@ -245,6 +234,8 @@ public: std::optional<ColourAlpha> ElementColour(int element) const; bool ElementAllowsTranslucent(int element) const; void ResetElement(int element); + void SetElementRGB(int element, int rgb); + void SetElementAlpha(int element, int alpha); bool ElementIsSet(int element) const; bool SetElementBase(int element, ColourAlpha colour); |