diff --git a/v2/internal/app/desktop.go b/v2/internal/app/desktop.go index 3f89c36da..3629cc998 100644 --- a/v2/internal/app/desktop.go +++ b/v2/internal/app/desktop.go @@ -6,6 +6,7 @@ import ( "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/ffenestri" "github.com/wailsapp/wails/v2/internal/logger" + "github.com/wailsapp/wails/v2/internal/menumanager" "github.com/wailsapp/wails/v2/internal/messagedispatcher" "github.com/wailsapp/wails/v2/internal/runtime" "github.com/wailsapp/wails/v2/internal/servicebus" @@ -33,6 +34,8 @@ type App struct { contextmenus *subsystem.ContextMenus dispatcher *messagedispatcher.Dispatcher + menuManager *menumanager.Manager + // Indicates if the app is in debug mode debug bool @@ -54,13 +57,18 @@ func CreateApp(appoptions *options.App) (*App, error) { myLogger := logger.New(appoptions.Logger) myLogger.SetLogLevel(appoptions.LogLevel) - window := ffenestri.NewApplicationWithConfig(appoptions, myLogger) + // Create the menu manager + menuManager := menumanager.NewManager() + menuManager.SetApplicationMenu(options.GetApplicationMenu(appoptions)) + + window := ffenestri.NewApplicationWithConfig(appoptions, myLogger, menuManager) result := &App{ - window: window, - servicebus: servicebus.New(myLogger), - logger: myLogger, - bindings: binding.NewBindings(myLogger), + window: window, + servicebus: servicebus.New(myLogger), + logger: myLogger, + bindings: binding.NewBindings(myLogger), + menuManager: menuManager, } result.options = appoptions @@ -157,7 +165,7 @@ func (a *App) Run() error { // Optionally start the menu subsystem if applicationMenu != nil { - menusubsystem, err := subsystem.NewMenu(applicationMenu, a.servicebus, a.logger) + menusubsystem, err := subsystem.NewMenu(a.servicebus, a.logger, a.menuManager) if err != nil { return err } diff --git a/v2/internal/ffenestri/ffenestri.go b/v2/internal/ffenestri/ffenestri.go index e1536cfca..0cfe01a47 100644 --- a/v2/internal/ffenestri/ffenestri.go +++ b/v2/internal/ffenestri/ffenestri.go @@ -2,6 +2,7 @@ package ffenestri import ( "encoding/json" + "github.com/wailsapp/wails/v2/internal/menumanager" "github.com/wailsapp/wails/v2/pkg/menu" "runtime" "strings" @@ -35,6 +36,9 @@ type Application struct { // This is the main app pointer app unsafe.Pointer + // Manages menus + menuManager *menumanager.Manager + // Logger logger logger.CustomLogger } @@ -54,10 +58,11 @@ func init() { } // NewApplicationWithConfig creates a new application based on the given config -func NewApplicationWithConfig(config *options.App, logger *logger.Logger) *Application { +func NewApplicationWithConfig(config *options.App, logger *logger.Logger, menuManager *menumanager.Manager) *Application { return &Application{ - config: config, - logger: logger.CustomLogger("Ffenestri"), + config: config, + logger: logger.CustomLogger("Ffenestri"), + menuManager: menuManager, } } diff --git a/v2/internal/ffenestri/ffenestri_darwin.go b/v2/internal/ffenestri/ffenestri_darwin.go index 11c797b4e..5f3e59d65 100644 --- a/v2/internal/ffenestri/ffenestri_darwin.go +++ b/v2/internal/ffenestri/ffenestri_darwin.go @@ -76,23 +76,10 @@ func (a *Application) processPlatformSettings() error { } // Process menu - applicationMenu := options.GetApplicationMenu(a.config) - if applicationMenu != nil { - - /* - As radio groups need to be manually managed on OSX, - we preprocess the menu to determine the radio groups. - This is defined as any adjacent menu item of type "RadioType". - We keep a record of every radio group member we discover by saving - a list of all members of the group and the number of members - in the group (this last one is for optimisation at the C layer). - */ - processedMenu := NewProcessedMenu(applicationMenu) - applicationMenuJSON, err := json.Marshal(processedMenu) - if err != nil { - return err - } - C.SetMenu(a.app, a.string2CString(string(applicationMenuJSON))) + //applicationMenu := options.GetApplicationMenu(a.config) + applicationMenu := a.menuManager.GetApplicationMenuJSON() + if applicationMenu != "" { + C.SetMenu(a.app, a.string2CString(applicationMenu)) } // Process tray diff --git a/v2/internal/menumanager/menuitemmap.go b/v2/internal/menumanager/menuitemmap.go new file mode 100644 index 000000000..923e0281a --- /dev/null +++ b/v2/internal/menumanager/menuitemmap.go @@ -0,0 +1,54 @@ +package menumanager + +import ( + "fmt" + "github.com/wailsapp/wails/v2/pkg/menu" +) + +// MenuItemMap holds a mapping between menuIDs and menu items +type MenuItemMap struct { + idToMenuItemMap map[string]*menu.MenuItem + menuItemToIDMap map[*menu.MenuItem]string +} + +func NewMenuItemMap() *MenuItemMap { + result := &MenuItemMap{ + idToMenuItemMap: make(map[string]*menu.MenuItem), + menuItemToIDMap: make(map[*menu.MenuItem]string), + } + + return result +} + +func (m *MenuItemMap) AddMenu(menu *menu.Menu) { + for _, item := range menu.Items { + m.processMenuItem(item) + } +} + +func (m *MenuItemMap) Dump() { + println("idToMenuItemMap:") + for key, value := range m.idToMenuItemMap { + fmt.Printf(" %s\t%p\n", key, value) + } + println("\nmenuItemToIDMap") + for key, value := range m.menuItemToIDMap { + fmt.Printf(" %p\t%s\n", key, value) + } +} + +func (m *MenuItemMap) processMenuItem(item *menu.MenuItem) { + + if item.SubMenu != nil { + for _, submenuitem := range item.SubMenu.Items { + m.processMenuItem(submenuitem) + } + } + + // Create a unique ID for this menu item + menuID := fmt.Sprintf("%d", len(m.idToMenuItemMap)) + + // Store references + m.idToMenuItemMap[menuID] = item + m.menuItemToIDMap[item] = menuID +} diff --git a/v2/internal/menumanager/menumanager.go b/v2/internal/menumanager/menumanager.go new file mode 100644 index 000000000..b9b372e3b --- /dev/null +++ b/v2/internal/menumanager/menumanager.go @@ -0,0 +1,82 @@ +package menumanager + +import ( + "fmt" + "github.com/wailsapp/wails/v2/pkg/menu" +) + +type Manager struct { + + // The application menu. + applicationMenu *menu.Menu + applicationMenuJSON string + + // Our menu mappings + menuItemMap *MenuItemMap +} + +func NewManager() *Manager { + return &Manager{ + menuItemMap: NewMenuItemMap(), + } +} + +func (m *Manager) SetApplicationMenu(applicationMenu *menu.Menu) error { + if applicationMenu == nil { + return nil + } + m.applicationMenu = applicationMenu + m.menuItemMap.AddMenu(applicationMenu) + return m.processApplicationMenu() +} + +func (m *Manager) GetApplicationMenuJSON() string { + return m.applicationMenuJSON +} + +func (m *Manager) processApplicationMenu() error { + + // Process the menu + processedApplicationMenu := m.NewWailsMenu(m.applicationMenu) + applicationMenuJSON, err := processedApplicationMenu.AsJSON() + if err != nil { + return err + } + m.applicationMenuJSON = applicationMenuJSON + return nil +} + +func (m *Manager) getMenuItemByID(menuId string) *menu.MenuItem { + return m.menuItemMap.idToMenuItemMap[menuId] +} + +func (m *Manager) ProcessClick(menuID string) error { + + // Get the menu item + menuItem := m.getMenuItemByID(menuID) + if menuItem == nil { + return fmt.Errorf("Cannot process menuid %s - unknown", menuID) + } + + // Is the menu item a checkbox? + if menuItem.Type == menu.CheckboxType { + // Toggle state + menuItem.Checked = !menuItem.Checked + } + + if menuItem.Click == nil { + // No callback + return fmt.Errorf("No callback for menu '%s'", menuItem.Label) + } + + // Create new Callback struct + callbackData := &menu.CallbackData{ + MenuItem: menuItem, + ContextData: "", + } + + // Call back! + go menuItem.Click(callbackData) + + return nil +} diff --git a/v2/internal/menumanager/processedMenu.go b/v2/internal/menumanager/processedMenu.go new file mode 100644 index 000000000..293796c92 --- /dev/null +++ b/v2/internal/menumanager/processedMenu.go @@ -0,0 +1,156 @@ +package menumanager + +import ( + "encoding/json" + "github.com/wailsapp/wails/v2/pkg/menu" + "github.com/wailsapp/wails/v2/pkg/menu/keys" +) + +type ProcessedMenuItem struct { + ID string + // Label is what appears as the menu text + Label string + // Role is a predefined menu type + Role menu.Role `json:"Role,omitempty"` + // Accelerator holds a representation of a key binding + Accelerator *keys.Accelerator `json:"Accelerator,omitempty"` + // Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu + Type menu.Type + // Disabled makes the item unselectable + Disabled bool + // Hidden ensures that the item is not shown in the menu + Hidden bool + // Checked indicates if the item is selected (used by Checkbox and Radio types only) + Checked bool + // Submenu contains a list of menu items that will be shown as a submenu + //SubMenu []*MenuItem `json:"SubMenu,omitempty"` + SubMenu *ProcessedMenu `json:"SubMenu,omitempty"` + + // Foreground colour in hex RGBA format EG: 0xFF0000FF = #FF0000FF = red + Foreground int + + // Background colour + Background int +} + +func (m *Manager) NewProcessedMenuItem(menuItem *menu.MenuItem) *ProcessedMenuItem { + + ID := m.menuItemMap.menuItemToIDMap[menuItem] + result := &ProcessedMenuItem{ + ID: ID, + Label: menuItem.Label, + Role: menuItem.Role, + Accelerator: menuItem.Accelerator, + Type: menuItem.Type, + Disabled: menuItem.Disabled, + Hidden: menuItem.Hidden, + Checked: menuItem.Checked, + Foreground: menuItem.Foreground, + Background: menuItem.Background, + } + + if menuItem.SubMenu != nil { + result.SubMenu = m.NewProcessedMenu(menuItem.SubMenu) + } + + return result +} + +type ProcessedMenu struct { + Items []*ProcessedMenuItem +} + +func (m *Manager) NewProcessedMenu(menu *menu.Menu) *ProcessedMenu { + + result := &ProcessedMenu{} + for _, item := range menu.Items { + processedMenuItem := m.NewProcessedMenuItem(item) + result.Items = append(result.Items, processedMenuItem) + } + + return result +} + +// WailsMenu is the original menu with the addition +// of radio groups extracted from the menu data +type WailsMenu struct { + Menu *ProcessedMenu + RadioGroups []*RadioGroup + currentRadioGroup []string +} + +// RadioGroup holds all the members of the same radio group +type RadioGroup struct { + Members []string + Length int +} + +func (m *Manager) NewWailsMenu(menu *menu.Menu) *WailsMenu { + result := &WailsMenu{} + + // Process the menus + result.Menu = m.NewProcessedMenu(menu) + + // Process the radio groups + result.processRadioGroups() + + return result +} + +func (w *WailsMenu) AsJSON() (string, error) { + + menuAsJSON, err := json.Marshal(w) + if err != nil { + return "", err + } + return string(menuAsJSON), nil +} + +func (w *WailsMenu) processRadioGroups() { + // Loop over top level menus + for _, item := range w.Menu.Items { + // Process MenuItem + w.processMenuItem(item) + } + + w.finaliseRadioGroup() +} + +func (w *WailsMenu) processMenuItem(item *ProcessedMenuItem) { + + switch item.Type { + + // We need to recurse submenus + case menu.SubmenuType: + + // Finalise any current radio groups as they don't trickle down to submenus + w.finaliseRadioGroup() + + // Process each submenu item + for _, subitem := range item.SubMenu.Items { + w.processMenuItem(subitem) + } + case menu.RadioType: + // Add the item to the radio group + w.currentRadioGroup = append(w.currentRadioGroup, item.ID) + default: + w.finaliseRadioGroup() + } +} + +func (w *WailsMenu) finaliseRadioGroup() { + + // If we were processing a radio group, fix up the references + if len(w.currentRadioGroup) > 0 { + + // Create new radiogroup + group := &RadioGroup{ + Members: w.currentRadioGroup, + Length: len(w.currentRadioGroup), + } + w.RadioGroups = append(w.RadioGroups, group) + + // Empty the radio group + w.currentRadioGroup = []string{} + } +} diff --git a/v2/internal/subsystem/menu.go b/v2/internal/subsystem/menu.go index a700a17d9..da37dbe20 100644 --- a/v2/internal/subsystem/menu.go +++ b/v2/internal/subsystem/menu.go @@ -1,6 +1,7 @@ package subsystem import ( + "github.com/wailsapp/wails/v2/internal/menumanager" "strings" "sync" @@ -35,15 +36,15 @@ type Menu struct { // logger logger logger.CustomLogger - // The application menu - applicationMenu *menu.Menu - // Service Bus bus *servicebus.ServiceBus + + // Menu Manager + menuManager *menumanager.Manager } // NewMenu creates a new menu subsystem -func NewMenu(applicationMenu *menu.Menu, bus *servicebus.ServiceBus, logger *logger.Logger) (*Menu, error) { +func NewMenu(bus *servicebus.ServiceBus, logger *logger.Logger, menuManager *menumanager.Manager) (*Menu, error) { // Register quit channel quitChannel, err := bus.Subscribe("quit") @@ -58,18 +59,15 @@ func NewMenu(applicationMenu *menu.Menu, bus *servicebus.ServiceBus, logger *log } result := &Menu{ - quitChannel: quitChannel, - menuChannel: menuChannel, - logger: logger.CustomLogger("Menu Subsystem"), - listeners: make(map[string][]func(*menu.MenuItem)), - menuItems: make(map[string]*menu.MenuItem), - applicationMenu: applicationMenu, - bus: bus, + quitChannel: quitChannel, + menuChannel: menuChannel, + logger: logger.CustomLogger("Menu Subsystem"), + listeners: make(map[string][]func(*menu.MenuItem)), + menuItems: make(map[string]*menu.MenuItem), + bus: bus, + menuManager: menuManager, } - // Build up list of item/id pairs - result.processMenu(applicationMenu) - return result, nil } @@ -99,21 +97,11 @@ func (m *Menu) Start() error { m.logger.Trace("Got Menu clicked Message: %s %+v", menuMessage.Topic(), menuMessage.Data()) menuid := menuMessage.Data().(string) - // Get the menu item - menuItem := m.menuItems[menuid] - if menuItem == nil { - m.logger.Trace("Cannot process menuid %s - unknown", menuid) - return + err := m.menuManager.ProcessClick(menuid) + if err != nil { + m.logger.Trace("%s", err.Error()) } - // Is the menu item a checkbox? - if menuItem.Type == menu.CheckboxType { - // Toggle state - menuItem.Checked = !menuItem.Checked - } - - // Notify listeners - m.notifyListeners(menuid, menuItem) case "on": listenerDetails := menuMessage.Data().(*message.MenuOnMessage) id := listenerDetails.MenuID @@ -121,11 +109,11 @@ func (m *Menu) Start() error { // Make sure we catch any menu updates case "update": - updatedMenu := menuMessage.Data().(*menu.Menu) - m.processMenu(updatedMenu) - - // Notify frontend of menu change - m.bus.Publish("menufrontend:update", updatedMenu) + //updatedMenu := menuMessage.Data().(*menu.Menu) + //m.processMenu(updatedMenu) + // + //// Notify frontend of menu change + //m.bus.Publish("menufrontend:update", updatedMenu) default: m.logger.Error("unknown menu message: %+v", menuMessage) @@ -140,56 +128,6 @@ func (m *Menu) Start() error { return nil } -func (m *Menu) processMenu(applicationMenu *menu.Menu) { - // Initialise the variables - m.menuItems = make(map[string]*menu.MenuItem) - m.applicationMenu = applicationMenu - - for _, item := range applicationMenu.Items { - m.processMenuItem(item) - } -} - -func (m *Menu) processMenuItem(item *menu.MenuItem) { - - if item.SubMenu != nil { - for _, submenuitem := range item.SubMenu.Items { - m.processMenuItem(submenuitem) - } - return - } - - if item.ID != "" { - if m.menuItems[item.ID] != nil { - m.logger.Error("Menu id '%s' is used by multiple menu items: %s %s", m.menuItems[item.ID].Label, item.Label) - return - } - m.menuItems[item.ID] = item - } -} - -// Notifies listeners that the given menu was clicked -func (m *Menu) notifyListeners(menuid string, menuItem *menu.MenuItem) { - - // Get list of menu listeners - listeners := m.listeners[menuid] - if listeners == nil { - m.logger.Trace("No listeners for MenuItem with ID '%s'", menuid) - return - } - - // Lock the listeners - m.notifyLock.Lock() - - // Callback in goroutine - for _, listener := range listeners { - go listener(menuItem) - } - - // Unlock - m.notifyLock.Unlock() -} - func (m *Menu) shutdown() { m.logger.Trace("Shutdown") } diff --git a/v2/pkg/menu/callback.go b/v2/pkg/menu/callback.go new file mode 100644 index 000000000..9ca19f3c1 --- /dev/null +++ b/v2/pkg/menu/callback.go @@ -0,0 +1,8 @@ +package menu + +type CallbackData struct { + MenuItem *MenuItem + ContextData string +} + +type Callback func(*CallbackData) diff --git a/v2/pkg/menu/menuitem.go b/v2/pkg/menu/menuitem.go index 078190b2c..6b282846a 100644 --- a/v2/pkg/menu/menuitem.go +++ b/v2/pkg/menu/menuitem.go @@ -24,6 +24,9 @@ type MenuItem struct { //SubMenu []*MenuItem `json:"SubMenu,omitempty"` SubMenu *Menu `json:"SubMenu,omitempty"` + // Callback function when menu clicked + Click Callback `json:"-"` + // Foreground colour in hex RGBA format EG: 0xFF0000FF = #FF0000FF = red Foreground int @@ -226,12 +229,13 @@ func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool { } // Text is a helper to create basic Text menu items -func Text(label string, id string, accelerator *keys.Accelerator) *MenuItem { +func Text(label string, id string, accelerator *keys.Accelerator, click Callback) *MenuItem { return &MenuItem{ ID: id, Label: label, Type: TextType, Accelerator: accelerator, + Click: click, } } @@ -243,24 +247,26 @@ func Separator() *MenuItem { } // Radio is a helper to create basic Radio menu items with an accelerator -func Radio(label string, id string, selected bool, accelerator *keys.Accelerator) *MenuItem { +func Radio(label string, id string, selected bool, accelerator *keys.Accelerator, click Callback) *MenuItem { return &MenuItem{ ID: id, Label: label, Type: RadioType, Checked: selected, Accelerator: accelerator, + Click: click, } } // Checkbox is a helper to create basic Checkbox menu items -func Checkbox(label string, id string, checked bool, accelerator *keys.Accelerator) *MenuItem { +func Checkbox(label string, id string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem { return &MenuItem{ ID: id, Label: label, Type: CheckboxType, Checked: checked, Accelerator: accelerator, + Click: click, } } diff --git a/v2/test/kitchensink/main.go b/v2/test/kitchensink/main.go index c72a95174..e91301c9e 100644 --- a/v2/test/kitchensink/main.go +++ b/v2/test/kitchensink/main.go @@ -3,7 +3,6 @@ package main import ( "github.com/wailsapp/wails/v2" "github.com/wailsapp/wails/v2/pkg/logger" - "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/mac" "log" @@ -11,6 +10,8 @@ import ( func main() { + Menu := &Menu{} + // Create application with options app, err := wails.CreateAppWithOptions(&options.App{ Title: "Kitchen Sink", @@ -21,17 +22,17 @@ func main() { //Tray: menu.NewMenuFromItems(menu.AppMenu()), //Menu: menu.NewMenuFromItems(menu.AppMenu()), //StartHidden: true, - ContextMenus: createContextMenus(), + //ContextMenus: createContextMenus(), Mac: &mac.Options{ WebviewIsTransparent: true, WindowBackgroundIsTranslucent: true, // Comment out line below to see Window.SetTitle() work TitleBar: mac.TitleBarHiddenInset(), - Menu: createApplicationMenu(), - Tray: &menu.Tray{ - Icon: "light", - Menu: createApplicationTray(), - }, + Menu: Menu.createApplicationMenu(), + //Tray: &menu.Tray{ + // Icon: "light", + // Menu: createApplicationTray(), + //}, }, LogLevel: logger.TRACE, }) @@ -46,7 +47,7 @@ func main() { app.Bind(&System{}) app.Bind(&Dialog{}) app.Bind(&Window{}) - app.Bind(&Menu{}) + app.Bind(Menu) app.Bind(&Tray{}) app.Bind(&ContextMenu{}) diff --git a/v2/test/kitchensink/menu.go b/v2/test/kitchensink/menu.go index 07c2aa618..709a584bb 100644 --- a/v2/test/kitchensink/menu.go +++ b/v2/test/kitchensink/menu.go @@ -69,13 +69,13 @@ func (m *Menu) addMenu(mi *menu.MenuItem) { parent := mi.Parent() counter := m.incrementcounter() menuText := "Dynamic Menu Item " + strconv.Itoa(counter) - parent.Append(menu.Text(menuText, menuText, nil)) + parent.Append(menu.Text(menuText, menuText, nil, nil)) // parent.Append(menu.Text(menuText, menuText, menu.Key("["))) // If this is the first dynamic menu added, let's add a remove menu item if counter == 1 { removeMenu := menu.Text("Remove "+menuText, - "Remove Last Item", keys.CmdOrCtrl("-")) + "Remove Last Item", keys.CmdOrCtrl("-"), nil) parent.Prepend(removeMenu) m.runtime.Menu.On("Remove Last Item", m.removeMenu) } else { @@ -126,9 +126,9 @@ func (m *Menu) createDynamicMenuTwo() { // Create our submenu dm2 := menu.SubMenu("Dynamic Menus 2", menu.NewMenuFromItems( menu.Text("Insert Before Random Menu Item", - "Insert Before Random", keys.CmdOrCtrl("]")), + "Insert Before Random", keys.CmdOrCtrl("]"), nil), menu.Text("Insert After Random Menu Item", - "Insert After Random", keys.CmdOrCtrl("[")), + "Insert After Random", keys.CmdOrCtrl("["), nil), menu.Separator(), )) @@ -142,7 +142,7 @@ func (m *Menu) createDynamicMenuTwo() { m.anotherDynamicMenuCounter = 5 for index := 0; index < m.anotherDynamicMenuCounter; index++ { text := "Other Dynamic Menu Item " + strconv.Itoa(index+1) - item := menu.Text(text, text, nil) + item := menu.Text(text, text, nil, nil) m.dynamicMenuItems[text] = item dm2.Append(item) } @@ -176,7 +176,7 @@ func (m *Menu) insertBeforeRandom(_ *menu.MenuItem) { m.anotherDynamicMenuCounter++ text := "Other Dynamic Menu Item " + strconv.Itoa( m.anotherDynamicMenuCounter+1) - newItem := menu.Text(text, text, nil) + newItem := menu.Text(text, text, nil, nil) m.dynamicMenuItems[text] = newItem item := m.runtime.Menu.GetByID(randomItemID) @@ -211,7 +211,7 @@ func (m *Menu) insertAfterRandom(_ *menu.MenuItem) { m.anotherDynamicMenuCounter++ text := "Other Dynamic Menu Item " + strconv.Itoa( m.anotherDynamicMenuCounter+1) - newItem := menu.Text(text, text, nil) + newItem := menu.Text(text, text, nil, nil) item := m.runtime.Menu.GetByID(randomItemID) m.dynamicMenuItems[text] = newItem @@ -224,7 +224,11 @@ func (m *Menu) insertAfterRandom(_ *menu.MenuItem) { m.runtime.Menu.Update() } -func createApplicationMenu() *menu.Menu { +func (m *Menu) processPlainText(callbackData *menu.CallbackData) { + println("\n\n\n\n\n\n\nCallback successful\n\n\n\n\n") +} + +func (m *Menu) createApplicationMenu() *menu.Menu { // Create menu myMenu := menu.DefaultMacMenu() @@ -245,62 +249,62 @@ func createApplicationMenu() *menu.Menu { menu.Front(), menu.SubMenu("Test Submenu", menu.NewMenuFromItems( - menu.Text("Plain text", "plain text", nil), - menu.Text("Show Dynamic Menus 2 Submenu", "show-dynamic-menus-2", nil), + menu.Text("Plain text", "plain text", nil, m.processPlainText), + menu.Text("Show Dynamic Menus 2 Submenu", "show-dynamic-menus-2", nil, nil), menu.SubMenu("Accelerators", menu.NewMenuFromItems( menu.SubMenu("Modifiers", menu.NewMenuFromItems( - menu.Text("Shift accelerator", "Shift", keys.Shift("o")), - menu.Text("Control accelerator", "Control", keys.Control("o")), - menu.Text("Command accelerator", "Command", keys.CmdOrCtrl("o")), - menu.Text("Option accelerator", "Option", keys.OptionOrAlt("o")), - menu.Text("Combo accelerator", "Combo", keys.Combo("o", keys.CmdOrCtrlKey, keys.ShiftKey)), + menu.Text("Shift accelerator", "Shift", keys.Shift("o"), nil), + menu.Text("Control accelerator", "Control", keys.Control("o"), nil), + menu.Text("Command accelerator", "Command", keys.CmdOrCtrl("o"), nil), + menu.Text("Option accelerator", "Option", keys.OptionOrAlt("o"), nil), + menu.Text("Combo accelerator", "Combo", keys.Combo("o", keys.CmdOrCtrlKey, keys.ShiftKey), nil), )), menu.SubMenu("System Keys", menu.NewMenuFromItems( - menu.Text("Backspace", "Backspace", keys.Key("Backspace")), - menu.Text("Tab", "Tab", keys.Key("Tab")), - menu.Text("Return", "Return", keys.Key("Return")), - menu.Text("Escape", "Escape", keys.Key("Escape")), - menu.Text("Left", "Left", keys.Key("Left")), - menu.Text("Right", "Right", keys.Key("Right")), - menu.Text("Up", "Up", keys.Key("Up")), - menu.Text("Down", "Down", keys.Key("Down")), - menu.Text("Space", "Space", keys.Key("Space")), - menu.Text("Delete", "Delete", keys.Key("Delete")), - menu.Text("Home", "Home", keys.Key("Home")), - menu.Text("End", "End", keys.Key("End")), - menu.Text("Page Up", "Page Up", keys.Key("Page Up")), - menu.Text("Page Down", "Page Down", keys.Key("Page Down")), - menu.Text("NumLock", "NumLock", keys.Key("NumLock")), + menu.Text("Backspace", "Backspace", keys.Key("Backspace"), nil), + menu.Text("Tab", "Tab", keys.Key("Tab"), nil), + menu.Text("Return", "Return", keys.Key("Return"), nil), + menu.Text("Escape", "Escape", keys.Key("Escape"), nil), + menu.Text("Left", "Left", keys.Key("Left"), nil), + menu.Text("Right", "Right", keys.Key("Right"), nil), + menu.Text("Up", "Up", keys.Key("Up"), nil), + menu.Text("Down", "Down", keys.Key("Down"), nil), + menu.Text("Space", "Space", keys.Key("Space"), nil), + menu.Text("Delete", "Delete", keys.Key("Delete"), nil), + menu.Text("Home", "Home", keys.Key("Home"), nil), + menu.Text("End", "End", keys.Key("End"), nil), + menu.Text("Page Up", "Page Up", keys.Key("Page Up"), nil), + menu.Text("Page Down", "Page Down", keys.Key("Page Down"), nil), + menu.Text("NumLock", "NumLock", keys.Key("NumLock"), nil), )), menu.SubMenu("Function Keys", menu.NewMenuFromItems( - menu.Text("F1", "F1", keys.Key("F1")), - menu.Text("F2", "F2", keys.Key("F2")), - menu.Text("F3", "F3", keys.Key("F3")), - menu.Text("F4", "F4", keys.Key("F4")), - menu.Text("F5", "F5", keys.Key("F5")), - menu.Text("F6", "F6", keys.Key("F6")), - menu.Text("F7", "F7", keys.Key("F7")), - menu.Text("F8", "F8", keys.Key("F8")), - menu.Text("F9", "F9", keys.Key("F9")), - menu.Text("F10", "F10", keys.Key("F10")), - menu.Text("F11", "F11", keys.Key("F11")), - menu.Text("F12", "F12", keys.Key("F12")), - menu.Text("F13", "F13", keys.Key("F13")), - menu.Text("F14", "F14", keys.Key("F14")), - menu.Text("F15", "F15", keys.Key("F15")), - menu.Text("F16", "F16", keys.Key("F16")), - menu.Text("F17", "F17", keys.Key("F17")), - menu.Text("F18", "F18", keys.Key("F18")), - menu.Text("F19", "F19", keys.Key("F19")), - menu.Text("F20", "F20", keys.Key("F20")), + menu.Text("F1", "F1", keys.Key("F1"), nil), + menu.Text("F2", "F2", keys.Key("F2"), nil), + menu.Text("F3", "F3", keys.Key("F3"), nil), + menu.Text("F4", "F4", keys.Key("F4"), nil), + menu.Text("F5", "F5", keys.Key("F5"), nil), + menu.Text("F6", "F6", keys.Key("F6"), nil), + menu.Text("F7", "F7", keys.Key("F7"), nil), + menu.Text("F8", "F8", keys.Key("F8"), nil), + menu.Text("F9", "F9", keys.Key("F9"), nil), + menu.Text("F10", "F10", keys.Key("F10"), nil), + menu.Text("F11", "F11", keys.Key("F11"), nil), + menu.Text("F12", "F12", keys.Key("F12"), nil), + menu.Text("F13", "F13", keys.Key("F13"), nil), + menu.Text("F14", "F14", keys.Key("F14"), nil), + menu.Text("F15", "F15", keys.Key("F15"), nil), + menu.Text("F16", "F16", keys.Key("F16"), nil), + menu.Text("F17", "F17", keys.Key("F17"), nil), + menu.Text("F18", "F18", keys.Key("F18"), nil), + menu.Text("F19", "F19", keys.Key("F19"), nil), + menu.Text("F20", "F20", keys.Key("F20"), nil), )), menu.SubMenu("Standard Keys", menu.NewMenuFromItems( - menu.Text("Backtick", "Backtick", keys.Key("`")), - menu.Text("Plus", "Plus", keys.Key("+")), + menu.Text("Backtick", "Backtick", keys.Key("`"), nil), + menu.Text("Plus", "Plus", keys.Key("+"), nil), )), )), menu.SubMenuWithID("Dynamic Menus 1", "Dynamic Menus 1", menu.NewMenuFromItems( - menu.Text("Add Menu Item", "Add Menu Item", keys.CmdOrCtrl("+")), + menu.Text("Add Menu Item", "Add Menu Item", keys.CmdOrCtrl("+"), nil), menu.Separator(), )), &menu.MenuItem{ @@ -321,11 +325,11 @@ func createApplicationMenu() *menu.Menu { Accelerator: keys.CmdOrCtrl("l"), Checked: true, }, - menu.Checkbox("Checkbox Menu 2", "checkbox-menu 2", false, nil), + menu.Checkbox("Checkbox Menu 2", "checkbox-menu 2", false, nil, nil), menu.Separator(), - menu.Radio("😀 Option 1", "😀option-1", true, nil), - menu.Radio("😺 Option 2", "option-2", false, nil), - menu.Radio("❤️ Option 3", "option-3", false, nil), + menu.Radio("😀 Option 1", "😀option-1", true, nil, nil), + menu.Radio("😺 Option 2", "option-2", false, nil, nil), + menu.Radio("❤️ Option 3", "option-3", false, nil, nil), )), )) diff --git a/v2/test/kitchensink/tray.go b/v2/test/kitchensink/tray.go index 67c629073..2474c59cc 100644 --- a/v2/test/kitchensink/tray.go +++ b/v2/test/kitchensink/tray.go @@ -78,13 +78,13 @@ func (t *Tray) addMenu(mi *menu.MenuItem) { parent := mi.Parent() counter := t.incrementcounter() menuText := "Dynamic Menu Item " + strconv.Itoa(counter) - parent.Append(menu.Text(menuText, menuText, nil)) + parent.Append(menu.Text(menuText, menuText, nil, nil)) // parent.Append(menu.Text(menuText, menuText, menu.Key("["))) // If this is the first dynamic menu added, let's add a remove menu item if counter == 1 { removeMenu := menu.Text("Remove "+menuText, - "Remove Last Item", keys.CmdOrCtrl("-")) + "Remove Last Item", keys.CmdOrCtrl("-"), nil) parent.Prepend(removeMenu) t.runtime.Tray.On("Remove Last Item", t.removeMenu) } else { @@ -136,9 +136,9 @@ func (t *Tray) SetIcon(trayIconID string) { func createApplicationTray() *menu.Menu { trayMenu := &menu.Menu{} - trayMenu.Append(menu.Text("Show Window", "Show Window", nil)) - trayMenu.Append(menu.Text("Hide Window", "Hide Window", nil)) - trayMenu.Append(menu.Text("Minimise Window", "Minimise Window", nil)) - trayMenu.Append(menu.Text("Unminimise Window", "Unminimise Window", nil)) + trayMenu.Append(menu.Text("Show Window", "Show Window", nil, nil)) + trayMenu.Append(menu.Text("Hide Window", "Hide Window", nil, nil)) + trayMenu.Append(menu.Text("Minimise Window", "Minimise Window", nil, nil)) + trayMenu.Append(menu.Text("Unminimise Window", "Unminimise Window", nil, nil)) return trayMenu }