Skip to content

Commit 2ba06c5

Browse files
committed
refactor(datagrid): extract cell focus indicator into layer-backed CellFocusOverlay
1 parent b2a6f94 commit 2ba06c5

2 files changed

Lines changed: 68 additions & 34 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// CellFocusOverlay.swift
3+
// TablePro
4+
//
5+
6+
import AppKit
7+
8+
final class CellFocusOverlay: NSView {
9+
enum Style {
10+
case hidden
11+
case contrastingBorder
12+
}
13+
14+
var style: Style = .hidden {
15+
didSet {
16+
guard oldValue != style else { return }
17+
applyStyle()
18+
}
19+
}
20+
21+
override init(frame frameRect: NSRect) {
22+
super.init(frame: frameRect)
23+
wantsLayer = true
24+
translatesAutoresizingMaskIntoConstraints = false
25+
isHidden = true
26+
}
27+
28+
required init?(coder: NSCoder) {
29+
fatalError("init(coder:) has not been implemented")
30+
}
31+
32+
override func hitTest(_ point: NSPoint) -> NSView? { nil }
33+
34+
override func viewDidChangeEffectiveAppearance() {
35+
super.viewDidChangeEffectiveAppearance()
36+
if !isHidden { applyStyle() }
37+
}
38+
39+
private func applyStyle() {
40+
switch style {
41+
case .hidden:
42+
isHidden = true
43+
layer?.borderWidth = 0
44+
case .contrastingBorder:
45+
isHidden = false
46+
layer?.borderWidth = 2
47+
layer?.borderColor = NSColor.alternateSelectedControlTextColor.cgColor
48+
}
49+
}
50+
}

TablePro/Views/Results/Cells/DataGridBaseCellView.swift

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,22 @@ class DataGridBaseCellView: NSTableCellView {
3434
var isFocusedCell: Bool = false {
3535
didSet {
3636
guard oldValue != isFocusedCell else { return }
37-
updateFocusRing()
37+
updateFocusPresentation()
3838
}
3939
}
4040

41+
private lazy var focusOverlay: CellFocusOverlay = {
42+
let overlay = CellFocusOverlay()
43+
addSubview(overlay)
44+
NSLayoutConstraint.activate([
45+
overlay.leadingAnchor.constraint(equalTo: leadingAnchor),
46+
overlay.trailingAnchor.constraint(equalTo: trailingAnchor),
47+
overlay.topAnchor.constraint(equalTo: topAnchor),
48+
overlay.bottomAnchor.constraint(equalTo: bottomAnchor),
49+
])
50+
return overlay
51+
}()
52+
4153
private(set) lazy var backgroundView: NSView = {
4254
let view = NSView()
4355
view.wantsLayer = true
@@ -189,7 +201,7 @@ class DataGridBaseCellView: NSTableCellView {
189201
override var backgroundStyle: NSView.BackgroundStyle {
190202
didSet {
191203
backgroundView.isHidden = (changeBackgroundColor == nil)
192-
if isFocusedCell { needsDisplay = true }
204+
updateFocusPresentation()
193205
}
194206
}
195207

@@ -202,38 +214,10 @@ class DataGridBaseCellView: NSTableCellView {
202214
NSBezierPath(rect: bounds).fill()
203215
}
204216

205-
override func draw(_ dirtyRect: NSRect) {
206-
super.draw(dirtyRect)
207-
guard isFocusedCell else { return }
208-
if backgroundStyle == .emphasized {
209-
drawEmphasizedFocusBorder()
210-
} else {
211-
NSGraphicsContext.saveGraphicsState()
212-
NSFocusRingPlacement.only.set()
213-
drawFocusRingMask()
214-
NSGraphicsContext.restoreGraphicsState()
215-
}
216-
}
217-
218-
private func drawEmphasizedFocusBorder() {
219-
let inset: CGFloat = 1
220-
let rect = bounds.insetBy(dx: inset, dy: inset)
221-
let path = NSBezierPath(rect: rect)
222-
path.lineWidth = 2
223-
NSColor.alternateSelectedControlTextColor.setStroke()
224-
path.stroke()
225-
}
226-
227-
override func viewDidChangeEffectiveAppearance() {
228-
super.viewDidChangeEffectiveAppearance()
229-
if isFocusedCell {
230-
needsDisplay = true
231-
}
232-
}
233-
234-
private func updateFocusRing() {
235-
focusRingType = (isFocusedCell && backgroundStyle != .emphasized) ? .exterior : .none
217+
private func updateFocusPresentation() {
218+
let onEmphasized = backgroundStyle == .emphasized
219+
focusOverlay.style = (isFocusedCell && onEmphasized) ? .contrastingBorder : .hidden
220+
focusRingType = (isFocusedCell && !onEmphasized) ? .exterior : .none
236221
noteFocusRingMaskChanged()
237-
needsDisplay = true
238222
}
239223
}

0 commit comments

Comments
 (0)