mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 22:55:48 +01:00
Updates for dynamic menus
Cleanup of logging
This commit is contained in:
parent
13dc0c78df
commit
e8bb950e06
7 changed files with 182 additions and 20 deletions
|
|
@ -71,7 +71,7 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
menuChannel, err := servicebus.Subscribe("menu:")
|
||||
menuChannel, err := servicebus.Subscribe("menufrontend:")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -422,7 +422,8 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
|||
|
||||
updatedMenu, ok := result.Data().(*menu.Menu)
|
||||
if !ok {
|
||||
d.logger.Error("Invalid data for 'dialog:select:open' : %#v", result.Data())
|
||||
d.logger.Error("Invalid data for 'menufrontend:update' : %#v",
|
||||
result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -433,6 +434,6 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
|||
}
|
||||
|
||||
default:
|
||||
d.logger.Error("Unknown dialog command: %s", command)
|
||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import (
|
|||
type Menu interface {
|
||||
On(menuID string, callback func(*menu.MenuItem))
|
||||
Update()
|
||||
GetByID(menuID string) *menu.MenuItem
|
||||
RemoveByID(id string) bool
|
||||
}
|
||||
|
||||
type menuRuntime struct {
|
||||
|
|
@ -36,3 +38,11 @@ func (m *menuRuntime) On(menuID string, callback func(*menu.MenuItem)) {
|
|||
func (m *menuRuntime) Update() {
|
||||
m.bus.Publish("menu:update", m.menu)
|
||||
}
|
||||
|
||||
func (m *menuRuntime) GetByID(menuID string) *menu.MenuItem {
|
||||
return m.menu.GetByID(menuID)
|
||||
}
|
||||
|
||||
func (m *menuRuntime) RemoveByID(id string) bool {
|
||||
return m.menu.RemoveByID(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ type Menu struct {
|
|||
|
||||
// The application menu
|
||||
applicationMenu *menu.Menu
|
||||
|
||||
// Service Bus
|
||||
bus *servicebus.ServiceBus
|
||||
}
|
||||
|
||||
// NewMenu creates a new menu subsystem
|
||||
|
|
@ -49,7 +52,7 @@ func NewMenu(applicationMenu *menu.Menu, bus *servicebus.ServiceBus, logger *log
|
|||
}
|
||||
|
||||
// Subscribe to menu messages
|
||||
menuChannel, err := bus.Subscribe("menu")
|
||||
menuChannel, err := bus.Subscribe("menu:")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -61,6 +64,7 @@ func NewMenu(applicationMenu *menu.Menu, bus *servicebus.ServiceBus, logger *log
|
|||
listeners: make(map[string][]func(*menu.MenuItem)),
|
||||
menuItems: make(map[string]*menu.MenuItem),
|
||||
applicationMenu: applicationMenu,
|
||||
bus: bus,
|
||||
}
|
||||
|
||||
// Build up list of item/id pairs
|
||||
|
|
@ -113,13 +117,16 @@ func (m *Menu) Start() error {
|
|||
case "on":
|
||||
listenerDetails := menuMessage.Data().(*message.MenuOnMessage)
|
||||
id := listenerDetails.MenuID
|
||||
// Check we have a menu with that id
|
||||
if m.menuItems[id] == nil {
|
||||
m.logger.Error("cannot register listener for unknown menu id '%s'", id)
|
||||
continue
|
||||
}
|
||||
// We do! Append the callback
|
||||
m.listeners[id] = append(m.listeners[id], listenerDetails.Callback)
|
||||
|
||||
// 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)
|
||||
|
||||
default:
|
||||
m.logger.Error("unknown menu message: %+v", menuMessage)
|
||||
}
|
||||
|
|
@ -133,8 +140,12 @@ func (m *Menu) Start() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *Menu) processMenu(menu *menu.Menu) {
|
||||
for _, item := range menu.Items {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,3 +22,30 @@ 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,53 @@ func (m *MenuItem) Append(item *MenuItem) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// Prepend will attempt to prepend the given menu item to
|
||||
// this item's submenu items. If this menu item is not a
|
||||
// submenu, then this method will not add the item and
|
||||
// simply return false.
|
||||
func (m *MenuItem) Prepend(item *MenuItem) bool {
|
||||
if m.Type != SubmenuType {
|
||||
return false
|
||||
}
|
||||
m.SubMenu = append([]*MenuItem{item}, m.SubMenu...)
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MenuItem) getByID(id string) *MenuItem {
|
||||
|
||||
// If I have the ID return me!
|
||||
if m.ID == id {
|
||||
return m
|
||||
}
|
||||
|
||||
// Check submenus
|
||||
for _, submenu := range m.SubMenu {
|
||||
result := submenu.getByID(id)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MenuItem) removeByID(id string) bool {
|
||||
|
||||
for index, item := range m.SubMenu {
|
||||
if item.ID == id {
|
||||
m.SubMenu = append(m.SubMenu[:index], m.SubMenu[index+1:]...)
|
||||
return true
|
||||
}
|
||||
if item.Type == SubmenuType {
|
||||
result := item.removeByID(id)
|
||||
if result == true {
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Text is a helper to create basic Text menu items
|
||||
func Text(label string, id string) *MenuItem {
|
||||
return TextWithAccelerator(label, id, nil)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
|
|||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/wailsapp/wails v1.8.0 h1:gnQhpwoGM8s2GD5PZrgMKU1PO3pQ9cdKKJgwtkNz2f4=
|
||||
github.com/wailsapp/wails v1.8.0/go.mod h1:XFZunea+USOCMMgBlz0A0JHLL3oWrRhnOl4baZlRpxo=
|
||||
github.com/wailsapp/wails v1.9.1 h1:ez/TK8YpU9lvOZ9nkgzUXsWu+xOPFVO57zTy0n5w3hc=
|
||||
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
wails "github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
|
|
@ -13,6 +14,7 @@ type Menu struct {
|
|||
runtime *wails.Runtime
|
||||
|
||||
dynamicMenuCounter int
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// WailsInit is called at application startup
|
||||
|
|
@ -37,12 +39,74 @@ func (m *Menu) WailsInit(runtime *wails.Runtime) error {
|
|||
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) addMenu(mi *menu.MenuItem) {
|
||||
|
||||
// Lock because this method will be called in a gorouting
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
// Get this menu's parent
|
||||
parent := mi.Parent()
|
||||
m.dynamicMenuCounter++
|
||||
menuText := "Dynamic Menu Item " + strconv.Itoa(m.dynamicMenuCounter)
|
||||
counter := m.incrementcounter()
|
||||
menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
|
||||
parent.Append(menu.Text(menuText, menuText))
|
||||
// parent.Append(menu.TextWithAccelerator(menuText, menuText, menu.Accel("[")))
|
||||
|
||||
// If this is the first dynamic menu added, let's add a remove menu item
|
||||
if counter == 1 {
|
||||
removeMenu := menu.TextWithAccelerator("Remove "+menuText,
|
||||
"Remove Last Item", menu.CmdOrCtrlAccel("-"))
|
||||
parent.Prepend(removeMenu)
|
||||
m.runtime.Menu.On("Remove Last Item", m.removeMenu)
|
||||
} else {
|
||||
removeMenu := m.runtime.Menu.GetByID("Remove Last Item")
|
||||
// Test if the remove menu hasn't already been removed in another thread
|
||||
if removeMenu != nil {
|
||||
removeMenu.Label = "Remove " + menuText
|
||||
}
|
||||
}
|
||||
m.runtime.Menu.Update()
|
||||
}
|
||||
|
||||
func (m *Menu) removeMenu(_ *menu.MenuItem) {
|
||||
|
||||
// Lock because this method will be called in a goroutine
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
// Get the id of the last dynamic menu
|
||||
menuID := "Dynamic Menu Item " + strconv.Itoa(m.dynamicMenuCounter)
|
||||
|
||||
// Remove the last menu item by ID
|
||||
m.runtime.Menu.RemoveByID(menuID)
|
||||
|
||||
// Update the counter
|
||||
counter := m.decrementcounter()
|
||||
|
||||
// If we deleted the last dynamic menu, remove the "Remove Last Item" menu
|
||||
if counter == 0 {
|
||||
m.runtime.Menu.RemoveByID("Remove Last Item")
|
||||
} else {
|
||||
// Update label
|
||||
menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
|
||||
removeMenu := m.runtime.Menu.GetByID("Remove Last Item")
|
||||
// Test if the remove menu hasn't already been removed in another thread
|
||||
if removeMenu == nil {
|
||||
return
|
||||
}
|
||||
removeMenu.Label = "Remove " + menuText
|
||||
}
|
||||
|
||||
// parent.Append(menu.TextWithAccelerator(menuText, menuText, menu.Accel("[")))
|
||||
m.runtime.Menu.Update()
|
||||
}
|
||||
|
|
@ -119,10 +183,10 @@ func createApplicationMenu() *menu.Menu {
|
|||
menu.TextWithAccelerator("Backtick", "Backtick", menu.Accel("`")),
|
||||
menu.TextWithAccelerator("Plus", "Plus", menu.Accel("+")),
|
||||
}),
|
||||
menu.SubMenu("Dynamic Menus", []*menu.MenuItem{
|
||||
menu.TextWithAccelerator("Add Menu Item", "Add Menu Item", menu.CmdOrCtrlAccel("+")),
|
||||
menu.Separator(),
|
||||
}),
|
||||
}),
|
||||
menu.SubMenu("Dynamic Menus", []*menu.MenuItem{
|
||||
menu.TextWithAccelerator("Add Menu Item", "Add Menu Item", menu.CmdOrCtrlAccel("+")),
|
||||
menu.Separator(),
|
||||
}),
|
||||
{
|
||||
Label: "Disabled Menu",
|
||||
|
|
@ -136,12 +200,13 @@ func createApplicationMenu() *menu.Menu {
|
|||
Hidden: true,
|
||||
},
|
||||
{
|
||||
ID: "checkbox-menu",
|
||||
Label: "Checkbox Menu",
|
||||
ID: "checkbox-menu 1",
|
||||
Label: "Checkbox Menu 1",
|
||||
Type: menu.CheckboxType,
|
||||
Accelerator: menu.CmdOrCtrlAccel("l"),
|
||||
Checked: true,
|
||||
},
|
||||
menu.Checkbox("Checkbox Menu 2", "checkbox-menu 2", false),
|
||||
menu.Separator(),
|
||||
menu.Radio("😀 Option 1", "😀option-1", true),
|
||||
menu.Radio("😺 Option 2", "option-2", false),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue