aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2023-01-16 09:07:09 +1100
committerNeil <nyamatongwe@gmail.com>2023-01-16 09:07:09 +1100
commit887da82073d4ab855a3ba95deaa652d475df21e2 (patch)
treed1d9d02e5915726b3bb21e5ef95da4507a42ec18 /src
parent8fe06c8d006a9f149a964f1a69b4f1230082ed00 (diff)
downloadscintilla-mirror-887da82073d4ab855a3ba95deaa652d475df21e2.tar.gz
Use intervals for drawing.
Diffstat (limited to 'src')
-rw-r--r--src/EditView.cxx100
-rw-r--r--src/Geometry.h11
-rw-r--r--src/PositionCache.cxx8
-rw-r--r--src/PositionCache.h2
-rw-r--r--src/Selection.h6
5 files changed, 70 insertions, 57 deletions
diff --git a/src/EditView.cxx b/src/EditView.cxx
index ab94c4691..78d38f110 100644
--- a/src/EditView.cxx
+++ b/src/EditView.cxx
@@ -1756,17 +1756,11 @@ void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &v
const Sci::Position i = ts.end() - 1;
const Sci::Position iDoc = i + posLineStart;
- PRectangle rcSegment = rcLine;
- rcSegment.left = ll->positions[ts.start] + horizontalOffset;
- rcSegment.right = ll->positions[ts.end()] + horizontalOffset;
+ const Interval horizontal = ll->Span(ts.start, ts.end()).Offset(horizontalOffset);
// Only try to draw if really visible - enhances performance by not calling environment to
// draw strings that are completely past the right side of the window.
- if (!rcSegment.Empty() && rcSegment.Intersects(rcLine)) {
- // Clip to line rectangle, since may have a huge position which will not work with some platforms
- if (rcSegment.left < rcLine.left)
- rcSegment.left = rcLine.left;
- if (rcSegment.right > rcLine.right)
- rcSegment.right = rcLine.right;
+ if (!horizontal.Empty() && rcLine.Intersects(horizontal)) {
+ const PRectangle rcSegment = Intersection(rcLine, horizontal);
InSelection inSelection = vsDraw.selection.visible ? model.sel.CharacterInSelection(iDoc) : InSelection::inNone;
if (FlagSet(vsDraw.caret.style, CaretStyle::Curses) && (inSelection == InSelection::inMain))
@@ -1792,11 +1786,8 @@ void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &v
for (int cpos = 0; cpos <= i - ts.start; cpos++) {
if (ll->chars[cpos + ts.start] == ' ') {
if (drawWhitespaceBackground && vsDraw.WhiteSpaceVisible(inIndentation)) {
- const PRectangle rcSpace(
- ll->positions[cpos + ts.start] + horizontalOffset,
- rcSegment.top,
- ll->positions[cpos + ts.start + 1] + horizontalOffset,
- rcSegment.bottom);
+ const PRectangle rcSpace = Intersection(rcLine,
+ ll->SpanByte(cpos + ts.start).Offset(horizontalOffset));
surface->FillRectangleAligned(rcSpace,
vsDraw.ElementColourForced(Element::WhiteSpaceBack).Opaque());
}
@@ -1806,7 +1797,7 @@ void DrawBackground(Surface *surface, const EditModel &model, const ViewStyle &v
}
}
}
- } else if (rcSegment.left > rcLine.right) {
+ } else if (horizontal.left > rcLine.right) {
break;
}
}
@@ -1869,45 +1860,44 @@ void DrawTranslucentSelection(Surface *surface, const EditModel &model, const Vi
for (size_t r = 0; r < model.sel.Count(); r++) {
const SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange);
if (!portion.Empty()) {
+ const SelectionSegment portionInLine = portion.Subtract(posLineStart);
const ColourRGBA selectionBack = SelectionBackground(
model, vsDraw, model.sel.RangeType(r));
const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth;
+ const Interval intervalVirtual{ portion.start.VirtualSpace() * spaceWidth, portion.end.VirtualSpace() * spaceWidth };
if (model.BidirectionalEnabled()) {
- const Sci::Position selectionStart = portion.start.Position() - posLineStart - lineRange.start;
- const Sci::Position selectionEnd = portion.end.Position() - posLineStart - lineRange.start;
+ const SelectionSegment portionInSubLine = portionInLine.Subtract(lineRange.start);
const ScreenLine screenLine(ll, subLine, vsDraw, rcLine.right, tabWidthMinimumPixels);
std::unique_ptr<IScreenLineLayout> slLayout = surface->Layout(&screenLine);
if (slLayout) {
- const std::vector<Interval> intervals = slLayout->FindRangeIntervals(selectionStart, selectionEnd);
+ const std::vector<Interval> intervals = slLayout->FindRangeIntervals(
+ portionInSubLine.start.Position(), portionInSubLine.end.Position());
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);
+ const PRectangle rcSelection = rcLine.WithHorizontalBounds(interval.Offset(xStart));
surface->FillRectangleAligned(rcSelection, selectionBack);
}
}
if (portion.end.VirtualSpace()) {
const XYPOSITION xStartVirtual = ll->positions[lineRange.end] + horizontalOffset;
- PRectangle rcSegment = rcLine;
- rcSegment.left = xStartVirtual + portion.start.VirtualSpace() * spaceWidth;
- rcSegment.right = xStartVirtual + portion.end.VirtualSpace() * spaceWidth;
+ const PRectangle rcSegment = rcLine.WithHorizontalBounds(intervalVirtual.Offset(xStartVirtual));
surface->FillRectangleAligned(rcSegment, selectionBack);
}
} else {
- PRectangle rcSegment = rcLine;
- rcSegment.left = ll->positions[portion.start.Position() - posLineStart] +
- horizontalOffset + portion.start.VirtualSpace() * spaceWidth;
- rcSegment.right = ll->positions[portion.end.Position() - posLineStart] +
- horizontalOffset + portion.end.VirtualSpace() * spaceWidth;
+ Interval intervalSegment = ll->Span(
+ static_cast<int>(portionInLine.start.Position()),
+ static_cast<int>(portionInLine.end.Position()))
+ .Offset(horizontalOffset);
+ intervalSegment.left += intervalVirtual.left;
+ intervalSegment.right += intervalVirtual.right;
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
+ if ((portionInLine.start.Position() == lineRange.start) &&
+ model.sel.Range(r).ContainsCharacter(portion.start.Position() - 1))
+ intervalSegment.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;
+ const PRectangle rcSegment = Intersection(rcLine, intervalSegment);
if (rcSegment.right > rcLine.left)
surface->FillRectangleAligned(rcSegment, selectionBack);
}
@@ -2240,12 +2230,11 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
const Sci::Position i = ts.end() - 1;
const Sci::Position iDoc = i + posLineStart;
- PRectangle rcSegment = rcLine;
- rcSegment.left = ll->positions[ts.start] + horizontalOffset;
- rcSegment.right = ll->positions[ts.end()] + horizontalOffset;
+ const Interval horizontal = ll->Span(ts.start, ts.end()).Offset(horizontalOffset);
// Only try to draw if really visible - enhances performance by not calling environment to
// draw strings that are completely past the right side of the window.
- if (rcSegment.Intersects(rcLine)) {
+ if (rcLine.Intersects(horizontal)) {
+ const PRectangle rcSegment = rcLine.WithHorizontalBounds(horizontal);
const int styleMain = ll->styles[i];
ColourRGBA textFore = vsDraw.styles[styleMain].fore;
const Font *textFont = vsDraw.styles[styleMain].font.get();
@@ -2299,8 +2288,9 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
surface->FillRectangleAligned(rcSegment, Fill(textBack));
}
if (inIndentation && vsDraw.viewIndentationGuides == IndentView::Real) {
- for (int indentCount = static_cast<int>((ll->positions[i] + epsilon) / indentWidth);
- indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth;
+ const Interval intervalCharacter = ll->SpanByte(static_cast<int>(i));
+ for (int indentCount = static_cast<int>((intervalCharacter.left + epsilon) / indentWidth);
+ indentCount <= (intervalCharacter.right - epsilon) / indentWidth;
indentCount++) {
if (indentCount > 0) {
const XYPOSITION xIndent = std::floor(indentCount * indentWidth);
@@ -2370,18 +2360,15 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
if (ll->chars[cpos + ts.start] == ' ') {
if (vsDraw.viewWhitespace != WhiteSpace::Invisible) {
if (vsDraw.WhiteSpaceVisible(inIndentation)) {
- const XYPOSITION xmid = (ll->positions[cpos + ts.start] + ll->positions[cpos + ts.start + 1]) / 2;
+ const Interval intervalSpace = ll->SpanByte(cpos + ts.start).Offset(horizontalOffset);
+ const XYPOSITION xmid = (intervalSpace.left + intervalSpace.right) / 2;
if ((phasesDraw == PhasesDraw::One) && drawWhitespaceBackground) {
textBack = vsDraw.ElementColourForced(Element::WhiteSpaceBack).Opaque();
- const PRectangle rcSpace(
- ll->positions[cpos + ts.start] + horizontalOffset,
- rcSegment.top,
- ll->positions[cpos + ts.start + 1] + horizontalOffset,
- rcSegment.bottom);
+ const PRectangle rcSpace = rcLine.WithHorizontalBounds(intervalSpace);
surface->FillRectangleAligned(rcSpace, Fill(textBack));
}
const int halfDotWidth = vsDraw.whitespaceSize / 2;
- PRectangle rcDot(xmid - halfDotWidth + horizontalOffset,
+ PRectangle rcDot(xmid - halfDotWidth,
rcSegment.top + vsDraw.lineHeight / 2, 0.0f, 0.0f);
rcDot.right = rcDot.left + vsDraw.whitespaceSize;
rcDot.bottom = rcDot.top + vsDraw.whitespaceSize;
@@ -2390,8 +2377,9 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
}
}
if (inIndentation && vsDraw.viewIndentationGuides == IndentView::Real) {
- for (int indentCount = static_cast<int>((ll->positions[cpos + ts.start] + epsilon) / indentWidth);
- indentCount <= (ll->positions[cpos + ts.start + 1] - epsilon) / indentWidth;
+ const Interval intervalCharacter = ll->SpanByte(cpos + ts.start);
+ for (int indentCount = static_cast<int>((intervalCharacter.left + epsilon) / indentWidth);
+ indentCount <= (intervalCharacter.right - epsilon) / indentWidth;
indentCount++) {
if (indentCount > 0) {
const XYPOSITION xIndent = std::floor(indentCount * indentWidth);
@@ -2405,19 +2393,17 @@ void EditView::DrawForeground(Surface *surface, const EditModel &model, const Vi
}
}
}
- if (inHotspot && vsDraw.hotspotUnderline) {
+ if ((inHotspot && vsDraw.hotspotUnderline) || vsDraw.styles[styleMain].underline) {
PRectangle rcUL = rcSegment;
rcUL.top = ybase + 1;
rcUL.bottom = ybase + 2;
- const ColourOptional colourHotSpot = vsDraw.ElementColour(Element::HotSpotActive);
- surface->FillRectangleAligned(rcUL, Fill(colourHotSpot.value_or(textFore)));
- } else if (vsDraw.styles[styleMain].underline) {
- PRectangle rcUL = rcSegment;
- rcUL.top = ybase + 1;
- rcUL.bottom = ybase + 2;
- surface->FillRectangleAligned(rcUL, Fill(textFore));
+ ColourRGBA colourUnderline = textFore;
+ if (inHotspot && vsDraw.hotspotUnderline) {
+ colourUnderline = vsDraw.ElementColour(Element::HotSpotActive).value_or(textFore);
+ }
+ surface->FillRectangleAligned(rcUL, colourUnderline);
}
- } else if (rcSegment.left > rcLine.right) {
+ } else if (horizontal.left > rcLine.right) {
break;
}
}
diff --git a/src/Geometry.h b/src/Geometry.h
index 354f3ea25..4e4fe95d9 100644
--- a/src/Geometry.h
+++ b/src/Geometry.h
@@ -66,6 +66,9 @@ public:
constexpr bool Intersects(Interval other) const noexcept {
return (right > other.left) && (left < other.right);
}
+ constexpr Interval Offset(XYPOSITION offset) const noexcept {
+ return {left + offset, right + offset};
+ }
};
/**
@@ -112,6 +115,10 @@ public:
return (right > other.left) && (left < other.right) &&
(bottom > other.top) && (top < other.bottom);
}
+ constexpr bool Intersects(Interval horizontalBounds) const noexcept {
+ return (right > horizontalBounds.left) && (left < horizontalBounds.right);
+ }
+
void Move(XYPOSITION xDelta, XYPOSITION yDelta) noexcept {
left += xDelta;
top += yDelta;
@@ -119,6 +126,10 @@ public:
bottom += yDelta;
}
+ PRectangle WithHorizontalBounds(Interval horizontal) const noexcept {
+ return PRectangle(horizontal.left, top, horizontal.right, bottom);
+ }
+
constexpr PRectangle Inset(XYPOSITION delta) const noexcept {
return PRectangle(left + delta, top + delta, right - delta, bottom - delta);
}
diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx
index d36e3e629..c4bcbc411 100644
--- a/src/PositionCache.cxx
+++ b/src/PositionCache.cxx
@@ -314,6 +314,14 @@ XYPOSITION LineLayout::XInLine(Sci::Position index) const noexcept {
return positions[numCharsInLine] + 1.0;
}
+Interval LineLayout::Span(int start, int end) const noexcept {
+ return { positions[start], positions[end] };
+}
+
+Interval LineLayout::SpanByte(int index) const noexcept {
+ return Span(index, index+1);
+}
+
int LineLayout::EndLineStyle() const noexcept {
return styles[numCharsBeforeEOL > 0 ? numCharsBeforeEOL-1 : 0];
}
diff --git a/src/PositionCache.h b/src/PositionCache.h
index 24e4e2d5a..834472e75 100644
--- a/src/PositionCache.h
+++ b/src/PositionCache.h
@@ -105,6 +105,8 @@ public:
int FindPositionFromX(XYPOSITION x, Range range, bool charPosition) const noexcept;
Point PointFromPosition(int posInLine, int lineHeight, PointEnd pe) const noexcept;
XYPOSITION XInLine(Sci::Position index) const noexcept;
+ Interval Span(int start, int end) const noexcept;
+ Interval SpanByte(int index) const noexcept;
int EndLineStyle() const noexcept;
};
diff --git a/src/Selection.h b/src/Selection.h
index 4cda65d97..bc0f2208a 100644
--- a/src/Selection.h
+++ b/src/Selection.h
@@ -81,6 +81,12 @@ struct SelectionSegment {
if (end < p)
end = p;
}
+ SelectionSegment Subtract(Sci::Position increment) const noexcept {
+ SelectionSegment ret(start, end);
+ ret.start.Add(-increment);
+ ret.end.Add(-increment);
+ return ret;
+ }
};
struct SelectionRange {