From 4e9fef02a574f16bb6fe3f7cef4f967e009d2a5d Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 18 Jun 2026 20:48:55 +0800
Subject: [PATCH] Add App Shelf index markers

---
 C1.source/Sources/Aligner/AlignerApplicationDelegate.swift |  197 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 184 insertions(+), 13 deletions(-)

diff --git a/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift b/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
index ad68641..4ada6fd 100644
--- a/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
+++ b/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
@@ -20,10 +20,11 @@
     private var round1TriggerProbe: CGEventTapTriggerProbe?
     private var quickSwitchSessionController: QuickSwitchSessionController?
     private var quickSwitchTriggerService: CGEventTapTriggerService?
+    private var settingsWindowController: SettingsWindowController?
     private var isRunningQuickSwitchLifecycle = false
     private var statusItem: NSStatusItem?
-    private var verticalWaterfallViewModeMenuItem: NSMenuItem?
-    private var horizontalWaterfallViewModeMenuItem: NSMenuItem?
+    private var verticalWaterfallViewModeMenuItems: [NSMenuItem] = []
+    private var horizontalWaterfallViewModeMenuItems: [NSMenuItem] = []
 
     func applicationDidFinishLaunching(_ notification: Notification) {
         let bundlePathSummary = DevelopmentDiagnostics.pathSummary(Bundle.main.bundlePath)
@@ -47,6 +48,7 @@
             return
         }
 
