Skip to content

Commit

Permalink
Clean up implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
thecoolwinter committed Feb 16, 2024
1 parent 4329841 commit 1c171b2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 15 deletions.
29 changes: 29 additions & 0 deletions Sources/CodeEditTextView/Extensions/GC+ApproximateEqual.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// GC+ApproximateEqual.swift
// CodeEditTextView
//
// Created by Khan Winter on 2/16/24.
//

import Foundation

extension CGFloat {
func approxEqual(_ other: CGFloat, tolerance: CGFloat = 0.5) -> Bool {
abs(self - other) <= tolerance
}
}

extension CGPoint {
func approxEqual(_ other: CGPoint, tolerance: CGFloat = 0.5) -> Bool {
return self.x.approxEqual(other.x, tolerance: tolerance)
&& self.y.approxEqual(other.y, tolerance: tolerance)
}
}

extension CGRect {
func approxEqual(_ other: CGRect, tolerance: CGFloat = 0.5) -> Bool {
return self.origin.approxEqual(other.origin, tolerance: tolerance)
&& self.width.approxEqual(other.width, tolerance: tolerance)
&& self.height.approxEqual(other.height, tolerance: tolerance)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ public class TextSelectionManager: NSObject {
layoutManager: TextLayoutManager,
textStorage: NSTextStorage,
textView: TextView?,
delegate: TextSelectionManagerDelegate?
delegate: TextSelectionManagerDelegate?,
useSystemCursor: Bool = false
) {
self.layoutManager = layoutManager
self.textStorage = textStorage
Expand Down Expand Up @@ -173,29 +174,44 @@ public class TextSelectionManager: NSObject {
for textSelection in textSelections {
if textSelection.range.isEmpty {
let cursorOrigin = (layoutManager?.rectForOffset(textSelection.range.location) ?? .zero).origin
if textSelection.view == nil
|| textSelection.boundingRect.origin != cursorOrigin
|| textSelection.boundingRect.height != layoutManager?.estimateLineHeight() ?? 0 {
textSelection.view?.removeFromSuperview()
textSelection.view = nil

var doesViewNeedReposition: Bool

// If using the system cursor, macOS will change the origin and height by about 0.5, so we do an
// approximate equals in that case to avoid extra updates.
if useSystemCursor, #available(macOS 14.0, *) {
doesViewNeedReposition = !textSelection.boundingRect.origin.approxEqual(cursorOrigin)
|| !textSelection.boundingRect.height.approxEqual(layoutManager?.estimateLineHeight() ?? 0)
} else {
doesViewNeedReposition = textSelection.boundingRect.origin != cursorOrigin
|| textSelection.boundingRect.height != layoutManager?.estimateLineHeight() ?? 0
}

if textSelection.view == nil || doesViewNeedReposition {
let cursorView: NSView

if useSystemCursor, #available(macOS 14.0, *) {
let systemCursorView = NSTextInsertionIndicator(frame: .zero)
cursorView = systemCursorView
systemCursorView.displayMode = .visible
if let existingCursorView = textSelection.view {
cursorView = existingCursorView
} else {
let internalCursorView = CursorView(color: insertionPointColor)
cursorView = internalCursorView
cursorTimer.register(internalCursorView)
textSelection.view?.removeFromSuperview()
textSelection.view = nil

if useSystemCursor, #available(macOS 14.0, *) {
let systemCursorView = NSTextInsertionIndicator(frame: .zero)
cursorView = systemCursorView
systemCursorView.displayMode = .automatic
} else {
let internalCursorView = CursorView(color: insertionPointColor)
cursorView = internalCursorView
cursorTimer.register(internalCursorView)
}

textView?.addSubview(cursorView)
}

cursorView.frame.origin = cursorOrigin
cursorView.frame.size.height = layoutManager?.estimateLineHeight() ?? 0

textView?.addSubview(cursorView)

textSelection.view = cursorView
textSelection.boundingRect = cursorView.frame

Expand Down
31 changes: 31 additions & 0 deletions Sources/CodeEditTextView/TextView/TextView+Setup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,35 @@ extension TextView {
delegate: self
)
}

func setUpScrollListeners(scrollView: NSScrollView) {
NotificationCenter.default.removeObserver(self, name: NSScrollView.willStartLiveScrollNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: NSScrollView.didEndLiveScrollNotification, object: nil)

NotificationCenter.default.addObserver(
self,
selector: #selector(scrollViewWillStartScroll),
name: NSScrollView.willStartLiveScrollNotification,
object: scrollView
)

NotificationCenter.default.addObserver(
self,
selector: #selector(scrollViewDidEndScroll),
name: NSScrollView.didEndLiveScrollNotification,
object: scrollView
)
}

@objc func scrollViewWillStartScroll() {
if #available(macOS 14.0, *) {
inputContext?.textInputClientWillStartScrollingOrZooming()
}
}

@objc func scrollViewDidEndScroll() {
if #available(macOS 14.0, *) {
inputContext?.textInputClientDidEndScrollingOrZooming()
}
}
}
11 changes: 11 additions & 0 deletions Sources/CodeEditTextView/TextView/TextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ public class TextView: NSView, NSTextContent {
/// - isEditable: Determines if the view is editable.
/// - isSelectable: Determines if the view is selectable.
/// - letterSpacing: Sets the letter spacing on the view.
/// - useSystemCursor: Set to true to use the system cursor. Only available in macOS >= 14.
/// - delegate: The text view's delegate.
public init(
string: String,
Expand All @@ -251,6 +252,7 @@ public class TextView: NSView, NSTextContent {
isEditable: Bool,
isSelectable: Bool,
letterSpacing: Double,
useSystemCursor: Bool = false,
delegate: TextViewDelegate
) {
self.textStorage = NSTextStorage(string: string)
Expand Down Expand Up @@ -280,6 +282,7 @@ public class TextView: NSView, NSTextContent {
layoutManager = setUpLayoutManager(lineHeightMultiplier: lineHeightMultiplier, wrapLines: wrapLines)
storageDelegate.addDelegate(layoutManager)
selectionManager = setUpSelectionManager()
selectionManager.useSystemCursor = useSystemCursor

_undoManager = CEUndoManager(textView: self)

Expand Down Expand Up @@ -386,6 +389,14 @@ public class TextView: NSView, NSTextContent {
layoutManager.layoutLines()
}

override public func viewWillMove(toSuperview newSuperview: NSView?) {
guard let scrollView = enclosingScrollView else {
return
}

setUpScrollListeners(scrollView: scrollView)
}

override public func viewDidEndLiveResize() {
super.viewDidEndLiveResize()
updateFrameIfNeeded()
Expand Down

0 comments on commit 1c171b2

Please sign in to comment.