From 4b03917b1fb8279f1027d8e0265a1ee1b79d58f8 Mon Sep 17 00:00:00 2001 From: Pascal Date: Wed, 17 Jun 2026 01:31:47 -0400 Subject: [PATCH] Make grouped ruler windows primary --- Free Ruler/AppDelegate.swift | 13 +++++++ Free Ruler/GroupedRulerWindow.swift | 4 +-- Free Ruler/Localizable.xcstrings | 6 ++-- FreeRulerTests/RulerCoreTests.swift | 53 +++++++++++++++++++++++++++-- 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/Free Ruler/AppDelegate.swift b/Free Ruler/AppDelegate.swift index 204472a..f5ce1a4 100644 --- a/Free Ruler/AppDelegate.swift +++ b/Free Ruler/AppDelegate.swift @@ -373,6 +373,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { } func toggleRuler(orientation: Orientation) { + if !rulerManager.hasRulers && rulers.isEmpty { + createRulersIfNeeded() + } + if rulerManager.hasRulers { let controller = rulerManager.activeController ?? rulerManager.createRuler() controller.toggleWing(orientation) @@ -635,6 +639,8 @@ class AppDelegate: NSObject, NSApplicationDelegate { } @IBAction func toggleGroupRulers(_ sender: Any) { + guard !rulerManager.hasRulers else { return } + prefs.groupRulers = !prefs.groupRulers showGroupRulersHotkeyBezel(on: bezelScreen(for: sender)) } @@ -770,6 +776,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { } func flipRulers(along orientation: Orientation) { + if !rulerManager.hasRulers && rulers.isEmpty { + createRulersIfNeeded() + } + if let controller = rulerManager.activeController { let flippedCorner = prefs.zeroCorner.flipped(along: orientation) controller.prepareForZeroCornerChange(to: flippedCorner) @@ -893,6 +903,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { case kVK_ANSI_F: toggleFloatRulers(sender) case kVK_ANSI_G: + guard !rulerManager.hasRulers else { return true } toggleGroupRulers(sender) case kVK_ANSI_S: toggleRulerShadow(sender) @@ -974,6 +985,8 @@ extension AppDelegate: NSMenuItemValidation { return true case #selector(closeKeyWindow(_:)): return NSApp.keyWindow?.isVisible == true + case #selector(toggleGroupRulers(_:)): + return !rulerManager.hasRulers case #selector(toggleHorizontalRuler(_:)): if let controller = rulerManager.activeController { menuItem.title = controller.state.isWingVisible(.horizontal) diff --git a/Free Ruler/GroupedRulerWindow.swift b/Free Ruler/GroupedRulerWindow.swift index 0fca3e8..d85f3fc 100644 --- a/Free Ruler/GroupedRulerWindow.swift +++ b/Free Ruler/GroupedRulerWindow.swift @@ -296,8 +296,8 @@ final class GroupedRulerWindow: NSPanel { alphaValue = windowAlphaValue(prefs.foregroundOpacity) title = NSLocalizedString( - "Grouped Rulers", - comment: "Window title for the grouped ruler window" + "Ruler", + comment: "Window title for a ruler window" ) identifier = NSUserInterfaceItemIdentifier("grouped-ruler-window") setAccessibilityIdentifier("grouped-ruler-window") diff --git a/Free Ruler/Localizable.xcstrings b/Free Ruler/Localizable.xcstrings index 71f2872..0d6e296 100644 --- a/Free Ruler/Localizable.xcstrings +++ b/Free Ruler/Localizable.xcstrings @@ -43,14 +43,14 @@ } } }, - "Grouped Rulers" : { - "comment" : "Window title for the grouped ruler window", + "Ruler" : { + "comment" : "Window title for a ruler window", "extractionState" : "manual", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "Grouped Rulers" + "value" : "Ruler" } } } diff --git a/FreeRulerTests/RulerCoreTests.swift b/FreeRulerTests/RulerCoreTests.swift index 12d23e5..afcc7bb 100644 --- a/FreeRulerTests/RulerCoreTests.swift +++ b/FreeRulerTests/RulerCoreTests.swift @@ -2138,7 +2138,7 @@ final class RulerCoreTests: XCTestCase { } } - func testGroupedRulerHotkeysToggleLegVisibilityWithoutUngrouping() { + func testPrimaryGroupedRulerHotkeysToggleLegVisibilityWithoutLegacyWindows() { withRestoredZeroCornerPreference { let previousGroupRulers = prefs.groupRulers defer { prefs.groupRulers = previousGroupRulers } @@ -2159,12 +2159,59 @@ final class RulerCoreTests: XCTestCase { XCTAssertTrue(prefs.groupRulers) XCTAssertFalse(groupedWindow?.isRuleVisible(.horizontal) ?? true) XCTAssertTrue(groupedWindow?.isRuleVisible(.vertical) ?? false) - XCTAssertFalse(appDelegate.rulers.first { $0.ruler.orientation == .horizontal }?.rulerWindow.isVisible ?? true) - XCTAssertFalse(appDelegate.rulers.first { $0.ruler.orientation == .vertical }?.rulerWindow.isVisible ?? true) + XCTAssertTrue(appDelegate.rulers.isEmpty) groupedWindow?.orderOut(self) } } + func testManagedGroupHotkeyDoesNotToggleRetiredGroupedMode() { + withRestoredZeroCornerPreference { + let previousGroupRulers = prefs.groupRulers + defer { prefs.groupRulers = previousGroupRulers } + + prefs.groupRulers = true + let appDelegate = AppDelegate() + appDelegate.showRulers() + + XCTAssertTrue( + appDelegate.performRulerHotkey( + keyCode: kVK_ANSI_G, + modifierFlags: [], + sender: appDelegate.groupedRulerController! + ) + ) + + XCTAssertTrue(prefs.groupRulers) + XCTAssertEqual(appDelegate.rulerManager.controllers.count, 1) + appDelegate.groupedRulerController?.hide() + } + } + + func testManagedWingHotkeysAffectOnlyActiveRuler() { + let appDelegate = AppDelegate() + let first = appDelegate.rulerManager.createRuler() + let second = appDelegate.rulerManager.createRuler() + defer { + first.hide() + second.hide() + } + + appDelegate.rulerManager.markActive(first) + + XCTAssertTrue( + appDelegate.performRulerHotkey( + keyCode: kVK_ANSI_H, + modifierFlags: [], + sender: first + ) + ) + + XCTAssertFalse(first.groupedWindow.isRuleVisible(.horizontal)) + XCTAssertTrue(first.groupedWindow.isRuleVisible(.vertical)) + XCTAssertTrue(second.groupedWindow.isRuleVisible(.horizontal)) + XCTAssertTrue(second.groupedWindow.isRuleVisible(.vertical)) + } + func testUngroupedHorizontalFlipDoesNotMoveRulerWindows() { withRestoredZeroCornerPreference { let previousGroupRulers = prefs.groupRulers