diff options
Diffstat (limited to 'src/EditView.cxx')
| -rw-r--r-- | src/EditView.cxx | 417 |
1 files changed, 200 insertions, 217 deletions
diff --git a/src/EditView.cxx b/src/EditView.cxx index 3bf0a1fbb..bec07fe95 100644 --- a/src/EditView.cxx +++ b/src/EditView.cxx @@ -17,6 +17,7 @@ #include <string> #include <string_view> #include <vector> +#include <array> #include <map> #include <set> #include <forward_list> @@ -124,8 +125,7 @@ int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, cons const std::string_view text(st.text + start, lenLine); widthSubLine = static_cast<int>(surface->WidthText(fontText, text)); } - if (widthSubLine > widthMax) - widthMax = widthSubLine; + widthMax = std::max(widthMax, widthSubLine); start += lenLine + 1; } return widthMax; @@ -191,7 +191,7 @@ EditView::EditView() { imeCaretBlockOverride = false; llc.SetLevel(LineCache::Caret); posCache = CreatePositionCache(); - posCache->SetSize(0x400); + posCache->SetSize(positionCacheDefaultSize); maxLayoutThreads = 1; tabArrowHeight = 4; customDrawTabArrow = nullptr; @@ -251,9 +251,8 @@ bool EditView::AddTabstop(Sci::Line line, int x) { int EditView::GetNextTabstop(Sci::Line line, int x) const noexcept { if (ldTabstops) { return ldTabstops->GetNextTabstop(line, x); - } else { - return 0; } + return 0; } void EditView::LinesAddedOrRemoved(Sci::Line lineOfPos, Sci::Line linesAdded) { @@ -353,14 +352,14 @@ void LayoutSegments(IPositionCache *pCache, XYPOSITION representationWidth = 0.0; // Tab is a special case of representation, taking a variable amount of space // which will be filled in later. - if (ll->chars[ts.start] != '\t') { + if (ll->chars[ts.start] != '\t' || vstyle.tabDrawMode == TabDrawMode::ControlChar) { representationWidth = vstyle.controlCharWidth; if (representationWidth <= 0.0) { assert(ts.representation->stringRep.length() <= Representation::maxLength); - XYPOSITION positionsRepr[Representation::maxLength + 1]; + std::array<XYPOSITION, Representation::maxLength + 1> positionsRepr; // ts.representation->stringRep is UTF-8. pCache->MeasureWidths(surface, vstyle, StyleControlChar, true, ts.representation->stringRep, - positionsRepr, multiThreaded); + positionsRepr.data(), multiThreaded); representationWidth = positionsRepr[ts.representation->stringRep.length() - 1]; if (FlagSet(ts.representation->appearance, RepresentationAppearance::Blob)) { representationWidth += vstyle.ctrlCharPadding; @@ -379,9 +378,9 @@ void LayoutSegments(IPositionCache *pCache, } } else if (vstyle.styles[styleSegment].invisibleRepresentation[0]) { const std::string_view text = vstyle.styles[styleSegment].invisibleRepresentation; - XYPOSITION positionsRepr[Representation::maxLength + 1]; + std::array<XYPOSITION, Representation::maxLength + 1> positionsRepr; // invisibleRepresentation is UTF-8. - pCache->MeasureWidths(surface, vstyle, styleSegment, true, text, positionsRepr, multiThreaded); + pCache->MeasureWidths(surface, vstyle, styleSegment, true, text, positionsRepr.data(), multiThreaded); const XYPOSITION representationWidth = positionsRepr[text.length() - 1]; std::fill(positions, positions + ts.length, representationWidth); } @@ -402,13 +401,10 @@ void EditView::LayoutLine(const EditModel &model, Surface *surface, const ViewSt PLATFORM_ASSERT(line < model.pdoc->LinesTotal()); PLATFORM_ASSERT(ll->chars); const Sci::Position posLineStart = model.pdoc->LineStart(line); - Sci::Position posLineEnd = model.pdoc->LineStart(line + 1); - // If the line is very long, limit the treatment to a length that should fit in the viewport - if (posLineEnd >(posLineStart + ll->maxLineLength)) { - posLineEnd = posLineStart + ll->maxLineLength; - } + const Sci::Position posLineEnd = std::min(model.pdoc->LineStart(line + 1), posLineStart + ll->maxLineLength); // Hard to cope when too narrow, so just assume there is space - width = std::max(width, 20); + constexpr int minimumWidth = 20; + width = std::max(width, minimumWidth); if (ll->validity == LineLayout::ValidLevel::checkTextAndStyle) { Sci::Position lineLength = posLineEnd - posLineStart; @@ -526,7 +522,7 @@ void EditView::LayoutLine(const EditModel &model, Surface *surface, const ViewSt for (const TextSegment &ts : segments) { if (vstyle.styles[ll->styles[ts.start]].visible && ts.representation && - (ll->chars[ts.start] == '\t')) { + ll->chars[ts.start] == '\t' && vstyle.tabDrawMode != TabDrawMode::ControlChar) { // Simple visible tab, go to next tab stop const XYPOSITION startTab = ll->positions[ts.start]; const XYPOSITION nextTab = NextTabstopPos(line, startTab, vstyle.tabWidth); @@ -614,7 +610,7 @@ void EditView::UpdateBidiData(const EditModel &model, const ViewStyle &vstyle, L const Representation *repr = model.reprs->RepresentationFromCharacter(std::string_view(&ll->chars[charsInLine], charWidth)); ll->bidiData->widthReprs[charsInLine] = 0.0f; - if (repr && ll->chars[charsInLine] != '\t') { + if (repr && (ll->chars[charsInLine] != '\t' || vstyle.tabDrawMode == TabDrawMode::ControlChar)) { ll->bidiData->widthReprs[charsInLine] = ll->positions[charsInLine + charWidth] - ll->positions[charsInLine]; } if (charWidth > 1) { @@ -745,7 +741,8 @@ SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditMo const int spaceOffset = static_cast<int>( (pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); - } else if (canReturnInvalid) { + } + if (canReturnInvalid) { if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) { return SelectionPosition(model.pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1)); } @@ -892,11 +889,11 @@ ColourRGBA TextBackground(const EditModel &model, const ViewStyle &vsDraw, const } if (background && (styleMain != StyleBraceLight) && (styleMain != StyleBraceBad)) { return *background; - } else { - return vsDraw.styles[styleMain].back; } + return vsDraw.styles[styleMain].back; } +// Draw inverted text in a filled rectangle but omit the 4 corner pixels so appears rounded. void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, std::string_view text, ColourRGBA textBack, ColourRGBA textFore, bool fillBackground) { if (rcSegment.Empty()) @@ -910,42 +907,95 @@ void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegmen rcCChar.left = rcCChar.left + 1; rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; - PRectangle rcCentral = rcCChar; - rcCentral.top++; - rcCentral.bottom--; + + // Ensure pixels to left and right coloured for central part avoiding top and bottom + // pixels which will be drawn by DrawTextClippedUTF8. + const PRectangle rcCentral = rcCChar.Inset(Point(0, 1)); surface->FillRectangleAligned(rcCentral, Fill(textFore)); - PRectangle rcChar = rcCChar; - rcChar.left++; - rcChar.right--; + + const PRectangle rcChar = rcCChar.Inset(Point(1, 0)); + // NOLINTNEXTLINE(readability-suspicious-call-argument) Inverted text surface->DrawTextClippedUTF8(rcChar, ctrlCharsFont, rcSegment.top + vsDraw.maxAscent, text, textBack, textFore); } void FillLineRemainder(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - Sci::Line line, PRectangle rcArea, int subLine) { + Sci::Line line, PRectangle rcLine, XYPOSITION left, int subLine) { + if (rcLine.Empty()) { + return; + } InSelection eolInSelection = InSelection::inNone; if (vsDraw.selection.visible && (subLine == (ll->lines - 1))) { eolInSelection = model.LineEndInSelection(line); } + const bool drawEOLSelection = eolInSelection && vsDraw.selection.eolFilled && (line < model.pdoc->LinesTotal() - 1); - if (eolInSelection && vsDraw.selection.eolFilled && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer == Layer::Base)) { - surface->FillRectangleAligned(rcArea, Fill(SelectionBackground(model, vsDraw, eolInSelection).Opaque())); + const PRectangle rcArea = Clamp(rcLine, Edge::left, left); // Limit to right side of line from 'left' + + const ColourRGBA selectionBack = drawEOLSelection ? SelectionBackground(model, vsDraw, eolInSelection) : ColourRGBA{}; + ColourRGBA base = vsDraw.styles[StyleDefault].back; + if (drawEOLSelection && (vsDraw.selection.layer == Layer::Base)) { + base = selectionBack; } else { const ColourOptional background = vsDraw.Background(model.GetMark(line), model.caret.active, ll->containsCaret); 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[StyleDefault].back)); + base = *background; + } else if (vsDraw.styles[ll->LastStyle()].eolFilled) { + base = vsDraw.styles[ll->LastStyle()].back; } - if (eolInSelection && vsDraw.selection.eolFilled && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer != Layer::Base)) { - surface->FillRectangleAligned(rcArea, SelectionBackground(model, vsDraw, eolInSelection)); + } + surface->FillRectangleAligned(rcArea, Fill(base.Opaque())); + if (drawEOLSelection && (vsDraw.selection.layer != Layer::Base)) { + // This may be translucent + surface->FillRectangleAligned(rcArea, selectionBack); + } +} + +// Stadium ends require different amounts of padding to look reasonable around text. +constexpr XYPOSITION divisorAngle = 2.0; // <text> +constexpr XYPOSITION divisorCircle = 3.0; // (text) +constexpr XYPOSITION EndPadding(Surface::Ends side, XYPOSITION height) noexcept { + switch (side) { + case Surface::Ends::leftFlat: + case Surface::Ends::rightFlat: + return 1; + case Surface::Ends::leftAngle: + case Surface::Ends::rightAngle: + return height / divisorAngle; + default: + // semiCircles + return height / divisorCircle; + } +} + +struct HorizontalPadding { + XYPOSITION left = 0; + XYPOSITION right = 0; +}; + +[[nodiscard]] constexpr PRectangle TextPart(const PRectangle &rc, const HorizontalPadding &padding) noexcept { + return PRectangle(rc.left + padding.left, rc.top, rc.right - padding.right, rc.bottom); +} + +HorizontalPadding StadiumPadding(Scintilla::EOLAnnotationVisible eolAnnotationVisible, XYPOSITION height) noexcept { + if (eolAnnotationVisible >= EOLAnnotationVisible::Boxed) { + if (eolAnnotationVisible == EOLAnnotationVisible::Boxed) { + return { 1, 1 }; } + const Surface::Ends leftSide = static_cast<Surface::Ends>(static_cast<int>(eolAnnotationVisible) & 0xf); + const Surface::Ends rightSide = static_cast<Surface::Ends>(static_cast<int>(eolAnnotationVisible) & 0xf0); + const XYPOSITION leftSpace = EndPadding(leftSide, height); + const XYPOSITION rightSpace = EndPadding(rightSide, height); + return { leftSpace , rightSpace }; } + return {}; +} + } +void EditView::UpdateMaxWidth(XYPOSITION width) noexcept { + lineWidthMaxSeen = std::max(lineWidthMaxSeen, static_cast<int>(width)); } void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, @@ -955,27 +1005,23 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle PRectangle rcSegment = rcLine; const bool lastSubLine = subLine == (ll->lines - 1); - XYPOSITION virtualSpace = 0; - if (lastSubLine) { - const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - virtualSpace = static_cast<XYPOSITION>(model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line))) * spaceWidth; - } + const Sci::Position virtualSpaces = lastSubLine ? model.VirtualSpaceForLine(line) : 0; + const XYPOSITION spaceWidth = lastSubLine ? vsDraw.styles[ll->EndLineStyle()].spaceWidth : 0; + const XYPOSITION virtualSpace = static_cast<XYPOSITION>(virtualSpaces) * spaceWidth; const XYPOSITION xEol = ll->positions[lineEnd] - subLineStart; // Fill the virtual space and show selections within it if (virtualSpace > 0.0f) { rcSegment.left = xEol + xStart; rcSegment.right = xEol + xStart + virtualSpace; - const ColourRGBA backgroundFill = background.value_or(vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + const ColourRGBA backgroundFill = background.value_or(vsDraw.styles[ll->LastStyle()].back); surface->FillRectangleAligned(rcSegment, backgroundFill); if (vsDraw.selection.visible && (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)))); + SelectionPosition(model.pdoc->LineEnd(line), virtualSpaces)); for (size_t r = 0; r<model.sel.Count(); 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] - subLineStart + portion.start.VirtualSpaceWidth(spaceWidth); rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - @@ -989,30 +1035,29 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle } } - InSelection eolInSelection = InSelection::inNone; - if (vsDraw.selection.visible && lastSubLine) { - eolInSelection = model.LineEndInSelection(line); - } + const InSelection eolInSelection = (vsDraw.selection.visible && lastSubLine) ? + model.LineEndInSelection(line) : InSelection::inNone; + const bool lastLine = line >= (model.pdoc->LinesTotal() - 1); + const bool drawEOLSelection = eolInSelection && !lastLine; const ColourRGBA selectionBack = SelectionBackground(model, vsDraw, eolInSelection); // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on XYPOSITION blobsWidth = 0; if (lastSubLine) { - for (Sci::Position eolPos = ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine;) { + for (int eolPos = ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine;) { const int styleMain = ll->styles[eolPos]; const ColourOptional selectionFore = SelectionForeground(model, vsDraw, eolInSelection); ColourRGBA textFore = selectionFore.value_or(vsDraw.styles[styleMain].fore); char hexits[4] = ""; std::string_view ctrlChar; - Sci::Position widthBytes = 1; RepresentationAppearance appearance = RepresentationAppearance::Blob; - const Representation *repr = model.reprs->RepresentationFromCharacter(std::string_view(&ll->chars[eolPos], ll->numCharsInLine - eolPos)); - if (repr) { - // Representation of whole text - widthBytes = ll->numCharsInLine - eolPos; - } else { - repr = model.reprs->RepresentationFromCharacter(std::string_view(&ll->chars[eolPos], 1)); + const std::string_view rest(&ll->chars[eolPos], ll->numCharsInLine - eolPos); + const Representation *repr = model.reprs->RepresentationFromCharacter(rest); + const int widthBytes = repr ? static_cast<int>(rest.length()) : 1; + if (!repr) { + // No representation of whole line end so try first byte. + repr = model.reprs->RepresentationFromCharacter(rest.substr(0, 1)); } if (repr) { ctrlChar = repr->stringRep; @@ -1021,7 +1066,7 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle textFore = repr->colour; } } else { - const unsigned char chEOL = ll->chars[eolPos]; + const unsigned char chEOL = rest.front(); if (UTF8IsAscii(chEOL)) { ctrlChar = ControlCharacterString(chEOL); } else { @@ -1030,69 +1075,54 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle } } - rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace; - rcSegment.right = xStart + ll->positions[eolPos + widthBytes] - subLineStart + virtualSpace; - blobsWidth += rcSegment.Width(); + const PRectangle rcBlob = rcLine.WithHorizontalBounds( + ll->Span(eolPos, eolPos + widthBytes).Offset(xStart - subLineStart + virtualSpace)); + blobsWidth += rcBlob.Width(); const ColourRGBA textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, styleMain, eolPos); - 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)); - } + if (drawEOLSelection && (vsDraw.selection.layer == Layer::Base)) { + surface->FillRectangleAligned(rcBlob, Fill(selectionBack.Opaque())); } else { - surface->FillRectangleAligned(rcSegment, Fill(textBack)); + surface->FillRectangleAligned(rcBlob, Fill(textBack)); } - const bool drawEOLSelection = eolInSelection && (line < model.pdoc->LinesTotal() - 1); ColourRGBA blobText = textBack; if (drawEOLSelection && (vsDraw.selection.layer == Layer::UnderText)) { - surface->FillRectangleAligned(rcSegment, selectionBack); + surface->FillRectangleAligned(rcBlob, selectionBack); blobText = textBack.MixedWith(selectionBack, selectionBack.GetAlphaComponent()); } if (FlagSet(appearance, RepresentationAppearance::Blob)) { - DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, blobText, textFore, phasesDraw == PhasesDraw::One); + DrawTextBlob(surface, vsDraw, rcBlob, ctrlChar, blobText, textFore, phasesDraw == PhasesDraw::One); } else { - surface->DrawTextTransparentUTF8(rcSegment, vsDraw.styles[StyleControlChar].font.get(), - rcSegment.top + vsDraw.maxAscent, ctrlChar, textFore); + surface->DrawTextTransparentUTF8(rcBlob, vsDraw.styles[StyleControlChar].font.get(), + rcBlob.top + vsDraw.maxAscent, ctrlChar, textFore); } if (drawEOLSelection && (vsDraw.selection.layer == Layer::OverText)) { - surface->FillRectangleAligned(rcSegment, selectionBack); + surface->FillRectangleAligned(rcBlob, selectionBack); } eolPos += widthBytes; } } // Draw the eol-is-selected rectangle - rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; - rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; - - 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)); - } else if (line < model.pdoc->LinesTotal() - 1) { - surface->FillRectangleAligned(rcSegment, Fill(vsDraw.styles[ll->styles[ll->numCharsInLine]].back)); - } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { - surface->FillRectangleAligned(rcSegment, Fill(vsDraw.styles[ll->styles[ll->numCharsInLine]].back)); - } else { - surface->FillRectangleAligned(rcSegment, Fill(vsDraw.styles[StyleDefault].back)); - } - if (eolInSelection && (line < model.pdoc->LinesTotal() - 1) && (vsDraw.selection.layer != Layer::Base)) { - surface->FillRectangleAligned(rcSegment, selectionBack); - } + const PRectangle rcEOLIsSelected = rcLine.WithHorizontalBounds( + Interval::FromLeftAndWidth(xEol + xStart + virtualSpace + blobsWidth, vsDraw.aveCharWidth)); + ColourRGBA base = vsDraw.styles[StyleDefault].back; + if (drawEOLSelection && (vsDraw.selection.layer == Layer::Base)) { + base = selectionBack; + } else if (background) { + base = *background; + } else if (const Style &styleLast = vsDraw.styles[ll->LastStyle()]; styleLast.eolFilled) { + base = styleLast.back; + } + surface->FillRectangleAligned(rcEOLIsSelected, Fill(base.Opaque())); + if (drawEOLSelection && (vsDraw.selection.layer != Layer::Base)) { + surface->FillRectangleAligned(rcEOLIsSelected, selectionBack); } - - rcSegment.left = rcSegment.right; - if (rcSegment.left < rcLine.left) - rcSegment.left = rcLine.left; - rcSegment.right = rcLine.right; const bool drawEOLAnnotationStyledText = (vsDraw.eolAnnotationVisible != EOLAnnotationVisible::Hidden) && model.pdoc->EOLAnnotationStyledText(line).text; const bool fillRemainder = (!lastSubLine || (!model.GetFoldDisplayText(line) && !drawEOLAnnotationStyledText)); if (fillRemainder) { // Fill the remainder of the line - FillLineRemainder(surface, model, vsDraw, ll, line, rcSegment, subLine); + FillLineRemainder(surface, model, vsDraw, ll, line, rcLine, rcEOLIsSelected.right, subLine); } bool drawWrapMarkEnd = false; @@ -1109,8 +1139,8 @@ void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle } if (drawWrapMarkEnd) { - PRectangle rcPlace = rcSegment; - const XYPOSITION maxLeft = rcPlace.right - vsDraw.aveCharWidth; + PRectangle rcPlace = rcLine; + const XYPOSITION maxLeft = rcLine.right - vsDraw.aveCharWidth; if (FlagSet(vsDraw.wrap.visualFlagsLocation, WrapVisualLocation::EndByText)) { rcPlace.left = std::min(xEol + xStart + virtualSpace, maxLeft); @@ -1149,8 +1179,7 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con } const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - const XYPOSITION virtualSpace = static_cast<XYPOSITION>(model.sel.VirtualSpaceFor( - model.pdoc->LineEnd(line))) * spaceWidth; + const XYPOSITION virtualSpace = static_cast<XYPOSITION>(model.VirtualSpaceForLine(line)) * spaceWidth; rcSegment.left = xStart + ll->positions[ll->numCharsInLine] - subLineStart + virtualSpace + vsDraw.aveCharWidth; rcSegment.right = rcSegment.left + static_cast<XYPOSITION>(widthFoldDisplayText); @@ -1161,22 +1190,15 @@ void EditView::DrawFoldDisplayText(Surface *surface, const EditModel &model, con false, StyleFoldDisplayText, -1); if (model.trackLineWidth) { - if (rcSegment.right + 1> lineWidthMaxSeen) { - // Fold display text border drawn on rcSegment.right with width 1 is the last visible object of the line - lineWidthMaxSeen = static_cast<int>(rcSegment.right + 1); - } + // Fold display text border drawn on rcSegment.right with width 1 is the last visible object of the line + UpdateMaxWidth(rcSegment.right + 1); } if (FlagSet(phase, DrawPhase::back)) { surface->FillRectangleAligned(rcSegment, Fill(textBack)); // Fill Remainder of the line - PRectangle rcRemainder = rcSegment; - rcRemainder.left = rcRemainder.right; - if (rcRemainder.left < rcLine.left) - rcRemainder.left = rcLine.left; - rcRemainder.right = rcLine.right; - FillLineRemainder(surface, model, vsDraw, ll, line, rcRemainder, subLine); + FillLineRemainder(surface, model, vsDraw, ll, line, rcLine, rcSegment.right, subLine); } if (FlagSet(phase, DrawPhase::text)) { @@ -1228,47 +1250,14 @@ void EditView::DrawEOLAnnotationText(Surface *surface, const EditModel &model, c const Font *fontText = vsDraw.styles[style].font.get(); const Surface::Ends ends = static_cast<Surface::Ends>(static_cast<int>(vsDraw.eolAnnotationVisible) & 0xff); - const Surface::Ends leftSide = static_cast<Surface::Ends>(static_cast<int>(ends) & 0xf); - const Surface::Ends rightSide = static_cast<Surface::Ends>(static_cast<int>(ends) & 0xf0); - - XYPOSITION leftBoxSpace = 0; - XYPOSITION rightBoxSpace = 0; - if (vsDraw.eolAnnotationVisible >= EOLAnnotationVisible::Boxed) { - leftBoxSpace = 1; - rightBoxSpace = 1; - if (vsDraw.eolAnnotationVisible != EOLAnnotationVisible::Boxed) { - switch (leftSide) { - case Surface::Ends::leftFlat: - leftBoxSpace = 1; - break; - case Surface::Ends::leftAngle: - leftBoxSpace = rcLine.Height() / 2.0; - break; - case Surface::Ends::semiCircles: - default: - leftBoxSpace = rcLine.Height() / 3.0; - break; - } - switch (rightSide) { - case Surface::Ends::rightFlat: - rightBoxSpace = 1; - break; - case Surface::Ends::rightAngle: - rightBoxSpace = rcLine.Height() / 2.0; - break; - case Surface::Ends::semiCircles: - default: - rightBoxSpace = rcLine.Height() / 3.0; - break; - } - } - } + + const HorizontalPadding padding = StadiumPadding(vsDraw.eolAnnotationVisible, rcLine.Height()); + const int widthEOLAnnotationText = static_cast<int>(surface->WidthTextUTF8(fontText, eolAnnotationText) + - leftBoxSpace + rightBoxSpace); + padding.left + padding.right); const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; - const XYPOSITION virtualSpace = static_cast<XYPOSITION>(model.sel.VirtualSpaceFor( - model.pdoc->LineEnd(line))) * spaceWidth; + const XYPOSITION virtualSpace = static_cast<XYPOSITION>(model.VirtualSpaceForLine(line)) * spaceWidth; rcSegment.left = xStart + ll->positions[ll->numCharsInLine] - subLineStart + virtualSpace + vsDraw.aveCharWidth; @@ -1288,10 +1277,8 @@ void EditView::DrawEOLAnnotationText(Surface *surface, const EditModel &model, c false, static_cast<int>(style), -1); if (model.trackLineWidth) { - if (rcSegment.right + 1> lineWidthMaxSeen) { - // EOL Annotation text border drawn on rcSegment.right with width 1 is the last visible object of the line - lineWidthMaxSeen = static_cast<int>(rcSegment.right + 1); - } + // EOL Annotation text border drawn on rcSegment.right with width 1 is the last visible object of the line + UpdateMaxWidth(rcSegment.right + 1); } if (FlagSet(phase, DrawPhase::back)) { @@ -1299,14 +1286,10 @@ void EditView::DrawEOLAnnotationText(Surface *surface, const EditModel &model, c // it may be double drawing. This is to allow stadiums with // curved or angled ends to have the area outside in the correct // background colour. - PRectangle rcRemainder = rcSegment; - rcRemainder.right = rcLine.right; - FillLineRemainder(surface, model, vsDraw, ll, line, rcRemainder, subLine); + FillLineRemainder(surface, model, vsDraw, ll, line, rcLine, rcSegment.right, subLine); } - PRectangle rcText = rcSegment; - rcText.left += leftBoxSpace; - rcText.right -= rightBoxSpace; + const PRectangle rcText = TextPart(rcSegment, padding); // For single phase drawing, draw the text then any box over it if (FlagSet(phase, DrawPhase::text)) { @@ -1369,7 +1352,7 @@ constexpr bool AnnotationBoxedOrIndented(AnnotationVisible annotationVisible) no } void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - Sci::Line line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { + Sci::Line line, int xOrigin, PRectangle rcLine, int subLine, DrawPhase phase) { const int indent = static_cast<int>(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth); PRectangle rcSegment = rcLine; const int annotationLine = subLine - ll->lines; @@ -1378,17 +1361,16 @@ void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const Vi if (FlagSet(phase, DrawPhase::back)) { surface->FillRectangleAligned(rcSegment, Fill(vsDraw.styles[0].back)); } - rcSegment.left = static_cast<XYPOSITION>(xStart); + rcSegment.left = static_cast<XYPOSITION>(xOrigin); if (model.trackLineWidth || AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { // Only care about calculating width if tracking or need to draw indented box int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); if (AnnotationBoxedOrIndented(vsDraw.annotationVisible)) { widthAnnotation += static_cast<int>(vsDraw.spaceWidth * 2); // Margins - rcSegment.left = static_cast<XYPOSITION>(xStart + indent); + rcSegment.left = static_cast<XYPOSITION>(xOrigin + indent); rcSegment.right = rcSegment.left + widthAnnotation; } - if (widthAnnotation > lineWidthMaxSeen) - lineWidthMaxSeen = widthAnnotation; + UpdateMaxWidth(widthAnnotation); } const int annotationLines = model.pdoc->AnnotationLines(line); size_t start = 0; @@ -1430,7 +1412,7 @@ void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const Vi namespace { void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - int subLine, int xStart, Sci::Position offset, Sci::Position posCaret, PRectangle rcCaret, ColourRGBA caretColour) { + int subLine, int xOrigin, Sci::Position offset, Sci::Position posCaret, PRectangle rcCaret, ColourRGBA caretColour) { const Sci::Position lineStart = ll->LineStart(subLine); Sci::Position posBefore = posCaret; @@ -1456,8 +1438,7 @@ void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &v // See if the next character shares horizontal space, if so we'll // need to draw that too. - if (offsetFirstChar < 0) - offsetFirstChar = 0; + offsetFirstChar = std::max<Sci::Position>(offsetFirstChar, 0); numCharsToDraw = offsetLastChar - offsetFirstChar; while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { // Update posAfter to point to the 2nd next char, this is where @@ -1475,8 +1456,8 @@ void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &v } // We now know what to draw, update the caret drawing rectangle - rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; - rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xStart; + rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xOrigin; + rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xOrigin; // Adjust caret position to take into account any word wrapping symbols. if ((ll->wrapIndent != 0) && (lineStart != 0)) { @@ -1498,7 +1479,7 @@ void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &v } void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - Sci::Line lineDoc, int xStart, PRectangle rcLine, int subLine) const { + Sci::Line lineDoc, int xOrigin, PRectangle rcLine, int subLine) const { // When drag is active it is the only caret drawn const bool drawDrag = model.posDrag.IsValid(); if (!vsDraw.selection.visible && !drawDrag) @@ -1545,7 +1526,6 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt bool canDrawBlockCaret = true; bool drawBlockCaret = false; XYPOSITION widthOverstrikeCaret; - XYPOSITION caretWidthOffset = 0; PRectangle rcCaret = rcLine; if (posCaret.Position() == model.pdoc->Length()) { // At end of document @@ -1558,12 +1538,15 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt const int widthChar = model.pdoc->LenChar(posCaret.Position()); widthOverstrikeCaret = ll->positions[offset + widthChar] - ll->positions[offset]; } - if (widthOverstrikeCaret < 3) // Make sure its visible - widthOverstrikeCaret = 3; + // Make sure block caret visible + constexpr XYPOSITION minimumBlockCaretWidth = 3.0f; + widthOverstrikeCaret = std::max(widthOverstrikeCaret, minimumBlockCaretWidth); - if (xposCaret > 0) - caretWidthOffset = 0.51f; // Move back so overlaps both character cells. - xposCaret += xStart; + // Move back slightly so line caret overlaps both character cells unless at start of text area. + constexpr XYPOSITION justOverHalf = 0.51f; + const XYPOSITION caretWidthOffset = (xposCaret > 0) ? justOverHalf : 0; + + xposCaret += xOrigin; const ViewStyle::CaretShape caretShape = drawDrag ? ViewStyle::CaretShape::line : vsDraw.CaretShapeForMode(model.inOverstrike, mainCaret); if (drawDrag) { @@ -1593,7 +1576,7 @@ void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewSt const ColourRGBA caretColour = vsDraw.ElementColourForced(elementCaret); //assert(caretColour.IsOpaque()); if (drawBlockCaret) { - DrawBlockCaret(surface, model, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); + DrawBlockCaret(surface, model, vsDraw, ll, subLine, xOrigin, offset, posCaret.Position(), rcCaret, caretColour); } else { surface->FillRectangleAligned(rcCaret, Fill(caretColour)); } @@ -1690,7 +1673,7 @@ void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &v ColourRGBA textBack = TextBackground(model, vsDraw, ll, background, inSelection, inHotspot, ll->styles[i], i); if (ts.representation) { - if (ll->chars[i] == '\t') { + if (ll->chars[i] == '\t' && vsDraw.tabDrawMode != TabDrawMode::ControlChar) { // Tab display if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation)) { textBack = vsDraw.ElementColourForced(Element::WhiteSpaceBack).Opaque(); @@ -1771,10 +1754,8 @@ void DrawTranslucentSelection(Surface *surface, const EditModel &model, const Vi const XYPOSITION subLineStart = ll->positions[lineRange.start]; const XYPOSITION horizontalOffset = xStart - subLineStart; // For each selection draw - Sci::Position virtualSpaces = 0; - if (subLine == (ll->lines - 1)) { - virtualSpaces = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)); - } + const Sci::Position virtualSpaces = (subLine == (ll->lines - 1)) ? + model.VirtualSpaceForLine(line) : 0; const SelectionPosition posStart(posLineStart + lineRange.start); const SelectionPosition posEnd(posLineStart + lineRange.end, virtualSpaces); const SelectionSegment virtualSpaceRange(posStart, posEnd); @@ -1912,7 +1893,7 @@ void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid, // Draw the arrow head if needed if (vsDraw.tabDrawMode == TabDrawMode::LongArrow) { - XYPOSITION ydiff = std::floor(rcTab.Height() / 2.0f); + XYPOSITION ydiff = std::floor(rcTab.Height() / 2); XYPOSITION xhead = rightStroke - ydiff; if (xhead <= rcTab.left) { ydiff -= rcTab.left - xhead; @@ -2031,7 +2012,7 @@ void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &v const Sci::Position endPos = std::min(rangeRun.end, posLineEnd); const int edition = model.pdoc->EditionAt(startPos); if (edition != 0) { - const int indicator = (edition - 1) * 2 + indexHistory; + const int indicator = ((edition - 1) * 2) + indexHistory; const Sci::Position posSecond = model.pdoc->MovePositionOutsideChar(rangeRun.First() + 1, 1); DrawIndicator(indicator, startPos - posLineStart, endPos - posLineStart, surface, vsDraw, ll, xStart, rcLine, posSecond - posLineStart, subLine, Indicator::State::normal, @@ -2048,7 +2029,7 @@ void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &v const Sci::Position posSecond = model.pdoc->MovePositionOutsideChar(startPos + 1, 1); for (unsigned int edition = 0; edition < 4; edition++) { if (editions & (1 << edition)) { - const int indicator = edition * 2 + indexHistory + 1; + const int indicator = (edition * 2) + indexHistory + 1; DrawIndicator(indicator, startPos - posLineStart, posSecond - posLineStart, surface, vsDraw, ll, xStart, rcLine, posSecond - posLineStart, subLine, Indicator::State::normal, 1, model.BidirectionalEnabled(), tabWidthMinimumPixels); @@ -2102,12 +2083,12 @@ ColourRGBA InvertedLight(ColourRGBA orig) noexcept { r = r * il / l; g = g * il / l; b = b * il / l; - return ColourRGBA(std::min(r, 0xffu), std::min(g, 0xffu), std::min(b, 0xffu)); + return ColourRGBA(std::min(r, maximumByte), std::min(g, maximumByte), std::min(b, maximumByte)); } } -void EditView::DrawIndentGuide(Surface *surface, XYPOSITION start, PRectangle rcSegment, bool highlight, bool offset) { +void EditView::DrawIndentGuide(Surface *surface, XYPOSITION start, PRectangle rcSegment, bool highlight, bool offset) const { const Point from = Point::FromInts(0, offset ? 1 : 0); const PRectangle rcCopyArea(start + 1, rcSegment.top, start + 2, rcSegment.bottom); @@ -2197,7 +2178,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi } ColourRGBA textBack = TextBackground(model, vsDraw, ll, background, inSelection, inHotspot, styleMain, i); if (ts.representation) { - if (ll->chars[i] == '\t') { + if (ll->chars[i] == '\t' && vsDraw.tabDrawMode != TabDrawMode::ControlChar) { // Tab display if (phasesDraw == PhasesDraw::One) { if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation)) @@ -2219,7 +2200,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi if (vsDraw.WhiteSpaceVisible(inIndentation)) { const PRectangle rcTab(rcSegment.left + 1, rcSegment.top + tabArrowHeight, rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent); - const int segmentTop = static_cast<int>(rcSegment.top) + vsDraw.lineHeight / 2; + const int segmentTop = static_cast<int>(rcSegment.top) + (vsDraw.lineHeight / 2); const ColourRGBA whiteSpaceFore = vsDraw.ElementColour(Element::WhiteSpace).value_or(textFore); if (!customDrawTabArrow) DrawTabArrow(surface, rcTab, segmentTop, vsDraw, Stroke(whiteSpaceFore, 1.0f)); @@ -2229,12 +2210,13 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi } } else { inIndentation = false; - if (vsDraw.controlCharSymbol >= 32) { + if (vsDraw.controlCharSymbol >= ' ') { // Using one font for all control characters so it can be controlled independently to ensure // the box goes around the characters tightly. Seems to be no way to work out what height // is taken by an individual character - internal leading gives varying results. const Font *ctrlCharsFont = vsDraw.styles[StyleControlChar].font.get(); const char cc[2] = { static_cast<char>(vsDraw.controlCharSymbol), '\0' }; + // NOLINTNEXTLINE(readability-suspicious-call-argument) Inverted text surface->DrawTextNoClip(rcSegment, ctrlCharsFont, ybase, cc, textBack, textFore); } else { @@ -2286,7 +2268,7 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi } const int halfDotWidth = vsDraw.whitespaceSize / 2; PRectangle rcDot(xmid - halfDotWidth, - rcSegment.top + vsDraw.lineHeight / 2, 0.0f, 0.0f); + rcSegment.top + (vsDraw.lineHeight / 2), 0.0f, 0.0f); rcDot.right = rcDot.left + vsDraw.whitespaceSize; rcDot.bottom = rcDot.top + vsDraw.whitespaceSize; const ColourRGBA whiteSpaceFore = vsDraw.ElementColour(Element::WhiteSpace).value_or(textFore); @@ -2336,12 +2318,16 @@ void EditView::DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &mode // Find the most recent line with some text + constexpr int largeIndent = 100000; + + constexpr Sci::Line maxCheck = 20; + Sci::Line lineLastWithText = line; - while (lineLastWithText > std::max(line - 20, static_cast<Sci::Line>(0)) && model.pdoc->IsWhiteLine(lineLastWithText)) { + while (lineLastWithText > std::max(line - maxCheck, static_cast<Sci::Line>(0)) && model.pdoc->IsWhiteLine(lineLastWithText)) { lineLastWithText--; } if (lineLastWithText < line) { - xStartText = 100000; // Don't limit to visible indentation on empty line + xStartText = largeIndent; // Don't limit to visible indentation on empty line // This line is empty, so use indentation of last line with text int indentLastWithText = model.pdoc->GetLineIndentation(lineLastWithText); const int isFoldHeader = LevelIsHeader(model.pdoc->GetFoldLevel(lineLastWithText)); @@ -2350,21 +2336,21 @@ void EditView::DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &mode indentLastWithText += model.pdoc->IndentSize(); } if (vsDraw.viewIndentationGuides == IndentView::LookForward) { - // In viLookForward mode, previous line only used if it is a fold header + // In LookForward mode, previous line only used if it is a fold header if (isFoldHeader) { indentSpace = std::max(indentSpace, indentLastWithText); } - } else { // viLookBoth + } else { // LookBoth indentSpace = std::max(indentSpace, indentLastWithText); } } Sci::Line lineNextWithText = line; - while (lineNextWithText < std::min(line + 20, model.pdoc->LinesTotal()) && model.pdoc->IsWhiteLine(lineNextWithText)) { + while (lineNextWithText < std::min(line + maxCheck, model.pdoc->LinesTotal()) && model.pdoc->IsWhiteLine(lineNextWithText)) { lineNextWithText++; } if (lineNextWithText > line) { - xStartText = 100000; // Don't limit to visible indentation on empty line + xStartText = largeIndent; // Don't limit to visible indentation on empty line // This line is empty, so use indentation of first next line with text indentSpace = std::max(indentSpace, model.pdoc->GetLineIndentation(lineNextWithText)); @@ -2381,10 +2367,10 @@ void EditView::DrawIndentGuidesOverEmpty(Surface *surface, const EditModel &mode } void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, - Sci::Line line, Sci::Line lineVisible, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { + Sci::Line line, Sci::Line lineVisible, int xOrigin, PRectangle rcLine, int subLine, DrawPhase phase) { if (subLine >= ll->lines) { - DrawAnnotation(surface, model, vsDraw, ll, line, xStart, rcLine, subLine, phase); + DrawAnnotation(surface, model, vsDraw, ll, line, xOrigin, rcLine, subLine, phase); return; // No further drawing } @@ -2404,10 +2390,10 @@ void EditView::DrawLine(Surface *surface, const EditModel &model, const ViewStyl if ((ll->wrapIndent != 0) && (subLine > 0)) { if (FlagSet(phase, DrawPhase::back)) { - DrawWrapIndentAndMarker(surface, vsDraw, ll, xStart, rcLine, background, customDrawWrapMarker, model.caret.active); + DrawWrapIndentAndMarker(surface, vsDraw, ll, xOrigin, rcLine, background, customDrawWrapMarker, model.caret.active); } - xStart += static_cast<int>(ll->wrapIndent); } + const int xStart = xOrigin + ((subLine > 0) ? static_cast<int>(ll->wrapIndent) : 0); if (phasesDraw != PhasesDraw::One) { if (FlagSet(phase, DrawPhase::back)) { @@ -2497,7 +2483,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V const Point ptOrigin = model.GetVisibleOriginInMain(); const int screenLinePaintFirst = static_cast<int>(rcArea.top) / vsDraw.lineHeight; - const int xStart = vsDraw.textStart - model.xOffset + static_cast<int>(ptOrigin.x); + const int xOrigin = vsDraw.textStart - model.xOffset + static_cast<int>(ptOrigin.x); const SelectionPosition posCaret = model.posDrag.IsValid() ? model.posDrag : model.sel.RangeMain().caret; const Sci::Line lineCaret = model.pdoc->SciLineFromPosition(posCaret.Position()); @@ -2588,7 +2574,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V surface->FillRectangleAligned(rcSpacer, Fill(vsDraw.styles[StyleDefault].back)); } - DrawLine(surface, model, vsDraw, ll.get(), lineDoc, visibleLine, xStart, rcLine, subLine, phase); + DrawLine(surface, model, vsDraw, ll.get(), lineDoc, visibleLine, xOrigin, rcLine, subLine, phase); #if defined(TIME_PAINTING) durPaint += ep.Duration(true); #endif @@ -2600,7 +2586,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V } if (FlagSet(phase, DrawPhase::carets)) { - DrawCarets(surface, model, vsDraw, ll.get(), lineDoc, xStart, rcLine, subLine); + DrawCarets(surface, model, vsDraw, ll.get(), lineDoc, xOrigin, rcLine, subLine); } if (bufferedDraw) { @@ -2612,8 +2598,7 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); } - lineWidthMaxSeen = std::max( - lineWidthMaxSeen, static_cast<int>(ll->positions[ll->numCharsInLine])); + UpdateMaxWidth(ll->positions[ll->numCharsInLine]); #if defined(TIME_PAINTING) durCopy += ep.Duration(true); #endif @@ -2646,14 +2631,14 @@ void EditView::PaintText(Surface *surfaceWindow, const EditModel &model, const V surfaceWindow->FillRectangleAligned(rcBeyondEOF, Fill(vsDraw.styles[StyleDefault].back)); if (vsDraw.edgeState == EdgeVisualStyle::Line) { const int edgeX = static_cast<int>(vsDraw.theEdge.column * vsDraw.spaceWidth); - rcBeyondEOF.left = static_cast<XYPOSITION>(edgeX + xStart); + rcBeyondEOF.left = static_cast<XYPOSITION>(edgeX + xOrigin); rcBeyondEOF.right = rcBeyondEOF.left + 1; surfaceWindow->FillRectangleAligned(rcBeyondEOF, Fill(vsDraw.theEdge.colour)); } else if (vsDraw.edgeState == EdgeVisualStyle::MultiLine) { for (size_t edge = 0; edge < vsDraw.theMultiEdge.size(); edge++) { if (vsDraw.theMultiEdge[edge].column >= 0) { const int edgeX = static_cast<int>(vsDraw.theMultiEdge[edge].column * vsDraw.spaceWidth); - rcBeyondEOF.left = static_cast<XYPOSITION>(edgeX + xStart); + rcBeyondEOF.left = static_cast<XYPOSITION>(edgeX + xOrigin); rcBeyondEOF.right = rcBeyondEOF.left + 1; surfaceWindow->FillRectangleAligned(rcBeyondEOF, Fill(vsDraw.theMultiEdge[edge].colour)); } @@ -2750,13 +2735,11 @@ Sci::Position EditView::FormatRange(bool draw, CharacterRangeFull chrg, Rectangl 1u << static_cast<unsigned int>(MarkerOutline::HistoryRevertedToModified); vsPrint.maskInLine &= ~changeMarkers; + const int linesInArea = (rc.bottom - rc.top) / vsPrint.lineHeight; const Sci::Line linePrintStart = model.pdoc->SciLineFromPosition(chrg.cpMin); - Sci::Line linePrintLast = linePrintStart + (rc.bottom - rc.top) / vsPrint.lineHeight - 1; - if (linePrintLast < linePrintStart) - linePrintLast = linePrintStart; const Sci::Line linePrintMax = model.pdoc->SciLineFromPosition(chrg.cpMax); - if (linePrintLast > linePrintMax) - linePrintLast = linePrintMax; + const Sci::Line linePrintLast = std::min(std::max(linePrintStart + linesInArea - 1, linePrintStart), linePrintMax); + //Platform::DebugPrintf("Formatting lines=[%0d,%0d,%0d] top=%0d bottom=%0d line=%0d %0d\n", // linePrintStart, linePrintLast, linePrintMax, rc.top, rc.bottom, vsPrint.lineHeight, // surfaceMeasure->Height(vsPrint.styles[StyleLineNumber].font)); @@ -2767,7 +2750,7 @@ Sci::Position EditView::FormatRange(bool draw, CharacterRangeFull chrg, Rectangl // Ensure we are styled to where we are formatting. model.pdoc->EnsureStyledTo(endPosPrint); - const int xStart = vsPrint.fixedColumnWidth + rc.left; + const int xOrigin = vsPrint.fixedColumnWidth + rc.left; int ypos = rc.top; Sci::Line lineDoc = linePrintStart; @@ -2841,7 +2824,7 @@ Sci::Position EditView::FormatRange(bool draw, CharacterRangeFull chrg, Rectangl if (draw) { rcLine.top = static_cast<XYPOSITION>(ypos); rcLine.bottom = static_cast<XYPOSITION>(ypos + vsPrint.lineHeight); - DrawLine(surface, model, vsPrint, &ll, lineDoc, visibleLine, xStart, rcLine, iwl, DrawPhase::all); + DrawLine(surface, model, vsPrint, &ll, lineDoc, visibleLine, xOrigin, rcLine, iwl, DrawPhase::all); } ypos += vsPrint.lineHeight; } |
