Skip to content

Commit 3b78fcf

Browse files
committed
Mutli-Line Selections Fill Text Drawing Rect
1 parent 251033a commit 3b78fcf

File tree

2 files changed

+27
-12
lines changed

2 files changed

+27
-12
lines changed

Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,16 @@ public class TextLayoutManager: NSObject {
9797
delegate?.layoutManagerMaxWidthDidChange(newWidth: maxLineWidth + edgeInsets.horizontal)
9898
}
9999
}
100-
/// The maximum width available to lay out lines in.
100+
101+
/// The maximum width available to lay out lines in, used to determine how much space is available for laying out
102+
/// lines. Evals to `.greatestFiniteMagnitude` when ``wrapLines`` is `false`.
101103
var maxLineLayoutWidth: CGFloat {
102-
wrapLines ? (delegate?.textViewportSize().width ?? .greatestFiniteMagnitude) - edgeInsets.horizontal
103-
: .greatestFiniteMagnitude
104+
wrapLines ? wrapLinesWidth : .greatestFiniteMagnitude
105+
}
106+
107+
/// The width of the space available to draw text fragments when wrapping lines.
108+
var wrapLinesWidth: CGFloat {
109+
(delegate?.textViewportSize().width ?? .greatestFiniteMagnitude) - edgeInsets.horizontal
104110
}
105111

106112
/// Contains all data required to perform layout on a text line.

Sources/CodeEditTextView/TextSelectionManager/TextSelectionManager+FillRects.swift

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ import Foundation
99

1010
extension TextSelectionManager {
1111
/// Calculate a set of rects for a text selection suitable for filling with the selection color to indicate a
12-
/// multi-line selection.
13-
///
14-
/// The returned rects are inset by edge insets passed to the text view, the given `rect` parameter can be the 'raw'
15-
/// rect to draw in, no need to inset it before this method call.
12+
/// multi-line selection. The returned rects surround all selected line fragments for the given selection,
13+
/// following the available text layout space, rather than the available selection layout space.
1614
///
1715
/// - Parameters:
1816
/// - rect: The bounding rect of available draw space.
@@ -26,16 +24,27 @@ extension TextSelectionManager {
2624

2725
var fillRects: [CGRect] = []
2826

29-
let insetXPos = max(layoutManager.edgeInsets.left, rect.minX)
30-
let insetWidth = max(0, rect.maxX - insetXPos - layoutManager.edgeInsets.right)
31-
let insetRect = NSRect(x: insetXPos, y: rect.origin.y, width: insetWidth, height: rect.height)
27+
let textWidth = if layoutManager.maxLineLayoutWidth == .greatestFiniteMagnitude {
28+
layoutManager.maxLineWidth
29+
} else {
30+
layoutManager.maxLineLayoutWidth
31+
}
32+
let maxWidth = max(textWidth, layoutManager.wrapLinesWidth)
33+
let validTextDrawingRect = CGRect(
34+
x: layoutManager.edgeInsets.left,
35+
y: rect.minY,
36+
width: maxWidth,
37+
height: rect.height
38+
).intersection(rect)
3239

3340
for linePosition in layoutManager.lineStorage.linesInRange(range) {
34-
fillRects.append(contentsOf: getFillRects(in: insetRect, selectionRange: range, forPosition: linePosition))
41+
fillRects.append(
42+
contentsOf: getFillRects(in: validTextDrawingRect, selectionRange: range, forPosition: linePosition)
43+
)
3544
}
3645

3746
// Pixel align these to avoid aliasing on the edges of each rect that should be a solid box.
38-
return fillRects.map { $0.pixelAligned }
47+
return fillRects.map { $0.intersection(validTextDrawingRect).pixelAligned }
3948
}
4049

4150
/// Find fill rects for a specific line position.

0 commit comments

Comments
 (0)