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
2 changes: 2 additions & 0 deletions Free Ruler/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
"backgroundOpacity",
"rulerColor",
"unit",
"zeroCorner",
"NSWindow Frame horizontal-ruler",
"NSWindow Frame vertical-ruler",
"NSWindow Frame preferencesWindow",
Expand All @@ -274,6 +275,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
prefs.backgroundOpacity = 50
prefs.rulerColor = Prefs.defaultRulerFillColor
prefs.unit = .pixels
prefs.zeroCorner = .topLeft
}

func createRulersIfNeeded() {
Expand Down
12 changes: 11 additions & 1 deletion Free Ruler/Prefs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Prefs: NSObject {
@objc dynamic var backgroundOpacity : Int
@objc dynamic var rulerColor : NSColor
@objc dynamic var unit : Unit
@objc dynamic var zeroCorner : ZeroCorner

// MARK: - public save method
func save() {
Expand All @@ -58,7 +59,8 @@ class Prefs: NSObject {
"rulerShadow": false,
"foregroundOpacity": 90,
"backgroundOpacity": 50,
"unit": Unit.pixels.rawValue
"unit": Unit.pixels.rawValue,
"zeroCorner": ZeroCorner.topLeft.rawValue
]

if let defaultRulerColorData = Prefs.defaultRulerColorData {
Expand All @@ -78,6 +80,7 @@ class Prefs: NSObject {
backgroundOpacity = defaults.integer(forKey: "backgroundOpacity")
rulerColor = Prefs.rulerFillColor(fromArchivedData: defaults.data(forKey: "rulerColor"))
unit = Unit(rawValue: defaults.integer(forKey: "unit")) ?? .pixels
zeroCorner = Prefs.zeroCorner(fromRawValue: defaults.integer(forKey: "zeroCorner"))

super.init()

Expand Down Expand Up @@ -117,6 +120,9 @@ class Prefs: NSObject {
observe(\Prefs.unit, options: .new) { prefs, changed in
self.defaults.set(prefs.unit.rawValue, forKey: "unit")
},
observe(\Prefs.zeroCorner, options: .new) { prefs, changed in
self.defaults.set(prefs.zeroCorner.rawValue, forKey: "zeroCorner")
},
]
}

Expand All @@ -131,6 +137,10 @@ extension Prefs {
return normalizedRulerColor(unarchiveColor(data) ?? defaultRulerColor)
}

static func zeroCorner(fromRawValue rawValue: Int) -> ZeroCorner {
return ZeroCorner(rawValue: rawValue) ?? .topLeft
}

private static func archivedColorData(_ color: NSColor) -> Data? {
return try? NSKeyedArchiver.archivedData(
withRootObject: color,
Expand Down
7 changes: 7 additions & 0 deletions Free Ruler/Ruler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ enum Orientation: String {
case vertical
}

@objc enum ZeroCorner: Int {
case topLeft = 0
case topRight = 1
case bottomLeft = 2
case bottomRight = 3
}
Comment thread
Copilot marked this conversation as resolved.

class Ruler {
static let thickness: CGFloat = 40

Expand Down
65 changes: 65 additions & 0 deletions FreeRulerTests/RulerCoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,43 @@ final class RulerCoreTests: XCTestCase {
XCTAssertEqual(ruler.name, "test-ruler")
}

func testZeroCornerRawValuesPreservePersistedOrder() {
XCTAssertEqual(ZeroCorner.topLeft.rawValue, 0)
XCTAssertEqual(ZeroCorner.topRight.rawValue, 1)
XCTAssertEqual(ZeroCorner.bottomLeft.rawValue, 2)
XCTAssertEqual(ZeroCorner.bottomRight.rawValue, 3)
}

func testZeroCornerLoadsFromRawValue() {
XCTAssertEqual(Prefs.zeroCorner(fromRawValue: ZeroCorner.topLeft.rawValue), .topLeft)
XCTAssertEqual(Prefs.zeroCorner(fromRawValue: ZeroCorner.topRight.rawValue), .topRight)
XCTAssertEqual(Prefs.zeroCorner(fromRawValue: ZeroCorner.bottomLeft.rawValue), .bottomLeft)
XCTAssertEqual(Prefs.zeroCorner(fromRawValue: ZeroCorner.bottomRight.rawValue), .bottomRight)
}

func testZeroCornerDefaultsToTopLeftForUnknownRawValue() {
XCTAssertEqual(Prefs.zeroCorner(fromRawValue: -1), .topLeft)
XCTAssertEqual(Prefs.zeroCorner(fromRawValue: 99), .topLeft)
}

func testZeroCornerPreferencePersistsToUserDefaults() {
withRestoredZeroCornerPreference {
prefs.zeroCorner = .bottomRight

XCTAssertEqual(
UserDefaults.standard.integer(forKey: "zeroCorner"),
ZeroCorner.bottomRight.rawValue
)

prefs.zeroCorner = .topRight

XCTAssertEqual(
UserDefaults.standard.integer(forKey: "zeroCorner"),
ZeroCorner.topRight.rawValue
)
}
}

func testMinAndMaxSizesMatchRulerOrientation() {
let horizontal = Ruler(.horizontal, frame: NSRect(x: 0, y: 0, width: 300, height: 40))
let vertical = Ruler(.vertical, frame: NSRect(x: 0, y: 0, width: 40, height: 300))
Expand Down Expand Up @@ -706,6 +743,34 @@ final class RulerCoreTests: XCTestCase {

try test()
}

private func withRestoredZeroCornerPreference(_ test: () throws -> Void) rethrows {
let defaults = UserDefaults.standard
let previousZeroCorner = prefs.zeroCorner
let domainName = Bundle.main.bundleIdentifier
let previousDomainValue = domainName
.flatMap { defaults.persistentDomain(forName: $0)?["zeroCorner"] }

defer {
prefs.zeroCorner = previousZeroCorner

if let domainName = domainName {
var domain = defaults.persistentDomain(forName: domainName) ?? [:]
if let previousDomainValue = previousDomainValue {
domain["zeroCorner"] = previousDomainValue
} else {
domain.removeValue(forKey: "zeroCorner")
}
defaults.setPersistentDomain(domain, forName: domainName)
} else {
if previousDomainValue == nil {
defaults.removeObject(forKey: "zeroCorner")
}
}
}

try test()
}
}

private final class ChildAttachingRulerWindow: RulerWindow {
Expand Down