Skip to content

Commit

Permalink
Use usageBoundsForTextContainer to adjust view frame
Browse files Browse the repository at this point in the history
  • Loading branch information
krzyzanowskim committed Oct 9, 2023
1 parent 865b1ab commit 7771b9a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 16 deletions.
6 changes: 6 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ let package = Package(
dependencies: [
.target(name: "STTextView")
]
),
.testTarget(
name: "STTextKitPlusTests",
dependencies: [
.target(name: "STTextKitPlus")
]
)
]
)
40 changes: 24 additions & 16 deletions Sources/STTextView/STTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ open class STTextView: NSView, NSTextInput, NSTextContent {
// textCheckingController.didChangeSelectedRange()
}


usageBoundsForTextContainerObserver = textLayoutManager.observe(\.usageBoundsForTextContainer, options: [.new]) { [weak self] textLayoutManager, change in
self?.needsUpdateConstraints = true
}
Expand Down Expand Up @@ -975,24 +976,12 @@ open class STTextView: NSView, NSTextInput, NSTextContent {
} else {
let endLocation = textLayoutManager.documentRange.endLocation
textLayoutManager.ensureLayout(for: NSTextRange(location: endLocation))
textLayoutManager.enumerateTextLayoutFragments(from: endLocation, options: [.reverse, .ensuresLayout, .ensuresExtraLineFragment]) { layoutFragment in
// at times, reported height is way above the final value for the document
// it result in "jumping" the scroller, as frame height grow and shrink
proposedHeight = max(proposedHeight, layoutFragment.layoutFragmentFrame.maxY)
return false // stop
}
proposedHeight = textLayoutManager.usageBoundsForTextContainer.height
}

var proposedWidth: CGFloat = viewportBounds.width
if !textContainer.widthTracksTextView {
// TODO: if offset didn't change since last time, it is not necessary to relayout
// not necessarly need to layout whole thing, is's enough to enumerate over visible area
let startLocation = textLayoutManager.textViewportLayoutController.viewportRange?.location ?? textLayoutManager.documentRange.location
let endLocation = textLayoutManager.textViewportLayoutController.viewportRange?.endLocation ?? textLayoutManager.documentRange.endLocation
textLayoutManager.enumerateTextLayoutFragments(in: NSTextRange(location: startLocation, end: endLocation)!, options: [.ensuresLayout, .ensuresExtraLineFragment]) { layoutFragment in
proposedWidth = max(proposedWidth, layoutFragment.layoutFragmentFrame.maxX)
return true
}
proposedWidth = textLayoutManager.usageBoundsForTextContainer.width
} else {
proposedWidth = max(currentSize.width, proposedWidth)
}
Expand All @@ -1004,7 +993,7 @@ open class STTextView: NSView, NSTextInput, NSTextContent {
}

// Update textContainer width to match textview width if track textview width
internal func updateTextContainerSizeIfNeeded() {
fileprivate func updateTextContainerSizeIfNeeded() {
var proposedSize = textContainer.size

if textContainer.widthTracksTextView, !textContainer.size.width.isAlmostEqual(to: visibleRect.width) {
Expand Down Expand Up @@ -1262,16 +1251,23 @@ open class STTextView: NSView, NSTextInput, NSTextContent {
// MARK: - NSViewInvalidating

private extension NSViewInvalidating where Self == NSView.Invalidations.InsertionPoint {

static var insertionPoint: NSView.Invalidations.InsertionPoint {
NSView.Invalidations.InsertionPoint()
}
}

private extension NSViewInvalidating where Self == NSView.Invalidations.CursorRects {
static var cursorRects: NSView.Invalidations.CursorRects {
NSView.Invalidations.CursorRects()
}
}

private extension NSViewInvalidating where Self == NSView.Invalidations.TextContainer {
static var textContainer: NSView.Invalidations.TextContainer {
NSView.Invalidations.TextContainer()
}
}

private extension NSView.Invalidations {

struct InsertionPoint: NSViewInvalidating {
Expand All @@ -1292,4 +1288,16 @@ private extension NSView.Invalidations {
}
}

struct TextContainer: NSViewInvalidating {

func invalidate(view: NSView) {
guard let textView = view as? STTextView else {
return
}

textView.updateTextContainerSizeIfNeeded()
}

}

}
6 changes: 6 additions & 0 deletions Tests/STTextKitPlusTests/TextLayoutManagerTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import XCTest
@testable import STTextView

class TextLayoutManagerTests : XCTestCase {
//
}

0 comments on commit 7771b9a

Please sign in to comment.