diff --git a/Free Ruler/AppDelegate.swift b/Free Ruler/AppDelegate.swift index a6ae4af..560f2b4 100644 --- a/Free Ruler/AppDelegate.swift +++ b/Free Ruler/AppDelegate.swift @@ -794,6 +794,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { updateMouseTickTimer() } + @IBAction func cycleRulers(_ sender: Any) { + guard rulerManager.cycleActiveRuler() != nil else { return } + + updateDisplay() + } + @IBAction func closeKeyWindow(_ sender: Any) { if let controller = rulerManager.controller(containing: NSApp.keyWindow) { rulerManager.close(controller) @@ -872,10 +878,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { applyRulerWindowMode() } - @IBAction func showRulers(_ sender: Any) { - showRulers() - } - @IBAction func toggleHorizontalRuler(_ sender: Any) { toggleRuler(orientation: .horizontal) } @@ -1019,6 +1021,17 @@ class AppDelegate: NSObject, NSApplicationDelegate { return true } + if keyboardModifiers == .command { + switch keyCode { + case kVK_ANSI_Grave: + cycleRulers(sender) + default: + return false + } + + return true + } + guard keyboardModifiers.isEmpty else { return false } switch keyCode { @@ -1145,9 +1158,6 @@ extension AppDelegate: NSMenuItemValidation { ? NSLocalizedString("Hide Vertical Ruler", comment: "Menu item title to hide the vertical ruler") : NSLocalizedString("Show Vertical Ruler", comment: "Menu item title to show the vertical ruler") return canToggleRulerVisibility - case #selector(showRulers(_:)): - menuItem.title = NSLocalizedString("Show All Rulers", comment: "Menu item title to show all ruler windows") - return true default: return true } diff --git a/Free Ruler/Base.lproj/MainMenu.xib b/Free Ruler/Base.lproj/MainMenu.xib index 45df119..22d6e07 100644 --- a/Free Ruler/Base.lproj/MainMenu.xib +++ b/Free Ruler/Base.lproj/MainMenu.xib @@ -98,12 +98,6 @@ - - - - - - diff --git a/Free Ruler/GroupedRulerWindow.swift b/Free Ruler/GroupedRulerWindow.swift index 7615371..21f81a1 100644 --- a/Free Ruler/GroupedRulerWindow.swift +++ b/Free Ruler/GroupedRulerWindow.swift @@ -1760,6 +1760,24 @@ final class RulerManager { } } + @discardableResult + func cycleActiveRuler() -> GroupedRulerController? { + let visibleControllers = controllers.filter(\.isVisible) + guard !visibleControllers.isEmpty else { return nil } + + let activeID = activeController?.state.id + let activeIndex = activeID.flatMap { activeID in + visibleControllers.firstIndex { $0.state.id == activeID } + } + let nextIndex = activeIndex.map { ($0 + 1) % visibleControllers.count } ?? 0 + let nextController = visibleControllers[nextIndex] + + markActive(nextController) + nextController.groupedWindow.orderFrontRegardless() + nextController.groupedWindow.makeKey() + return nextController + } + @discardableResult func closeActiveRuler() -> Bool { guard let activeController = activeController else { return false } diff --git a/Free Ruler/Localizable.xcstrings b/Free Ruler/Localizable.xcstrings index 1cf1b8e..b6c2d2a 100644 --- a/Free Ruler/Localizable.xcstrings +++ b/Free Ruler/Localizable.xcstrings @@ -887,48 +887,6 @@ } } }, - "Show All Rulers" : { - "comment" : "Menu item title to show all ruler windows", - "extractionState" : "manual", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Alle Lineale anzeigen" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Show All Rulers" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Mostrar todas las reglas" - } - }, - "fi" : { - "stringUnit" : { - "state" : "translated", - "value" : "Näytä kaikki viivaimet" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "すべての定規を表示" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "显示所有标尺" - } - } - } - }, "Show Horizontal Ruler" : { "comment" : "Menu item title to show the horizontal ruler", "extractionState" : "manual", diff --git a/FreeRulerTests/RulerCoreTests.swift b/FreeRulerTests/RulerCoreTests.swift index 594574c..d4cae43 100644 --- a/FreeRulerTests/RulerCoreTests.swift +++ b/FreeRulerTests/RulerCoreTests.swift @@ -240,6 +240,27 @@ final class RulerCoreTests: XCTestCase { } } + func testRulerManagerCyclesVisibleRulers() { + let manager = RulerManager() + let first = manager.createRuler() + let second = manager.createRuler() + let hidden = manager.createRuler() + defer { + first.hide() + second.hide() + hidden.hide() + } + first.show() + second.show() + manager.markActive(first) + + XCTAssertTrue(manager.cycleActiveRuler() === second) + XCTAssertTrue(manager.activeController === second) + + XCTAssertTrue(manager.cycleActiveRuler() === first) + XCTAssertTrue(manager.activeController === first) + } + func testRulerContextMenuActivatesClickedRulerAndShowsSettingsCommand() { withInstalledAppDelegate { appDelegate in let manager = appDelegate.rulerManager @@ -3412,6 +3433,29 @@ final class RulerCoreTests: XCTestCase { } } + func testCommandGraveCyclesManagedRulers() { + let appDelegate = AppDelegate() + let first = appDelegate.rulerManager.createRuler() + let second = appDelegate.rulerManager.createRuler() + defer { + first.hide() + second.hide() + } + first.show() + second.show() + appDelegate.rulerManager.markActive(first) + + XCTAssertTrue( + appDelegate.performRulerHotkey( + keyCode: kVK_ANSI_Grave, + modifierFlags: .command, + sender: first + ) + ) + + XCTAssertTrue(appDelegate.rulerManager.activeController === second) + } + func testManagedWingHotkeysAffectOnlyActiveRuler() { let appDelegate = AppDelegate() let first = appDelegate.rulerManager.createRuler()