Updates for dynamic menus

Cleanup of logging
This commit is contained in:
Lea Anthony 2020-12-05 07:52:59 +11:00
commit e8bb950e06
No known key found for this signature in database
GPG key ID: 33DAF7BB90A58405
7 changed files with 182 additions and 20 deletions

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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)

View file

@ -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=

View file

@ -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),