+        configureMainMenu()
         configureStatusItem()
         if !launchOptions.skipPermissions {
             showPermissionsIfNeeded()
@@ -96,8 +98,9 @@
         let menu = NSMenu()
         menu.delegate = self
         menu.addItem(menuItem(title: "About Aligner...", action: #selector(showAbout), keyEquivalent: ""))
+        menu.addItem(menuItem(title: "Settings...", action: #selector(showSettingsFromMenu), keyEquivalent: ""))
         menu.addItem(.separator())
-        menu.addItem(menuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ","))
+        menu.addItem(menuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ""))
         menu.addItem(.separator())
         menu.addItem(menuItem(title: "Show Quick Switch", action: #selector(showQuickSwitchFromMenu), keyEquivalent: ""))
         menu.addItem(menuItem(title: "Hide Quick Switch", action: #selector(hideQuickSwitchFromMenu), keyEquivalent: ""))
@@ -114,8 +117,70 @@
         DevelopmentDiagnostics.log("app.statusItem.configure.end", [
             "hasButton": item.button != nil,
             "hasAboutItem": true,
-            "hasWaterfallViewModeItems": verticalWaterfallViewModeMenuItem != nil
-                && horizontalWaterfallViewModeMenuItem != nil
+            "hasSettingsItem": true,
+            "hasWaterfallViewModeItems": !verticalWaterfallViewModeMenuItems.isEmpty
+                && !horizontalWaterfallViewModeMenuItems.isEmpty
+        ])
+    }
+
+    private func configureMainMenu() {
+        DevelopmentDiagnostics.log("app.mainMenu.configure.start")
+
+        let mainMenu = NSMenu(title: "Main Menu")
+        let appMenuItem = NSMenuItem(title: "Aligner", action: nil, keyEquivalent: "")
+        let appMenu = NSMenu(title: "Aligner")
+        appMenu.delegate = self
+        appMenuItem.submenu = appMenu
+        appMenu.addItem(menuItem(title: "About Aligner...", action: #selector(showAbout), keyEquivalent: ""))
+        appMenu.addItem(.separator())
+        appMenu.addItem(menuItem(title: "Settings...", action: #selector(showSettingsFromMenu), keyEquivalent: ","))
+        appMenu.addItem(.separator())
+        appMenu.addItem(menuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ""))
+        appMenu.addItem(menuItem(title: "Show Quick Switch", action: #selector(showQuickSwitchFromMenu), keyEquivalent: ""))
+        appMenu.addItem(menuItem(title: "Hide Quick Switch", action: #selector(hideQuickSwitchFromMenu), keyEquivalent: ""))
+        appMenu.addItem(quickSwitchViewModeMenuItem())
+        appMenu.addItem(.separator())
+        appMenu.addItem(menuItem(title: "Quit Aligner", action: #selector(quit), keyEquivalent: "q"))
+        mainMenu.addItem(appMenuItem)
+
+        let editMenuItem = NSMenuItem(title: "Edit", action: nil, keyEquivalent: "")
+        let editMenu = NSMenu(title: "Edit")
+        editMenuItem.submenu = editMenu
+        editMenu.addItem(responderMenuItem(title: "Undo", action: Selector(("undo:")), keyEquivalent: "z"))
+        editMenu.addItem(responderMenuItem(title: "Redo", action: Selector(("redo:")), keyEquivalent: "Z"))
+        editMenu.addItem(.separator())
+        editMenu.addItem(responderMenuItem(title: "Cut", action: #selector(NSText.cut(_:)), keyEquivalent: "x"))
+        editMenu.addItem(responderMenuItem(title: "Copy", action: #selector(NSText.copy(_:)), keyEquivalent: "c"))
+        editMenu.addItem(responderMenuItem(title: "Paste", action: #selector(NSText.paste(_:)), keyEquivalent: "v"))
+        editMenu.addItem(responderMenuItem(title: "Select All", action: #selector(NSText.selectAll(_:)), keyEquivalent: "a"))
+        mainMenu.addItem(editMenuItem)
+
+        let viewMenuItem = NSMenuItem(title: "View", action: nil, keyEquivalent: "")
+        let viewMenu = NSMenu(title: "View")
+        viewMenu.delegate = self
+        viewMenuItem.submenu = viewMenu
+        viewMenu.addItem(quickSwitchViewModeMenuItem())
+        mainMenu.addItem(viewMenuItem)
+
+        let windowMenuItem = NSMenuItem(title: "Window", action: nil, keyEquivalent: "")
+        let windowMenu = NSMenu(title: "Window")
+        windowMenuItem.submenu = windowMenu
+        windowMenu.addItem(responderMenuItem(title: "Minimize", action: #selector(NSWindow.performMiniaturize(_:)), keyEquivalent: "m"))
+        windowMenu.addItem(responderMenuItem(title: "Zoom", action: #selector(NSWindow.performZoom(_:)), keyEquivalent: ""))
+        windowMenu.addItem(.separator())
+        windowMenu.addItem(responderMenuItem(title: "Bring All to Front", action: #selector(NSApplication.arrangeInFront(_:)), keyEquivalent: ""))
+        mainMenu.addItem(windowMenuItem)
+        NSApp.windowsMenu = windowMenu
+
+        let helpMenuItem = NSMenuItem(title: "Help", action: nil, keyEquivalent: "")
+        helpMenuItem.submenu = NSMenu(title: "Help")
+        mainMenu.addItem(helpMenuItem)
+
+        NSApp.mainMenu = mainMenu
+        updateWaterfallViewModeMenuState()
+        DevelopmentDiagnostics.log("app.mainMenu.configure.end", [
+            "hasSettingsItem": appMenu.item(withTitle: "Settings...") != nil,
+            "hasQuickSwitchViewSubmenu": appMenu.item(withTitle: "Quick Switch View")?.submenu != nil
         ])
     }
 
@@ -127,6 +192,10 @@
         let item = NSMenuItem(title: title, action: action, keyEquivalent: keyEquivalent)
         item.target = self
         return item
+    }
+
+    private func responderMenuItem(title: String, action: Selector?, keyEquivalent: String) -> NSMenuItem {
+        NSMenuItem(title: title, action: action, keyEquivalent: keyEquivalent)
     }
 
     private func quickSwitchViewModeMenuItem() -> NSMenuItem {
@@ -144,8 +213,8 @@
         submenu.addItem(verticalItem)
         submenu.addItem(horizontalItem)
 
-        verticalWaterfallViewModeMenuItem = verticalItem
-        horizontalWaterfallViewModeMenuItem = horizontalItem
+        verticalWaterfallViewModeMenuItems.append(verticalItem)
+        horizontalWaterfallViewModeMenuItems.append(horizontalItem)
 
         let rootItem = NSMenuItem(title: "Quick Switch View", action: nil, keyEquivalent: "")
         rootItem.submenu = submenu
@@ -154,8 +223,12 @@
 
     private func updateWaterfallViewModeMenuState() {
         let mode = quickSwitchWaterfallViewMode()
-        verticalWaterfallViewModeMenuItem?.state = mode == .verticalColumns ? .on : .off
-        horizontalWaterfallViewModeMenuItem?.state = mode == .horizontalMasonry ? .on : .off
+        for item in verticalWaterfallViewModeMenuItems {
+            item.state = mode == .verticalColumns ? .on : .off
+        }
+        for item in horizontalWaterfallViewModeMenuItems {
+            item.state = mode == .horizontalMasonry ? .on : .off
+        }
     }
 
     private func showPermissionsIfNeeded() {
@@ -421,6 +494,9 @@
             controller.onSnapshotUpdated = { [weak self] in
                 self?.writeQuickSwitchReportIfNeeded()
             }
+            controller.onToggleWaterfallViewMode = { [weak self] in
+                self?.toggleQuickSwitchWaterfallViewModeFromQuickSwitch()
+            }
             quickSwitchSessionController = controller
         }
 
@@ -497,6 +573,9 @@
             controller.onSnapshotUpdated = { [weak self] in
                 self?.writeQuickSwitchReportIfNeeded()
             }
+            controller.onToggleWaterfallViewMode = { [weak self] in
+                self?.toggleQuickSwitchWaterfallViewModeFromQuickSwitch()
+            }
             quickSwitchSessionController = controller
         }
 
@@ -531,6 +610,8 @@
         report["aboutVersion"] = versionBuild.version
         report["aboutBuild"] = versionBuild.build
         report["statusMenu"] = statusMenuReportDictionary()
+        report["mainMenu"] = mainMenuReportDictionary()
+        report["settingsWindow"] = settingsWindowReportDictionary()
 
         do {
             let data = try JSONSerialization.data(withJSONObject: report, options: [.prettyPrinted, .sortedKeys])
@@ -579,6 +660,14 @@
 
         if round1QuickSwitchOptions.fixtureSpaceFilter {
             return FixtureQuickSwitchSnapshotLoader(appCount: 1, mode: .spaceFilter)
+        }
+
+        if round1QuickSwitchOptions.fixtureSplitView {
+            return FixtureQuickSwitchSnapshotLoader(appCount: 1, mode: .splitView)
+        }
+
+        if round1QuickSwitchOptions.fixtureMultiPageIdentity {
+            return FixtureQuickSwitchSnapshotLoader(appCount: 1, mode: .multiPageIdentity)
         }
 
         if let fixtureAppCount = round1QuickSwitchOptions.fixtureAppCount {
@@ -652,11 +741,25 @@
         preferenceStore.write(updatedPreferences)
         quickSwitchSessionController?.setWaterfallViewMode(mode)
         updateWaterfallViewModeMenuState()
+        settingsWindowController?.refreshWaterfallViewMode()
         writeQuickSwitchReportIfNeeded()
         DevelopmentDiagnostics.log("app.quickSwitch.waterfallViewModePreferenceChanged", [
             "mode": mode.rawValue,
             "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false
         ])
+    }
+
+    private func toggleQuickSwitchWaterfallViewModeFromQuickSwitch() {
+        let currentMode = quickSwitchWaterfallViewMode()
+        let nextMode: QuickSwitchWaterfallViewMode = currentMode == .horizontalMasonry
+            ? .verticalColumns
+            : .horizontalMasonry
+        DevelopmentDiagnostics.log("app.quickSwitch.waterfallViewModeToggle", [
+            "currentMode": currentMode.rawValue,
+            "nextMode": nextMode.rawValue,
+            "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false
+        ])
+        setQuickSwitchWaterfallViewMode(nextMode)
     }
 
     private func appVersionBuild() -> (version: String, build: String) {
@@ -668,13 +771,44 @@
 
     private func statusMenuReportDictionary() -> [String: Any] {
         updateWaterfallViewModeMenuState()
+        let verticalItem = verticalWaterfallViewModeMenuItems.first
+        let horizontalItem = horizontalWaterfallViewModeMenuItems.first
         return [
             "hasAboutItem": statusItem?.menu?.item(withTitle: "About Aligner...") != nil,
+            "hasSettingsItem": statusItem?.menu?.item(withTitle: "Settings...") != nil,
             "hasQuickSwitchViewSubmenu": statusItem?.menu?.item(withTitle: "Quick Switch View")?.submenu != nil,
-            "hasVerticalColumnsItem": verticalWaterfallViewModeMenuItem != nil,
-            "hasHorizontalWaterfallItem": horizontalWaterfallViewModeMenuItem != nil,
-            "verticalColumnsState": verticalWaterfallViewModeMenuItem?.state == .on ? "on" : "off",
-            "horizontalWaterfallState": horizontalWaterfallViewModeMenuItem?.state == .on ? "on" : "off"
+            "hasVerticalColumnsItem": verticalItem != nil,
+            "hasHorizontalWaterfallItem": horizontalItem != nil,
+            "verticalColumnsState": verticalItem?.state == .on ? "on" : "off",
+            "horizontalWaterfallState": horizontalItem?.state == .on ? "on" : "off"
+        ]
+    }
+
+    private func mainMenuReportDictionary() -> [String: Any] {
+        updateWaterfallViewModeMenuState()
+        let appMenu = NSApp.mainMenu?.items.first?.submenu
+        let viewMenu = NSApp.mainMenu?.item(withTitle: "View")?.submenu
+        return [
+            "hasMenu": NSApp.mainMenu != nil,
+            "hasAppMenu": appMenu != nil,
+            "hasAboutItem": appMenu?.item(withTitle: "About Aligner...") != nil,
+            "hasSettingsItem": appMenu?.item(withTitle: "Settings...") != nil,
+            "settingsKeyEquivalent": appMenu?.item(withTitle: "Settings...")?.keyEquivalent ?? "",
+            "hasQuickSwitchViewSubmenuInAppMenu": appMenu?.item(withTitle: "Quick Switch View")?.submenu != nil,
+            "hasQuickSwitchViewSubmenuInViewMenu": viewMenu?.item(withTitle: "Quick Switch View")?.submenu != nil
+        ]
+    }
+
+    private func settingsWindowReportDictionary() -> [String: Any] {
+        settingsWindowController?.reportDictionary() ?? [
+            "exists": false,
+            "visible": false,
+            "title": "",
+            "selectedTabLabel": "",
+            "selectedTabIdentifier": "",
+            "waterfallViewMode": quickSwitchWaterfallViewMode().rawValue,
+            "hasViewTab": false,
+            "usesSwiftUI": false
         ]
     }
 
@@ -696,6 +830,43 @@
         alert.runModal()
     }
 
+    @objc private func showSettingsFromMenu() {
+        openSettingsWindow(source: "menu")
+    }
+
+    private func showSettingsFromQuickSwitch() {
+        openSettingsWindow(source: "quickSwitch")
+    }
+
+    private func openSettingsWindow(source: String) {
+        DevelopmentDiagnostics.log("app.settings.show", [
+            "source": source,
+            "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false,
+            "mode": quickSwitchWaterfallViewMode().rawValue
+        ])
+        hideQuickSwitchSession(reason: .userClosed)
+        NSApp.setActivationPolicy(.regular)
+
+        if settingsWindowController == nil {
+            settingsWindowController = SettingsWindowController(
+                modeProvider: { [weak self] in
+                    self?.quickSwitchWaterfallViewMode() ?? .verticalColumns
+                },
+                onWaterfallViewModeChanged: { [weak self] mode in
+                    self?.setQuickSwitchWaterfallViewMode(mode)
+                }
+            )
+        }
+
+        settingsWindowController?.showWindow(nil)
+        NSApp.activate(ignoringOtherApps: true)
+        writeQuickSwitchReportIfNeeded()
+        DevelopmentDiagnostics.log("app.settings.windowShown", [
+            "windowVisible": settingsWindowController?.window?.isVisible ?? false,
+            "activationPolicy": NSApp.activationPolicy().rawValue
+        ])
+    }
+
     @objc private func useVerticalWaterfallViewMode() {
         setQuickSwitchWaterfallViewMode(.verticalColumns)
     }

--
Gitblit v1.9.3