Skip to content

Conversation

@rgeraskin
Copy link
Contributor

Add Layouts Submenu to Application Menu

Description

This PR introduces a new layouts submenu in the application menu, providing users with quick access to layout options directly from the menu bar.

Closes: #1080

Changes Made

  • AppDelegate.swift: Added 87 lines of code to implement the layouts submenu functionality
  • MainMenu.xib: Updated the interface builder file to include the new submenu structure

What's New

  • ✨ New layouts submenu in the application menu
  • 🎯 Enhanced user experience with easier layout access
  • 📱 Improved menu navigation for layout management

Files Modified

  • Amethyst/AppDelegate.swift (+87 lines)
  • Amethyst/Base.lproj/MainMenu.xib (+7 lines)

@rgeraskin
Copy link
Contributor Author

rebased on development branch

currentLayoutKey = firstScreenManager.currentLayout?.layoutKey
}

// Filter to only enabled layouts and add menu items
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic isn't quite correct because it is technically possible for there to be multiple instances of the same layout in a space.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Added currentLayoutIndexValue property to ScreenManager to expose the current layout index. The menu now compares by index instead of by layoutKey:

  • Before: currentLayout?.layoutKey == layoutKey (would checkmark ALL instances of same layout type)
  • After: index == currentLayoutIndex (only checkmarks the specific instance)

This correctly handles configurations like [Tall, Wide, Tall] where only the active instance shows a checkmark.

- Populate layouts menu when main menu opens (not submenu)
- Add screen detection fallback using mouse cursor position
- Show error placeholder only when no screen manager available
- Move empty layouts check before loop with early return
- Fix multiple layout instances by comparing index instead of key
- Add currentLayoutIndexValue property to ScreenManager
Copy link
Owner

@ianyh ianyh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point about the layout instances is that we probably want this to be derived from the actual list of layouts in the screen manager.

let amScreen = AMScreen(screen: nsScreen)
return windowManager?.screenManager(for: amScreen)
}
return windowManager?.screenManager(at: 0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just return nil here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the screenManager(at: 0) fallback. Now returns nil if both focusedScreenManager() and mouse cursor screen detection fail, which will show the error placeholder.

- Add layoutsInfo property to ScreenManager to expose actual layouts
- Remove screenManager(at: 0) fallback, return nil instead
- Use screen manager's layouts for menu instead of UserConfiguration
- Ensures indices match correctly for current layout detection
@rgeraskin
Copy link
Contributor Author

My point about the layout instances is that we probably want this to be derived from the actual list of layouts in the screen manager.

Refactored to derive the menu from the screen manager's actual layouts instead of the global UserConfiguration.shared.layoutKeys():

  • Added layoutsInfo property to ScreenManager that exposes the layouts array as [(key: String, name: String)]
  • populateLayoutsMenu() now iterates over screenManager.layoutsInfo instead of global config
  • This ensures indices match correctly since both menu items and currentLayoutIndex come from the same source
// Before: used global config (indices might not match screen manager)
let enabledLayoutKeys = UserConfiguration.shared.layoutKeys()
for (index, layoutKey) in enabledLayoutKeys.enumerated() { ... }
// After: derived from screen manager's actual layouts
let layouts = screenManager.layoutsInfo
for (index, layoutInfo) in layouts.enumerated() { ... }

Copy link
Owner

@ianyh ianyh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment, but otherwise I think it looks good.

Comment on lines 59 to 67
/// The index of the current layout in the layouts array
var currentLayoutIndexValue: Int {
return currentLayoutIndex
}

/// Returns layout info (key and name) for all layouts in this screen manager
var layoutsInfo: [(key: String, name: String)] {
return layouts.map { (key: $0.layoutKey, name: $0.layoutName) }
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Could you change layoutsInfo to use a defined struct type instead of the named tuple?
  • Could you include whether or not it is the selected layout in that struct instead of exposing the index separately above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

- Add LayoutMenuItemInfo struct with key, name, and isSelected properties
- Remove currentLayoutIndexValue property from ScreenManager
- Encapsulate selection logic in layoutsInfo property
- Simplify AppDelegate menu population loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make Layouts available from menus

2 participants