Skip to content
Merged
Show file tree
Hide file tree
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
74 changes: 65 additions & 9 deletions Free Ruler/RulerWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,11 @@ final class RulerWindow: NSPanel {
return frame.origin
}

var drawsActiveBorder: Bool {
get { return rulerContentView.drawsActiveBorder }
set { rulerContentView.drawsActiveBorder = newValue }
}

private var leftMouseButtonIsPressed: Bool {
return NSEvent.pressedMouseButtons & 1 == 1
}
Expand Down Expand Up @@ -566,6 +571,9 @@ private final class RulerClipView: NSView {
}

private final class RulerWindowBorderView: RulerBorderView {
private static let activeBorderCenterInset = borderCenterInset + borderWidth
private static let activeBorderColor = NSColor(calibratedWhite: 0, alpha: 0.25)

var zeroCorner = prefs.zeroCorner {
didSet {
needsDisplay = true
Expand All @@ -584,31 +592,58 @@ private final class RulerWindowBorderView: RulerBorderView {
}
}

var drawsActiveBorder = false {
didSet {
needsDisplay = true
}
}

override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)

guard drawsActiveBorder else { return }

let path = activeBorderPath(in: bounds)
path.lineWidth = Self.borderWidth
path.lineJoinStyle = .miter
path.lineCapStyle = .butt
Self.activeBorderColor.setStroke()
path.stroke()
}

override func borderPath(in bounds: NSRect) -> NSBezierPath {
return panelBorderPath(in: bounds, inset: Self.borderCenterInset)
}

private func activeBorderPath(in bounds: NSRect) -> NSBezierPath {
return panelBorderPath(in: bounds, inset: Self.activeBorderCenterInset)
}

private func panelBorderPath(in bounds: NSRect, inset: CGFloat) -> NSBezierPath {
switch (showsHorizontalRule, showsVerticalRule) {
case (true, true):
return lShapedBorderPath()
return lShapedBorderPath(inset: inset)
case (true, false):
return visibleBoundsBorderPath()
return visibleBoundsBorderPath(inset: inset)
case (false, true):
return visibleBoundsBorderPath()
return visibleBoundsBorderPath(inset: inset)
case (false, false):
return NSBezierPath()
}
}

private func lShapedBorderPath() -> NSBezierPath {
private func lShapedBorderPath(inset: CGFloat) -> NSBezierPath {
return rulerWindowLShapedPath(
in: bounds,
zeroCorner: zeroCorner,
inset: Self.borderCenterInset
inset: inset
)
}

private func visibleBoundsBorderPath() -> NSBezierPath {
private func visibleBoundsBorderPath(inset: CGFloat) -> NSBezierPath {
return NSBezierPath(rect: bounds.insetBy(
dx: Self.borderCenterInset,
dy: Self.borderCenterInset
dx: inset,
dy: inset
))
}
}
Expand Down Expand Up @@ -808,6 +843,12 @@ final class RulerContentView: NSView {
}
}

var drawsActiveBorder = false {
didSet {
borderView.drawsActiveBorder = drawsActiveBorder
}
}

init(
frame frameRect: NSRect,
horizontalRule: HorizontalRule,
Expand Down Expand Up @@ -1632,6 +1673,7 @@ final class RulerManager {

func restore(_ states: [RulerInstanceState], activeRulerID restoredActiveRulerID: UUID? = nil) {
for controller in controllers {
controller.rulerWindow.drawsActiveBorder = false
controller.hide()
}

Expand Down Expand Up @@ -1688,11 +1730,18 @@ final class RulerManager {
}

func close(_ controller: RulerController) {
let wasActiveController = activeRulerID == controller.state.id

controller.hide()
controllers.removeAll { $0 === controller }

if activeRulerID == controller.state.id {
if wasActiveController {
activeRulerID = controllers.last?.state.id
}

updateActiveRulerBorders()

if wasActiveController {
onActiveControllerChanged?(activeController)
}

Expand All @@ -1703,6 +1752,7 @@ final class RulerManager {
guard controllers.contains(where: { $0 === controller }) else { return }

activeRulerID = controller.state.id
updateActiveRulerBorders()
onActiveControllerChanged?(controller)
notifyStateChanged()
}
Expand Down Expand Up @@ -1811,6 +1861,12 @@ final class RulerManager {
private func notifyStateChanged() {
onStateChanged?(self)
}

private func updateActiveRulerBorders() {
for controller in controllers {
controller.rulerWindow.drawsActiveBorder = controller.state.id == activeRulerID
}
}
}
#endif

Expand Down
30 changes: 30 additions & 0 deletions FreeRulerTests/RulerCoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,36 @@ final class RulerCoreTests: XCTestCase {
XCTAssertEqual(manager.states.map(\.settings.unit), [.inches])
}

func testRulerManagerDrawsActiveBorderOnlyOnActiveRuler() {
let manager = RulerManager()
defer {
for controller in manager.controllers {
controller.hide()
}
}

let first = manager.createRuler(
defaults: RulerSettings(unit: .pixels),
screenFrame: NSRect(x: 0, y: 0, width: 1000, height: 800)
)
let second = manager.createRuler(
defaults: RulerSettings(unit: .inches),
screenFrame: NSRect(x: 0, y: 0, width: 1000, height: 800)
)

XCTAssertFalse(first.rulerWindow.drawsActiveBorder)
XCTAssertTrue(second.rulerWindow.drawsActiveBorder)

manager.markActive(first)

XCTAssertTrue(first.rulerWindow.drawsActiveBorder)
XCTAssertFalse(second.rulerWindow.drawsActiveBorder)

XCTAssertTrue(manager.closeActiveRuler())

XCTAssertTrue(second.rulerWindow.drawsActiveBorder)
}

func testRulerManagerStaggersNewRulersWhenDefaultPositionIsOccupied() {
let manager = RulerManager()
defer {
Expand Down