mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-14 07:59:30 +08:00
306 lines
9.0 KiB
Go
306 lines
9.0 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
|
"strconv"
|
|
"sync"
|
|
|
|
"github.com/wailsapp/wails/v2"
|
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
|
)
|
|
|
|
// Menu struct
|
|
type Menu struct {
|
|
runtime *wails.Runtime
|
|
|
|
dynamicMenuCounter int
|
|
dynamicMenuOneItems []*menu.MenuItem
|
|
lock sync.Mutex
|
|
dynamicMenuItems map[string]*menu.MenuItem
|
|
anotherDynamicMenuCounter int
|
|
|
|
// Menus
|
|
removeMenuItem *menu.MenuItem
|
|
dynamicMenuOneSubmenu *menu.MenuItem
|
|
}
|
|
|
|
// WailsInit is called at application startup
|
|
func (m *Menu) WailsInit(runtime *wails.Runtime) error {
|
|
// Perform your setup here
|
|
m.runtime = runtime
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Menu) incrementcounter() int {
|
|
m.dynamicMenuCounter++
|
|
return m.dynamicMenuCounter
|
|
}
|
|
|
|
func (m *Menu) decrementcounter() int {
|
|
m.dynamicMenuCounter--
|
|
return m.dynamicMenuCounter
|
|
}
|
|
|
|
func (m *Menu) addDynamicMenusOneMenu(data *menu.CallbackData) {
|
|
|
|
// Lock because this method will be called in a gorouting
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
|
|
// Get this menu's parent
|
|
mi := data.MenuItem
|
|
parent := mi.Parent()
|
|
counter := m.incrementcounter()
|
|
menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
|
|
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, keys.CmdOrCtrl("-"), m.removeDynamicMenuOneMenu)
|
|
parent.Prepend(m.removeMenuItem)
|
|
} else {
|
|
// Test if the remove menu hasn't already been removed in another thread
|
|
if m.removeMenuItem != nil {
|
|
m.removeMenuItem.Label = "Remove " + menuText
|
|
}
|
|
}
|
|
m.runtime.Menu.UpdateApplicationMenu()
|
|
}
|
|
|
|
func (m *Menu) removeDynamicMenuOneMenu(_ *menu.CallbackData) {
|
|
//
|
|
// Lock because this method will be called in a goroutine
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
|
|
// Get the last menu we added
|
|
lastItemIndex := len(m.dynamicMenuOneItems) - 1
|
|
lastMenuAdded := m.dynamicMenuOneItems[lastItemIndex]
|
|
|
|
// Remove from slice
|
|
m.dynamicMenuOneItems = m.dynamicMenuOneItems[:lastItemIndex]
|
|
|
|
// Remove the item from the menu
|
|
lastMenuAdded.Remove()
|
|
|
|
// Update the counter
|
|
counter := m.decrementcounter()
|
|
|
|
// If we deleted the last dynamic menu, remove the "Remove Last Item" menu
|
|
if counter == 0 {
|
|
// Remove it!
|
|
m.removeMenuItem.Remove()
|
|
} else {
|
|
// Update label
|
|
menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
|
|
m.removeMenuItem.Label = "Remove " + menuText
|
|
}
|
|
|
|
// parent.Append(menu.Text(menuText, menuText, menu.Key("[")))
|
|
m.runtime.Menu.UpdateApplicationMenu()
|
|
}
|
|
|
|
func (m *Menu) createDynamicMenuTwo(data *menu.CallbackData) {
|
|
|
|
// Hide this menu
|
|
data.MenuItem.Hidden = true
|
|
|
|
// Create our submenu
|
|
dm2 := menu.SubMenu("Dynamic Menus 2", menu.NewMenuFromItems(
|
|
menu.Text("Insert Before Random Menu Item", keys.CmdOrCtrl("]"), m.insertBeforeRandom),
|
|
menu.Text("Insert After Random Menu Item", keys.CmdOrCtrl("["), m.insertAfterRandom),
|
|
menu.Separator(),
|
|
))
|
|
|
|
//m.runtime.Menu.On("Insert Before Random", m.insertBeforeRandom)
|
|
//m.runtime.Menu.On("Insert After Random", m.insertAfterRandom)
|
|
|
|
// Initialise dynamicMenuItems
|
|
m.dynamicMenuItems = make(map[string]*menu.MenuItem)
|
|
|
|
// Create some random menu items
|
|
m.anotherDynamicMenuCounter = 5
|
|
for index := 0; index < m.anotherDynamicMenuCounter; index++ {
|
|
text := "Other Dynamic Menu Item " + strconv.Itoa(index+1)
|
|
item := menu.Text(text, nil, nil)
|
|
m.dynamicMenuItems[text] = item
|
|
dm2.Append(item)
|
|
}
|
|
|
|
m.dynamicMenuOneSubmenu.InsertAfter(dm2)
|
|
m.runtime.Menu.UpdateApplicationMenu()
|
|
}
|
|
|
|
func (m *Menu) insertBeforeRandom(_ *menu.CallbackData) {
|
|
|
|
// Lock because this method will be called in a goroutine
|
|
m.lock.Lock()
|
|
defer m.lock.Unlock()
|
|
|
|
// Pick a random menu
|
|
var randomMenuItem *menu.MenuItem
|
|
for _, randomMenuItem = range m.dynamicMenuItems {
|
|
break
|
|
}
|
|
|
|
if randomMenuItem == nil {
|
|
return
|
|
}
|
|
|
|
m.anotherDynamicMenuCounter++
|
|
text := "Other Dynamic Menu Item " + strconv.Itoa(m.anotherDynamicMenuCounter)
|
|
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))
|
|
|
|
randomMenuItem.InsertBefore(newItem)
|
|
m.runtime.Menu.UpdateApplicationMenu()
|
|
}
|
|
|
|
func (m *Menu) insertAfterRandom(_ *menu.CallbackData) {
|
|
|
|
// Pick a random menu
|
|
var randomMenuItem *menu.MenuItem
|
|
for _, randomMenuItem = range m.dynamicMenuItems {
|
|
break
|
|
}
|
|
|
|
if randomMenuItem == nil {
|
|
return
|
|
}
|
|
|
|
m.anotherDynamicMenuCounter++
|
|
text := "Other Dynamic Menu Item " + strconv.Itoa(m.anotherDynamicMenuCounter)
|
|
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))
|
|
|
|
randomMenuItem.InsertBefore(newItem)
|
|
m.runtime.Menu.UpdateApplicationMenu()
|
|
}
|
|
|
|
func (m *Menu) processPlainText(callbackData *menu.CallbackData) {
|
|
label := callbackData.MenuItem.Label
|
|
fmt.Printf("\n\n\n\n\n\n\nMenu Item label = `%s`\n\n\n\n\n", label)
|
|
}
|
|
|
|
func (m *Menu) createApplicationMenu() *menu.Menu {
|
|
|
|
m.dynamicMenuOneSubmenu = menu.SubMenuWithID("Dynamic Menus 1", menu.NewMenuFromItems(
|
|
menu.Text("Add Menu Item", keys.CmdOrCtrl("+"), m.addDynamicMenusOneMenu),
|
|
menu.Separator(),
|
|
))
|
|
|
|
// Create menu
|
|
myMenu := menu.DefaultMacMenu()
|
|
|
|
windowMenu := menu.SubMenu("Test", menu.NewMenuFromItems(
|
|
menu.Togglefullscreen(),
|
|
menu.Minimize(),
|
|
menu.Zoom(),
|
|
|
|
menu.Separator(),
|
|
|
|
menu.Copy(),
|
|
menu.Cut(),
|
|
menu.Delete(),
|
|
|
|
menu.Separator(),
|
|
|
|
menu.Front(),
|
|
|
|
menu.SubMenu("Test Submenu", menu.NewMenuFromItems(
|
|
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", 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", 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", 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", keys.Key("`"), nil),
|
|
menu.Text("Plus", keys.Key("+"), nil),
|
|
)),
|
|
)),
|
|
m.dynamicMenuOneSubmenu,
|
|
&menu.MenuItem{
|
|
Label: "Disabled Menu",
|
|
Type: menu.TextType,
|
|
Accelerator: keys.Combo("p", keys.CmdOrCtrlKey, keys.ShiftKey),
|
|
Disabled: true,
|
|
},
|
|
&menu.MenuItem{
|
|
Label: "Hidden Menu",
|
|
Type: menu.TextType,
|
|
Hidden: true,
|
|
},
|
|
&menu.MenuItem{
|
|
Label: "Checkbox Menu 1",
|
|
Type: menu.CheckboxType,
|
|
Accelerator: keys.CmdOrCtrl("l"),
|
|
Checked: true,
|
|
Click: func(data *menu.CallbackData) {
|
|
fmt.Printf("The '%s' menu was clicked\n", data.MenuItem.Label)
|
|
fmt.Printf("It is now %v\n", data.MenuItem.Checked)
|
|
},
|
|
},
|
|
menu.Checkbox("Checkbox Menu 2", false, nil, nil),
|
|
menu.Separator(),
|
|
menu.Radio("😀 Option 1", true, nil, nil),
|
|
menu.Radio("😺 Option 2", false, nil, nil),
|
|
menu.Radio("❤️ Option 3", false, nil, nil),
|
|
)),
|
|
))
|
|
|
|
myMenu.Append(windowMenu)
|
|
return myMenu
|
|
}
|