Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inset Selection Rect By Leading Edge #60

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
import Foundation

extension TextSelectionManager {
/// Calculate a set of rects for a text selection suitable for highlighting the selection.
/// Calculate a set of rects for a text selection suitable for filling with the selection color to indicate a
/// multi-line selection.
///
/// The returned rects are inset by edge insets passed to the text view, the given `rect` parameter can be the 'raw'
/// rect to draw in, no need to inset it before this method call.
///
/// - Parameters:
/// - rect: The bounding rect of available draw space.
/// - textSelection: The selection to use.
Expand All @@ -25,27 +30,35 @@ extension TextSelectionManager {
return []
}

let insetXPos = max(layoutManager.edgeInsets.left, rect.minX)
let insetWidth = max(0, rect.maxX - insetXPos - layoutManager.edgeInsets.right)
let insetRect = NSRect(x: insetXPos, y: rect.origin.y, width: insetWidth, height: rect.height)

// Calculate the first line and any rects selected
// If the last line position is not the same as the first, calculate any rects from that line.
// If there's > 0 space between the first and last positions, add a rect between them to cover any
// intermediate lines.

fillRects.append(contentsOf: getFillRects(in: rect, selectionRange: range, forPosition: firstLinePosition))

if lastLinePosition.range != firstLinePosition.range {
fillRects.append(contentsOf: getFillRects(in: rect, selectionRange: range, forPosition: lastLinePosition))
let firstLineRects = getFillRects(in: rect, selectionRange: range, forPosition: firstLinePosition)
let lastLineRects: [CGRect] = if lastLinePosition.range != firstLinePosition.range {
getFillRects(in: rect, selectionRange: range, forPosition: lastLinePosition)
} else {
[]
}

fillRects.append(contentsOf: firstLineRects + lastLineRects)

if firstLinePosition.yPos + firstLinePosition.height < lastLinePosition.yPos {
fillRects.append(CGRect(
x: rect.minX,
x: insetXPos,
y: firstLinePosition.yPos + firstLinePosition.height,
width: rect.width,
width: insetWidth,
height: lastLinePosition.yPos - (firstLinePosition.yPos + firstLinePosition.height)
))
}

return fillRects
// Pixel align these to avoid aliasing on the edges of each rect that should be a solid box.
return fillRects.map { $0.intersection(insetRect).pixelAligned }
}

/// Find fill rects for a specific line position.
Expand Down