mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 05:08:54 -07:00
Removal of menu IDs. WARNING: context menus are currently broken
This commit is contained in:
@@ -24,15 +24,13 @@ type App struct {
|
||||
options *options.App
|
||||
|
||||
// Subsystems
|
||||
log *subsystem.Log
|
||||
runtime *subsystem.Runtime
|
||||
event *subsystem.Event
|
||||
binding *subsystem.Binding
|
||||
call *subsystem.Call
|
||||
menu *subsystem.Menu
|
||||
tray *subsystem.Tray
|
||||
contextmenus *subsystem.ContextMenus
|
||||
dispatcher *messagedispatcher.Dispatcher
|
||||
log *subsystem.Log
|
||||
runtime *subsystem.Runtime
|
||||
event *subsystem.Event
|
||||
binding *subsystem.Binding
|
||||
call *subsystem.Call
|
||||
menu *subsystem.Menu
|
||||
dispatcher *messagedispatcher.Dispatcher
|
||||
|
||||
menuManager *menumanager.Manager
|
||||
|
||||
@@ -191,32 +189,6 @@ func (a *App) Run() error {
|
||||
}
|
||||
}
|
||||
|
||||
//// Optionally start the tray subsystem
|
||||
//if trayMenu != nil {
|
||||
// traysubsystem, err := subsystem.NewTray(trayMenu, a.servicebus, a.logger)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// a.tray = traysubsystem
|
||||
// err = a.tray.Start()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
// Optionally start the context menu subsystem
|
||||
if contextMenus != nil {
|
||||
contextmenussubsystem, err := subsystem.NewContextMenus(contextMenus, a.servicebus, a.logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.contextmenus = contextmenussubsystem
|
||||
err = a.contextmenus.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Start the call subsystem
|
||||
call, err := subsystem.NewCall(a.servicebus, a.logger, a.bindings.DB(), a.runtime.GoRuntime())
|
||||
if err != nil {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package ffenestri
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
@@ -185,28 +183,3 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug
|
||||
func messageFromWindowCallback(data *C.char) {
|
||||
dispatcher.DispatchMessage(C.GoString(data))
|
||||
}
|
||||
|
||||
type ProcessedContextMenu struct {
|
||||
ID string
|
||||
ProcessedMenu *ProcessedMenu
|
||||
}
|
||||
|
||||
func processContextMenus(contextMenus *menu.ContextMenus) (string, error) {
|
||||
var processedContextMenus []*ProcessedContextMenu
|
||||
|
||||
// We need to iterate each context menu and pre-process it
|
||||
for contextMenuID, contextMenu := range contextMenus.Items {
|
||||
thisContextMenu := &ProcessedContextMenu{
|
||||
ID: contextMenuID,
|
||||
ProcessedMenu: NewProcessedMenu(contextMenu),
|
||||
}
|
||||
processedContextMenus = append(processedContextMenus, thisContextMenu)
|
||||
}
|
||||
|
||||
contextMenusJSON, err := json.Marshal(processedContextMenus)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(contextMenusJSON), nil
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ package ffenestri
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"strconv"
|
||||
|
||||
@@ -190,22 +189,6 @@ func (c *Client) UpdateMenu(menuJSON string) {
|
||||
C.SetApplicationMenu(c.app.app, c.app.string2CString(menuJSON))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateTray(menu *menu.Menu) {
|
||||
|
||||
// Guard against nil menus
|
||||
if menu == nil {
|
||||
return
|
||||
}
|
||||
// Process the menu
|
||||
processedMenu := NewProcessedMenu(menu)
|
||||
trayMenuJSON, err := json.Marshal(processedMenu)
|
||||
if err != nil {
|
||||
c.app.logger.Error("Error processing updated TrayMenu: %s", err.Error())
|
||||
return
|
||||
}
|
||||
C.UpdateTray(c.app.app, c.app.string2CString(string(trayMenuJSON)))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateTrayMenu(trayMenuJSON string) {
|
||||
C.UpdateTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON))
|
||||
}
|
||||
@@ -219,16 +202,16 @@ func (c *Client) UpdateTrayIcon(name string) {
|
||||
}
|
||||
|
||||
func (c *Client) UpdateContextMenus(contextMenus *menu.ContextMenus) {
|
||||
|
||||
// Guard against nil contextMenus
|
||||
if contextMenus == nil {
|
||||
return
|
||||
}
|
||||
// Process the menu
|
||||
contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
if err != nil {
|
||||
c.app.logger.Error("Error processing updated Context Menu: %s", err.Error())
|
||||
return
|
||||
}
|
||||
C.UpdateContextMenus(c.app.app, c.app.string2CString(contextMenusJSON))
|
||||
//
|
||||
// // Guard against nil contextMenus
|
||||
// if contextMenus == nil {
|
||||
// return
|
||||
// }
|
||||
// // Process the menu
|
||||
// contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
// if err != nil {
|
||||
// c.app.logger.Error("Error processing updated Context Menu: %s", err.Error())
|
||||
// return
|
||||
// }
|
||||
// C.UpdateContextMenus(c.app.app, c.app.string2CString(contextMenusJSON))
|
||||
}
|
||||
|
||||
@@ -7,13 +7,8 @@ package ffenestri
|
||||
#include "ffenestri.h"
|
||||
#include "ffenestri_darwin.h"
|
||||
|
||||
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
func (a *Application) processPlatformSettings() error {
|
||||
|
||||
@@ -83,14 +78,14 @@ func (a *Application) processPlatformSettings() error {
|
||||
}
|
||||
|
||||
// Process context menus
|
||||
contextMenus := options.GetContextMenus(a.config)
|
||||
if contextMenus != nil {
|
||||
contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
C.SetContextMenus(a.app, a.string2CString(contextMenusJSON))
|
||||
}
|
||||
//contextMenus := options.GetContextMenus(a.config)
|
||||
//if contextMenus != nil {
|
||||
// contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// C.SetContextMenus(a.app, a.string2CString(contextMenusJSON))
|
||||
//}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package ffenestri
|
||||
|
||||
import "github.com/wailsapp/wails/v2/pkg/menu"
|
||||
|
||||
// ProcessedMenu is the original menu with the addition
|
||||
// of radio groups extracted from the menu data
|
||||
type ProcessedMenu struct {
|
||||
Menu *menu.Menu
|
||||
RadioGroups []*RadioGroup
|
||||
currentRadioGroup []string
|
||||
}
|
||||
|
||||
// RadioGroup holds all the members of the same radio group
|
||||
type RadioGroup struct {
|
||||
Members []string
|
||||
Length int
|
||||
}
|
||||
|
||||
// NewProcessedMenu processed the given menu and returns
|
||||
// the original menu with the extracted radio groups
|
||||
func NewProcessedMenu(menu *menu.Menu) *ProcessedMenu {
|
||||
result := &ProcessedMenu{
|
||||
Menu: menu,
|
||||
RadioGroups: []*RadioGroup{},
|
||||
currentRadioGroup: []string{},
|
||||
}
|
||||
|
||||
result.processMenu()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *ProcessedMenu) processMenu() {
|
||||
// Loop over top level menus
|
||||
for _, item := range p.Menu.Items {
|
||||
// Process MenuItem
|
||||
p.processMenuItem(item)
|
||||
}
|
||||
|
||||
p.finaliseRadioGroup()
|
||||
}
|
||||
|
||||
func (p *ProcessedMenu) processMenuItem(item *menu.MenuItem) {
|
||||
|
||||
switch item.Type {
|
||||
|
||||
// We need to recurse submenus
|
||||
case menu.SubmenuType:
|
||||
|
||||
// Finalise any current radio groups as they don't trickle down to submenus
|
||||
p.finaliseRadioGroup()
|
||||
|
||||
// Process each submenu item
|
||||
for _, subitem := range item.SubMenu.Items {
|
||||
p.processMenuItem(subitem)
|
||||
}
|
||||
case menu.RadioType:
|
||||
// Add the item to the radio group
|
||||
p.currentRadioGroup = append(p.currentRadioGroup, item.ID)
|
||||
default:
|
||||
p.finaliseRadioGroup()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ProcessedMenu) finaliseRadioGroup() {
|
||||
|
||||
// If we were processing a radio group, fix up the references
|
||||
if len(p.currentRadioGroup) > 0 {
|
||||
|
||||
// Create new radiogroup
|
||||
group := &RadioGroup{
|
||||
Members: p.currentRadioGroup,
|
||||
Length: len(p.currentRadioGroup),
|
||||
}
|
||||
p.RadioGroups = append(p.RadioGroups, group)
|
||||
|
||||
// Empty the radio group
|
||||
p.currentRadioGroup = []string{}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ type Client interface {
|
||||
WindowSetColour(colour int)
|
||||
DarkModeEnabled(callbackID string)
|
||||
UpdateMenu(menuJSON string)
|
||||
UpdateTray(menu *menu.Menu)
|
||||
UpdateTrayLabel(label string)
|
||||
UpdateTrayIcon(name string)
|
||||
UpdateTrayMenu(menuJSON string)
|
||||
|
||||
@@ -25,7 +25,6 @@ type Dispatcher struct {
|
||||
systemChannel <-chan *servicebus.Message
|
||||
menuChannel <-chan *servicebus.Message
|
||||
contextMenuChannel <-chan *servicebus.Message
|
||||
trayChannel <-chan *servicebus.Message
|
||||
running bool
|
||||
|
||||
servicebus *servicebus.ServiceBus
|
||||
@@ -83,11 +82,6 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
trayChannel, err := servicebus.Subscribe("trayfrontend:")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &Dispatcher{
|
||||
servicebus: servicebus,
|
||||
eventChannel: eventChannel,
|
||||
@@ -99,7 +93,6 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
||||
dialogChannel: dialogChannel,
|
||||
systemChannel: systemChannel,
|
||||
menuChannel: menuChannel,
|
||||
trayChannel: trayChannel,
|
||||
contextMenuChannel: contextMenuChannel,
|
||||
}
|
||||
|
||||
@@ -134,8 +127,6 @@ func (d *Dispatcher) Start() error {
|
||||
d.processMenuMessage(menuMessage)
|
||||
case contextMenuMessage := <-d.contextMenuChannel:
|
||||
d.processContextMenuMessage(contextMenuMessage)
|
||||
case trayMessage := <-d.trayChannel:
|
||||
d.processTrayMessage(trayMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,62 +501,3 @@ func (d *Dispatcher) processContextMenuMessage(result *servicebus.Message) {
|
||||
d.logger.Error("Unknown contextmenufrontend command: %s", command)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dispatcher) processTrayMessage(result *servicebus.Message) {
|
||||
splitTopic := strings.Split(result.Topic(), ":")
|
||||
if len(splitTopic) < 2 {
|
||||
d.logger.Error("Invalid tray message : %#v", result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
command := splitTopic[1]
|
||||
switch command {
|
||||
case "update":
|
||||
|
||||
updatedMenu, ok := result.Data().(*menu.Menu)
|
||||
if !ok {
|
||||
d.logger.Error("Invalid data for 'trayfrontend:update' : %#v",
|
||||
result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Work out what we mean in a multi window environment...
|
||||
// For now we will just pick the first one
|
||||
for _, client := range d.clients {
|
||||
client.frontend.UpdateTray(updatedMenu)
|
||||
}
|
||||
|
||||
case "setlabel":
|
||||
|
||||
updatedLabel, ok := result.Data().(string)
|
||||
if !ok {
|
||||
d.logger.Error("Invalid data for 'trayfrontend:setlabel' : %#v",
|
||||
result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Work out what we mean in a multi window environment...
|
||||
// For now we will just pick the first one
|
||||
for _, client := range d.clients {
|
||||
client.frontend.UpdateTrayLabel(updatedLabel)
|
||||
}
|
||||
|
||||
case "seticon":
|
||||
|
||||
iconname, ok := result.Data().(string)
|
||||
if !ok {
|
||||
d.logger.Error("Invalid data for 'trayfrontend:seticon' : %#v",
|
||||
result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Work out what we mean in a multi window environment...
|
||||
// For now we will just pick the first one
|
||||
for _, client := range d.clients {
|
||||
client.frontend.UpdateTrayIcon(iconname)
|
||||
}
|
||||
|
||||
default:
|
||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// ContextMenus defines all ContextMenu related operations
|
||||
type ContextMenus interface {
|
||||
On(menuID string, callback func(*menu.MenuItem, string))
|
||||
Update()
|
||||
GetByID(menuID string) *menu.MenuItem
|
||||
RemoveByID(id string) bool
|
||||
}
|
||||
|
||||
type contextMenus struct {
|
||||
bus *servicebus.ServiceBus
|
||||
contextmenus *menu.ContextMenus
|
||||
}
|
||||
|
||||
// newContextMenus creates a new ContextMenu struct
|
||||
func newContextMenus(bus *servicebus.ServiceBus, contextmenus *menu.ContextMenus) ContextMenus {
|
||||
return &contextMenus{
|
||||
bus: bus,
|
||||
contextmenus: contextmenus,
|
||||
}
|
||||
}
|
||||
|
||||
// On registers a listener for a particular event
|
||||
func (t *contextMenus) On(menuID string, callback func(*menu.MenuItem, string)) {
|
||||
t.bus.Publish("contextmenus:on", &message.ContextMenusOnMessage{
|
||||
MenuID: menuID,
|
||||
Callback: callback,
|
||||
})
|
||||
}
|
||||
|
||||
func (t *contextMenus) Update() {
|
||||
t.bus.Publish("contextmenus:update", t.contextmenus)
|
||||
}
|
||||
|
||||
func (t *contextMenus) GetByID(menuItemID string) *menu.MenuItem {
|
||||
return t.contextmenus.GetByID(menuItemID)
|
||||
}
|
||||
|
||||
func (t *contextMenus) RemoveByID(menuItemID string) bool {
|
||||
return t.contextmenus.RemoveByID(menuItemID)
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// Tray defines all Tray related operations
|
||||
type Tray interface {
|
||||
On(menuID string, callback func(*menu.MenuItem))
|
||||
Update(tray ...*menu.TrayMenu)
|
||||
GetByID(menuID string) *menu.MenuItem
|
||||
RemoveByID(id string) bool
|
||||
SetLabel(label string)
|
||||
SetIcon(name string)
|
||||
}
|
||||
|
||||
type trayRuntime struct {
|
||||
bus *servicebus.ServiceBus
|
||||
trayMenu *menu.TrayMenu
|
||||
}
|
||||
|
||||
// newTray creates a new Menu struct
|
||||
func newTray(bus *servicebus.ServiceBus, menu *menu.TrayMenu) Tray {
|
||||
return &trayRuntime{
|
||||
bus: bus,
|
||||
trayMenu: menu,
|
||||
}
|
||||
}
|
||||
|
||||
// On registers a listener for a particular event
|
||||
func (t *trayRuntime) On(menuID string, callback func(*menu.MenuItem)) {
|
||||
t.bus.Publish("tray:on", &message.TrayOnMessage{
|
||||
MenuID: menuID,
|
||||
Callback: callback,
|
||||
})
|
||||
}
|
||||
|
||||
func (t *trayRuntime) Update(tray ...*menu.TrayMenu) {
|
||||
|
||||
//trayToUpdate := t.trayMenu
|
||||
t.bus.Publish("tray:update", t.trayMenu)
|
||||
}
|
||||
|
||||
func (t *trayRuntime) SetLabel(label string) {
|
||||
t.bus.Publish("tray:setlabel", label)
|
||||
}
|
||||
func (t *trayRuntime) SetIcon(name string) {
|
||||
t.bus.Publish("tray:seticon", name)
|
||||
}
|
||||
|
||||
func (t *trayRuntime) GetByID(menuID string) *menu.MenuItem {
|
||||
return t.trayMenu.Menu.GetByID(menuID)
|
||||
}
|
||||
|
||||
func (t *trayRuntime) RemoveByID(id string) bool {
|
||||
return t.trayMenu.Menu.RemoveByID(id)
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
package subsystem
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// ContextMenus is the subsystem that handles the operation of context menus. It manages all service bus messages
|
||||
// starting with "contextmenus".
|
||||
type ContextMenus struct {
|
||||
quitChannel <-chan *servicebus.Message
|
||||
menuChannel <-chan *servicebus.Message
|
||||
running bool
|
||||
|
||||
// Event listeners
|
||||
listeners map[string][]func(*menu.MenuItem, string)
|
||||
menuItems map[string]*menu.MenuItem
|
||||
notifyLock sync.RWMutex
|
||||
|
||||
// logger
|
||||
logger logger.CustomLogger
|
||||
|
||||
// The context menus
|
||||
contextMenus *menu.ContextMenus
|
||||
|
||||
// Service Bus
|
||||
bus *servicebus.ServiceBus
|
||||
}
|
||||
|
||||
// NewContextMenus creates a new context menu subsystem
|
||||
func NewContextMenus(contextMenus *menu.ContextMenus, bus *servicebus.ServiceBus, logger *logger.Logger) (*ContextMenus, error) {
|
||||
|
||||
// Register quit channel
|
||||
quitChannel, err := bus.Subscribe("quit")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Subscribe to menu messages
|
||||
menuChannel, err := bus.Subscribe("contextmenus:")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &ContextMenus{
|
||||
quitChannel: quitChannel,
|
||||
menuChannel: menuChannel,
|
||||
logger: logger.CustomLogger("Context Menu Subsystem"),
|
||||
listeners: make(map[string][]func(*menu.MenuItem, string)),
|
||||
menuItems: make(map[string]*menu.MenuItem),
|
||||
contextMenus: contextMenus,
|
||||
bus: bus,
|
||||
}
|
||||
|
||||
// Build up list of item/id pairs
|
||||
result.processContextMenus(contextMenus)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type contextMenuData struct {
|
||||
MenuItemID string `json:"menuItemID"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
// Start the subsystem
|
||||
func (c *ContextMenus) Start() error {
|
||||
|
||||
c.logger.Trace("Starting")
|
||||
|
||||
c.running = true
|
||||
|
||||
// Spin off a go routine
|
||||
go func() {
|
||||
for c.running {
|
||||
select {
|
||||
case <-c.quitChannel:
|
||||
c.running = false
|
||||
break
|
||||
case menuMessage := <-c.menuChannel:
|
||||
splitTopic := strings.Split(menuMessage.Topic(), ":")
|
||||
menuMessageType := splitTopic[1]
|
||||
switch menuMessageType {
|
||||
case "clicked":
|
||||
if len(splitTopic) != 2 {
|
||||
c.logger.Error("Received clicked message with invalid topic format. Expected 2 sections in topic, got %s", splitTopic)
|
||||
continue
|
||||
}
|
||||
c.logger.Trace("Got Context Menu clicked Message: %s %+v", menuMessage.Topic(), menuMessage.Data())
|
||||
contextMenuDataJSON := menuMessage.Data().(string)
|
||||
|
||||
var data contextMenuData
|
||||
err := json.Unmarshal([]byte(contextMenuDataJSON), &data)
|
||||
if err != nil {
|
||||
c.logger.Trace("Cannot process contextMenuDataJSON %s", string(contextMenuDataJSON))
|
||||
return
|
||||
}
|
||||
|
||||
// Get the menu item
|
||||
menuItem := c.menuItems[data.MenuItemID]
|
||||
if menuItem == nil {
|
||||
c.logger.Trace("Cannot process menuitem id %s - unknown", data.MenuItemID)
|
||||
return
|
||||
}
|
||||
|
||||
// Is the menu item a checkbox?
|
||||
if menuItem.Type == menu.CheckboxType {
|
||||
// Toggle state
|
||||
menuItem.Checked = !menuItem.Checked
|
||||
}
|
||||
|
||||
// Notify listeners
|
||||
c.notifyListeners(data, menuItem)
|
||||
case "on":
|
||||
listenerDetails := menuMessage.Data().(*message.ContextMenusOnMessage)
|
||||
id := listenerDetails.MenuID
|
||||
c.listeners[id] = append(c.listeners[id], listenerDetails.Callback)
|
||||
|
||||
// Make sure we catch any menu updates
|
||||
case "update":
|
||||
updatedMenu := menuMessage.Data().(*menu.ContextMenus)
|
||||
c.processContextMenus(updatedMenu)
|
||||
|
||||
// Notify frontend of menu change
|
||||
c.bus.Publish("contextmenufrontend:update", updatedMenu)
|
||||
|
||||
default:
|
||||
c.logger.Error("unknown context menu message: %+v", menuMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call shutdown
|
||||
c.shutdown()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ContextMenus) processContextMenus(contextMenus *menu.ContextMenus) {
|
||||
// Initialise the variables
|
||||
c.menuItems = make(map[string]*menu.MenuItem)
|
||||
c.contextMenus = contextMenus
|
||||
|
||||
for _, contextMenu := range contextMenus.Items {
|
||||
for _, item := range contextMenu.Items {
|
||||
c.processMenuItem(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ContextMenus) processMenuItem(item *menu.MenuItem) {
|
||||
|
||||
if item.SubMenu != nil {
|
||||
for _, submenuitem := range item.SubMenu.Items {
|
||||
c.processMenuItem(submenuitem)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if item.ID != "" {
|
||||
if c.menuItems[item.ID] != nil {
|
||||
c.logger.Error("Context Menu id '%s' is used by multiple menu items: %s %s", c.menuItems[item.ID].Label, item.Label)
|
||||
return
|
||||
}
|
||||
c.menuItems[item.ID] = item
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies listeners that the given menu was clicked
|
||||
func (c *ContextMenus) notifyListeners(contextData contextMenuData, menuItem *menu.MenuItem) {
|
||||
|
||||
// Get list of menu listeners
|
||||
listeners := c.listeners[contextData.MenuItemID]
|
||||
if listeners == nil {
|
||||
c.logger.Trace("No listeners for MenuItem with ID '%s'", contextData.MenuItemID)
|
||||
return
|
||||
}
|
||||
|
||||
// Lock the listeners
|
||||
c.notifyLock.Lock()
|
||||
|
||||
// Callback in goroutine
|
||||
for _, listener := range listeners {
|
||||
go listener(menuItem, contextData.Data)
|
||||
}
|
||||
|
||||
// Unlock
|
||||
c.notifyLock.Unlock()
|
||||
}
|
||||
|
||||
func (c *ContextMenus) shutdown() {
|
||||
c.logger.Trace("Shutdown")
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
package subsystem
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
// Tray is the subsystem that handles the operation of the tray menu.
|
||||
// It manages all service bus messages starting with "tray".
|
||||
type Tray struct {
|
||||
quitChannel <-chan *servicebus.Message
|
||||
trayChannel <-chan *servicebus.Message
|
||||
running bool
|
||||
|
||||
// Event listeners
|
||||
listeners map[string][]func(*menu.MenuItem)
|
||||
menuItems map[string]*menu.MenuItem
|
||||
notifyLock sync.RWMutex
|
||||
|
||||
// logger
|
||||
logger logger.CustomLogger
|
||||
|
||||
// The tray menu
|
||||
trayMenu *menu.TrayMenu
|
||||
|
||||
// Service Bus
|
||||
bus *servicebus.ServiceBus
|
||||
}
|
||||
|
||||
// NewTray creates a new menu subsystem
|
||||
func NewTray(trayMenu *menu.TrayMenu, bus *servicebus.ServiceBus,
|
||||
logger *logger.Logger) (*Tray, error) {
|
||||
|
||||
// Register quit channel
|
||||
quitChannel, err := bus.Subscribe("quit")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Subscribe to menu messages
|
||||
trayChannel, err := bus.Subscribe("tray:")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &Tray{
|
||||
quitChannel: quitChannel,
|
||||
trayChannel: trayChannel,
|
||||
logger: logger.CustomLogger("TrayMenu Subsystem"),
|
||||
listeners: make(map[string][]func(*menu.MenuItem)),
|
||||
menuItems: make(map[string]*menu.MenuItem),
|
||||
trayMenu: trayMenu,
|
||||
bus: bus,
|
||||
}
|
||||
|
||||
// Build up list of item/id pairs
|
||||
result.processMenu(trayMenu.Menu)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Start the subsystem
|
||||
func (t *Tray) Start() error {
|
||||
|
||||
t.logger.Trace("Starting")
|
||||
|
||||
t.running = true
|
||||
|
||||
// Spin off a go routine
|
||||
go func() {
|
||||
for t.running {
|
||||
select {
|
||||
case <-t.quitChannel:
|
||||
t.running = false
|
||||
break
|
||||
case menuMessage := <-t.trayChannel:
|
||||
splitTopic := strings.Split(menuMessage.Topic(), ":")
|
||||
menuMessageType := splitTopic[1]
|
||||
switch menuMessageType {
|
||||
case "clicked":
|
||||
if len(splitTopic) != 2 {
|
||||
t.logger.Error("Received clicked message with invalid topic format. Expected 2 sections in topic, got %s", splitTopic)
|
||||
continue
|
||||
}
|
||||
t.logger.Trace("Got TrayMenu Menu clicked Message: %s %+v", menuMessage.Topic(), menuMessage.Data())
|
||||
menuid := menuMessage.Data().(string)
|
||||
|
||||
// Get the menu item
|
||||
menuItem := t.menuItems[menuid]
|
||||
if menuItem == nil {
|
||||
t.logger.Trace("Cannot process menuid %s - unknown", menuid)
|
||||
return
|
||||
}
|
||||
|
||||
// Is the menu item a checkbox?
|
||||
if menuItem.Type == menu.CheckboxType {
|
||||
// Toggle state
|
||||
menuItem.Checked = !menuItem.Checked
|
||||
}
|
||||
|
||||
// Notify listeners
|
||||
t.notifyListeners(menuid, menuItem)
|
||||
case "on":
|
||||
listenerDetails := menuMessage.Data().(*message.TrayOnMessage)
|
||||
id := listenerDetails.MenuID
|
||||
t.listeners[id] = append(t.listeners[id], listenerDetails.Callback)
|
||||
|
||||
// Make sure we catch any menu updates
|
||||
case "update":
|
||||
updatedMenu := menuMessage.Data().(*menu.Menu)
|
||||
t.processMenu(updatedMenu)
|
||||
|
||||
// Notify frontend of menu change
|
||||
t.bus.Publish("trayfrontend:update", updatedMenu)
|
||||
|
||||
// Make sure we catch any menu updates
|
||||
case "setlabel":
|
||||
updatedLabel := menuMessage.Data().(string)
|
||||
t.trayMenu.Label = updatedLabel
|
||||
|
||||
// Notify frontend of menu change
|
||||
t.bus.Publish("trayfrontend:setlabel", updatedLabel)
|
||||
|
||||
// Make sure we catch any icon updates
|
||||
case "seticon":
|
||||
iconname := menuMessage.Data().(string)
|
||||
t.trayMenu.Label = iconname
|
||||
|
||||
// Notify frontend of menu change
|
||||
t.bus.Publish("trayfrontend:seticon", iconname)
|
||||
|
||||
default:
|
||||
t.logger.Error("unknown tray message: %+v", menuMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call shutdown
|
||||
t.shutdown()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tray) processMenu(trayMenu *menu.Menu) {
|
||||
// Initialise the variables
|
||||
t.menuItems = make(map[string]*menu.MenuItem)
|
||||
t.trayMenu.Menu = trayMenu
|
||||
|
||||
for _, item := range trayMenu.Items {
|
||||
t.processMenuItem(item)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tray) processMenuItem(item *menu.MenuItem) {
|
||||
|
||||
if item.SubMenu != nil {
|
||||
for _, submenuitem := range item.SubMenu.Items {
|
||||
t.processMenuItem(submenuitem)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if item.ID != "" {
|
||||
if t.menuItems[item.ID] != nil {
|
||||
t.logger.Error("Menu id '%s' is used by multiple menu items: %s %s", t.menuItems[item.ID].Label, item.Label)
|
||||
return
|
||||
}
|
||||
t.menuItems[item.ID] = item
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies listeners that the given menu was clicked
|
||||
func (t *Tray) notifyListeners(menuid string, menuItem *menu.MenuItem) {
|
||||
|
||||
// Get list of menu listeners
|
||||
listeners := t.listeners[menuid]
|
||||
if listeners == nil {
|
||||
t.logger.Trace("No listeners for MenuItem with ID '%s'", menuid)
|
||||
return
|
||||
}
|
||||
|
||||
// Lock the listeners
|
||||
t.notifyLock.Lock()
|
||||
|
||||
// Callback in goroutine
|
||||
for _, listener := range listeners {
|
||||
go listener(menuItem)
|
||||
}
|
||||
|
||||
// Unlock
|
||||
t.notifyLock.Unlock()
|
||||
}
|
||||
|
||||
func (t *Tray) shutdown() {
|
||||
t.logger.Trace("Shutdown")
|
||||
}
|
||||
@@ -14,29 +14,6 @@ func (c *ContextMenus) AddMenu(ID string, menu *Menu) {
|
||||
c.Items[ID] = menu
|
||||
}
|
||||
|
||||
func (c *ContextMenus) GetByID(menuID string) *MenuItem {
|
||||
|
||||
// Loop over menu items
|
||||
for _, item := range c.Items {
|
||||
result := item.GetByID(menuID)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ContextMenus) RemoveByID(id string) bool {
|
||||
// Loop over menu items
|
||||
for _, item := range c.Items {
|
||||
result := item.RemoveByID(id)
|
||||
if result == true {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ContextMenu struct {
|
||||
ID string
|
||||
Menu *Menu
|
||||
|
||||
@@ -27,33 +27,6 @@ func NewMenuFromItems(first *MenuItem, rest ...*MenuItem) *Menu {
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *Menu) GetByID(menuID string) *MenuItem {
|
||||
|
||||
// Loop over menu items
|
||||
for _, item := range m.Items {
|
||||
result := item.getByID(menuID)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Menu) RemoveByID(id string) bool {
|
||||
// Loop over menu items
|
||||
for index, item := range m.Items {
|
||||
if item.ID == id {
|
||||
m.Items = append(m.Items[:index], m.Items[index+1:]...)
|
||||
return true
|
||||
}
|
||||
result := item.removeByID(id)
|
||||
if result == true {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Menu) setParent(menuItem *MenuItem) {
|
||||
for _, item := range m.Items {
|
||||
item.parent = menuItem
|
||||
|
||||
@@ -7,8 +7,6 @@ import (
|
||||
|
||||
// MenuItem represents a menuitem contained in a menu
|
||||
type MenuItem struct {
|
||||
// The unique identifier of this menu item
|
||||
ID string `json:"ID,omitempty"`
|
||||
// Label is what appears as the menu text
|
||||
Label string
|
||||
// Role is a predefined menu type
|
||||
@@ -75,29 +73,6 @@ func (m *MenuItem) Prepend(item *MenuItem) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MenuItem) getByID(id string) *MenuItem {
|
||||
|
||||
// If I have the ID return me!
|
||||
if m.ID == id {
|
||||
return m
|
||||
}
|
||||
|
||||
// If we have no submenu then exit early
|
||||
if m.SubMenu == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check submenus
|
||||
for _, submenu := range m.SubMenu.Items {
|
||||
result := submenu.getByID(id)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MenuItem) Remove() {
|
||||
// Iterate my parent's children
|
||||
m.Parent().removeChild(m)
|
||||
@@ -113,28 +88,6 @@ func (m *MenuItem) removeChild(item *MenuItem) {
|
||||
m.removeLock.Unlock()
|
||||
}
|
||||
|
||||
func (m *MenuItem) removeByID(id string) bool {
|
||||
|
||||
// If we have no submenu, return
|
||||
if m.SubMenu == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for index, item := range m.SubMenu.Items {
|
||||
if item.ID == id {
|
||||
m.SubMenu.Items = append(m.SubMenu.Items[:index], m.SubMenu.Items[index+1:]...)
|
||||
return true
|
||||
}
|
||||
if item.isSubMenu() {
|
||||
result := item.removeByID(id)
|
||||
if result == true {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InsertAfter attempts to add the given item after this item in the parent
|
||||
// menu. If there is no parent menu (we are a top level menu) then false is
|
||||
// returned
|
||||
@@ -250,9 +203,8 @@ 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, click Callback) *MenuItem {
|
||||
func Text(label string, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
return &MenuItem{
|
||||
ID: id,
|
||||
Label: label,
|
||||
Type: TextType,
|
||||
Accelerator: accelerator,
|
||||
@@ -268,9 +220,8 @@ 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, click Callback) *MenuItem {
|
||||
func Radio(label string, selected bool, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
return &MenuItem{
|
||||
ID: id,
|
||||
Label: label,
|
||||
Type: RadioType,
|
||||
Checked: selected,
|
||||
@@ -280,9 +231,8 @@ func Radio(label string, id string, selected bool, accelerator *keys.Accelerator
|
||||
}
|
||||
|
||||
// Checkbox is a helper to create basic Checkbox menu items
|
||||
func Checkbox(label string, id string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
func Checkbox(label string, checked bool, accelerator *keys.Accelerator, click Callback) *MenuItem {
|
||||
return &MenuItem{
|
||||
ID: id,
|
||||
Label: label,
|
||||
Type: CheckboxType,
|
||||
Checked: checked,
|
||||
@@ -305,11 +255,10 @@ func SubMenu(label string, menu *Menu) *MenuItem {
|
||||
}
|
||||
|
||||
// SubMenuWithID is a helper to create Submenus with an ID
|
||||
func SubMenuWithID(label string, id string, menu *Menu) *MenuItem {
|
||||
func SubMenuWithID(label string, menu *Menu) *MenuItem {
|
||||
result := &MenuItem{
|
||||
Label: label,
|
||||
SubMenu: menu,
|
||||
ID: id,
|
||||
Type: SubmenuType,
|
||||
}
|
||||
|
||||
|
||||
@@ -25,16 +25,16 @@ func (c *ContextMenu) WailsInit(runtime *wails.Runtime) error {
|
||||
func createContextMenus() *menu.ContextMenus {
|
||||
result := menu.NewContextMenus()
|
||||
result.AddMenu("test", menu.NewMenuFromItems(
|
||||
menu.Text("Clicked 0 times", "Test Context Menu", nil, nil),
|
||||
menu.Text("Clicked 0 times", nil, nil),
|
||||
menu.Separator(),
|
||||
menu.Checkbox("I am a checkbox", "checkbox", false, nil, nil),
|
||||
menu.Checkbox("I am a checkbox", false, nil, nil),
|
||||
menu.Separator(),
|
||||
menu.Radio("Radio Option 1", "Radio Option 1", true, nil, nil),
|
||||
menu.Radio("Radio Option 2", "Radio Option 2", false, nil, nil),
|
||||
menu.Radio("Radio Option 3", "Radio Option 3", false, nil, nil),
|
||||
menu.Radio("Radio Option 1", true, nil, nil),
|
||||
menu.Radio("Radio Option 2", false, nil, nil),
|
||||
menu.Radio("Radio Option 3", false, nil, nil),
|
||||
menu.Separator(),
|
||||
menu.SubMenu("A Submenu", menu.NewMenuFromItems(
|
||||
menu.Text("Hello", "Hello", nil, nil),
|
||||
menu.Text("Hello", nil, nil),
|
||||
)),
|
||||
))
|
||||
return result
|
||||
|
||||
@@ -54,13 +54,13 @@ func (m *Menu) addDynamicMenusOneMenu(data *menu.CallbackData) {
|
||||
parent := mi.Parent()
|
||||
counter := m.incrementcounter()
|
||||
menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
|
||||
newDynamicMenu := menu.Text(menuText, menuText, nil, nil)
|
||||
newDynamicMenu := menu.Text(menuText, nil, nil)
|
||||
m.dynamicMenuOneItems = append(m.dynamicMenuOneItems, newDynamicMenu)
|
||||
parent.Append(newDynamicMenu)
|
||||
|
||||
// If this is the first dynamic menu added, let's add a remove menu item
|
||||
if counter == 1 {
|
||||
m.removeMenuItem = menu.Text("Remove "+menuText, "Remove Last Item", keys.CmdOrCtrl("-"), m.removeDynamicMenuOneMenu)
|
||||
m.removeMenuItem = menu.Text("Remove "+menuText, keys.CmdOrCtrl("-"), m.removeDynamicMenuOneMenu)
|
||||
parent.Prepend(m.removeMenuItem)
|
||||
} else {
|
||||
// Test if the remove menu hasn't already been removed in another thread
|
||||
@@ -111,8 +111,8 @@ func (m *Menu) createDynamicMenuTwo(data *menu.CallbackData) {
|
||||
|
||||
// Create our submenu
|
||||
dm2 := menu.SubMenu("Dynamic Menus 2", menu.NewMenuFromItems(
|
||||
menu.Text("Insert Before Random Menu Item", "Insert Before Random", keys.CmdOrCtrl("]"), m.insertBeforeRandom),
|
||||
menu.Text("Insert After Random Menu Item", "Insert After Random", keys.CmdOrCtrl("["), m.insertAfterRandom),
|
||||
menu.Text("Insert Before Random Menu Item", keys.CmdOrCtrl("]"), m.insertBeforeRandom),
|
||||
menu.Text("Insert After Random Menu Item", keys.CmdOrCtrl("["), m.insertAfterRandom),
|
||||
menu.Separator(),
|
||||
))
|
||||
|
||||
@@ -126,7 +126,7 @@ func (m *Menu) createDynamicMenuTwo(data *menu.CallbackData) {
|
||||
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, nil)
|
||||
item := menu.Text(text, nil, nil)
|
||||
m.dynamicMenuItems[text] = item
|
||||
dm2.Append(item)
|
||||
}
|
||||
@@ -153,7 +153,7 @@ func (m *Menu) insertBeforeRandom(_ *menu.CallbackData) {
|
||||
|
||||
m.anotherDynamicMenuCounter++
|
||||
text := "Other Dynamic Menu Item " + strconv.Itoa(m.anotherDynamicMenuCounter)
|
||||
newItem := menu.Text(text, text, nil, nil)
|
||||
newItem := menu.Text(text, nil, nil)
|
||||
m.dynamicMenuItems[text] = newItem
|
||||
|
||||
m.runtime.Log.Info(fmt.Sprintf("Inserting menu item '%s' before menu item '%s'", newItem.Label, randomMenuItem.Label))
|
||||
@@ -176,7 +176,7 @@ func (m *Menu) insertAfterRandom(_ *menu.CallbackData) {
|
||||
|
||||
m.anotherDynamicMenuCounter++
|
||||
text := "Other Dynamic Menu Item " + strconv.Itoa(m.anotherDynamicMenuCounter)
|
||||
newItem := menu.Text(text, text, nil, nil)
|
||||
newItem := menu.Text(text, nil, nil)
|
||||
m.dynamicMenuItems[text] = newItem
|
||||
|
||||
m.runtime.Log.Info(fmt.Sprintf("Inserting menu item '%s' after menu item '%s'", newItem.Label, randomMenuItem.Label))
|
||||
@@ -192,8 +192,8 @@ func (m *Menu) processPlainText(callbackData *menu.CallbackData) {
|
||||
|
||||
func (m *Menu) createApplicationMenu() *menu.Menu {
|
||||
|
||||
m.dynamicMenuOneSubmenu = menu.SubMenuWithID("Dynamic Menus 1", "Dynamic Menus 1", menu.NewMenuFromItems(
|
||||
menu.Text("Add Menu Item", "Add Menu Item", keys.CmdOrCtrl("+"), m.addDynamicMenusOneMenu),
|
||||
m.dynamicMenuOneSubmenu = menu.SubMenuWithID("Dynamic Menus 1", menu.NewMenuFromItems(
|
||||
menu.Text("Add Menu Item", keys.CmdOrCtrl("+"), m.addDynamicMenusOneMenu),
|
||||
menu.Separator(),
|
||||
))
|
||||
|
||||
@@ -216,58 +216,58 @@ func (m *Menu) createApplicationMenu() *menu.Menu {
|
||||
menu.Front(),
|
||||
|
||||
menu.SubMenu("Test Submenu", menu.NewMenuFromItems(
|
||||
menu.Text("Plain text", "plain text", nil, m.processPlainText),
|
||||
menu.Text("Show Dynamic Menus 2 Submenu", "show-dynamic-menus-2", nil, m.createDynamicMenuTwo),
|
||||
menu.Text("Plain text", nil, m.processPlainText),
|
||||
menu.Text("Show Dynamic Menus 2 Submenu", nil, m.createDynamicMenuTwo),
|
||||
menu.SubMenu("Accelerators", menu.NewMenuFromItems(
|
||||
menu.SubMenu("Modifiers", menu.NewMenuFromItems(
|
||||
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.Text("Shift accelerator", keys.Shift("o"), nil),
|
||||
menu.Text("Control accelerator", keys.Control("o"), nil),
|
||||
menu.Text("Command accelerator", keys.CmdOrCtrl("o"), nil),
|
||||
menu.Text("Option accelerator", keys.OptionOrAlt("o"), nil),
|
||||
menu.Text("Combo accelerator", keys.Combo("o", keys.CmdOrCtrlKey, keys.ShiftKey), nil),
|
||||
)),
|
||||
menu.SubMenu("System Keys", menu.NewMenuFromItems(
|
||||
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.Text("Backspace", keys.Key("Backspace"), nil),
|
||||
menu.Text("Tab", keys.Key("Tab"), nil),
|
||||
menu.Text("Return", keys.Key("Return"), nil),
|
||||
menu.Text("Escape", keys.Key("Escape"), nil),
|
||||
menu.Text("Left", keys.Key("Left"), nil),
|
||||
menu.Text("Right", keys.Key("Right"), nil),
|
||||
menu.Text("Up", keys.Key("Up"), nil),
|
||||
menu.Text("Down", keys.Key("Down"), nil),
|
||||
menu.Text("Space", keys.Key("Space"), nil),
|
||||
menu.Text("Delete", keys.Key("Delete"), nil),
|
||||
menu.Text("Home", keys.Key("Home"), nil),
|
||||
menu.Text("End", keys.Key("End"), nil),
|
||||
menu.Text("Page Up", keys.Key("Page Up"), nil),
|
||||
menu.Text("Page Down", keys.Key("Page Down"), nil),
|
||||
menu.Text("NumLock", keys.Key("NumLock"), nil),
|
||||
)),
|
||||
menu.SubMenu("Function Keys", menu.NewMenuFromItems(
|
||||
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.Text("F1", keys.Key("F1"), nil),
|
||||
menu.Text("F2", keys.Key("F2"), nil),
|
||||
menu.Text("F3", keys.Key("F3"), nil),
|
||||
menu.Text("F4", keys.Key("F4"), nil),
|
||||
menu.Text("F5", keys.Key("F5"), nil),
|
||||
menu.Text("F6", keys.Key("F6"), nil),
|
||||
menu.Text("F7", keys.Key("F7"), nil),
|
||||
menu.Text("F8", keys.Key("F8"), nil),
|
||||
menu.Text("F9", keys.Key("F9"), nil),
|
||||
menu.Text("F10", keys.Key("F10"), nil),
|
||||
menu.Text("F11", keys.Key("F11"), nil),
|
||||
menu.Text("F12", keys.Key("F12"), nil),
|
||||
menu.Text("F13", keys.Key("F13"), nil),
|
||||
menu.Text("F14", keys.Key("F14"), nil),
|
||||
menu.Text("F15", keys.Key("F15"), nil),
|
||||
menu.Text("F16", keys.Key("F16"), nil),
|
||||
menu.Text("F17", keys.Key("F17"), nil),
|
||||
menu.Text("F18", keys.Key("F18"), nil),
|
||||
menu.Text("F19", keys.Key("F19"), nil),
|
||||
menu.Text("F20", keys.Key("F20"), nil),
|
||||
)),
|
||||
menu.SubMenu("Standard Keys", menu.NewMenuFromItems(
|
||||
menu.Text("Backtick", "Backtick", keys.Key("`"), nil),
|
||||
menu.Text("Plus", "Plus", keys.Key("+"), nil),
|
||||
menu.Text("Backtick", keys.Key("`"), nil),
|
||||
menu.Text("Plus", keys.Key("+"), nil),
|
||||
)),
|
||||
)),
|
||||
m.dynamicMenuOneSubmenu,
|
||||
@@ -283,7 +283,6 @@ func (m *Menu) createApplicationMenu() *menu.Menu {
|
||||
Hidden: true,
|
||||
},
|
||||
&menu.MenuItem{
|
||||
ID: "checkbox-menu 1",
|
||||
Label: "Checkbox Menu 1",
|
||||
Type: menu.CheckboxType,
|
||||
Accelerator: keys.CmdOrCtrl("l"),
|
||||
@@ -293,11 +292,11 @@ func (m *Menu) createApplicationMenu() *menu.Menu {
|
||||
fmt.Printf("It is now %v\n", data.MenuItem.Checked)
|
||||
},
|
||||
},
|
||||
menu.Checkbox("Checkbox Menu 2", "checkbox-menu 2", false, nil, nil),
|
||||
menu.Checkbox("Checkbox Menu 2", false, nil, nil),
|
||||
menu.Separator(),
|
||||
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),
|
||||
menu.Radio("😀 Option 1", true, nil, nil),
|
||||
menu.Radio("😺 Option 2", false, nil, nil),
|
||||
menu.Radio("❤️ Option 3", false, nil, nil),
|
||||
)),
|
||||
))
|
||||
|
||||
|
||||
@@ -127,10 +127,10 @@ func (t *Tray) createTrayMenus() []*menu.TrayMenu {
|
||||
trayMenu := &menu.TrayMenu{}
|
||||
trayMenu.Label = "Test Tray Label"
|
||||
trayMenu.Menu = menu.NewMenuFromItems(
|
||||
menu.Text("Show Window", "Show Window", nil, t.showWindow),
|
||||
menu.Text("Hide Window", "Hide Window", nil, t.hideWindow),
|
||||
menu.Text("Minimise Window", "Minimise Window", nil, t.minimiseWindow),
|
||||
menu.Text("Unminimise Window", "Unminimise Window", nil, t.unminimiseWindow),
|
||||
menu.Text("Show Window", nil, t.showWindow),
|
||||
menu.Text("Hide Window", nil, t.hideWindow),
|
||||
menu.Text("Minimise Window", nil, t.minimiseWindow),
|
||||
menu.Text("Unminimise Window", nil, t.unminimiseWindow),
|
||||
)
|
||||
t.trayMenu = trayMenu
|
||||
|
||||
@@ -138,7 +138,7 @@ func (t *Tray) createTrayMenus() []*menu.TrayMenu {
|
||||
secondTrayMenu.Label = "Another tray label"
|
||||
secondTrayMenu.Icon = "svelte"
|
||||
secondTrayMenu.Menu = menu.NewMenuFromItems(
|
||||
menu.Text("Update Label", "Update Label", nil, func(_ *menu.CallbackData) {
|
||||
menu.Text("Update Label", nil, func(_ *menu.CallbackData) {
|
||||
// Lock because this method will be called in a goroutine
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
@@ -149,10 +149,10 @@ func (t *Tray) createTrayMenus() []*menu.TrayMenu {
|
||||
t.runtime.Menu.UpdateTrayMenu(t.secondTrayMenu)
|
||||
}),
|
||||
menu.SubMenu("Select Icon", menu.NewMenuFromItems(
|
||||
menu.Text("Svelte", "Svelte", nil, t.SvelteIcon),
|
||||
menu.Text("Light", "Light", nil, t.LightIcon),
|
||||
menu.Text("Dark", "Dark", nil, t.DarkIcon),
|
||||
menu.Text("None", "None", nil, t.NoIcon),
|
||||
menu.Text("Svelte", nil, t.SvelteIcon),
|
||||
menu.Text("Light", nil, t.LightIcon),
|
||||
menu.Text("Dark", nil, t.DarkIcon),
|
||||
menu.Text("None", nil, t.NoIcon),
|
||||
)),
|
||||
)
|
||||
t.secondTrayMenu = secondTrayMenu
|
||||
|
||||
Reference in New Issue
Block a user