5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 20:03:01 +08:00

Support Menu updates!

This commit is contained in:
Lea Anthony 2021-01-11 11:21:28 +11:00
parent 7347d2caa2
commit 8053357d99
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
14 changed files with 233 additions and 187 deletions

View File

@ -33,7 +33,7 @@ extern void OpenDialog(void *appPointer, char *callbackID, char *title, char *fi
extern void SaveDialog(void *appPointer, char *callbackID, char *title, char *filters, char *defaultFilename, char *defaultDir, int showHiddenFiles, int canCreateDirectories, int treatPackagesAsDirectories);
extern void MessageDialog(void *appPointer, char *callbackID, char *type, char *title, char *message, char *icon, char *button1, char *button2, char *button3, char *button4, char *defaultButton, char *cancelButton);
extern void DarkModeEnabled(void *appPointer, char *callbackID);
extern void UpdateMenu(void *app, char *menuAsJSON);
extern void SetApplicationMenu(void *, const char *);
extern void UpdateTray(void *app, char *menuAsJSON);
extern void UpdateContextMenus(void *app, char *contextMenusAsJSON);
extern void UpdateTrayLabel(void *app, const char *label);

View File

@ -186,20 +186,8 @@ func (c *Client) DarkModeEnabled(callbackID string) {
C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
}
func (c *Client) UpdateMenu(menu *menu.Menu) {
// Guard against nil menus
if menu == nil {
return
}
// Process the menu
processedMenu := NewProcessedMenu(menu)
menuJSON, err := json.Marshal(processedMenu)
if err != nil {
c.app.logger.Error("Error processing updated Menu: %s", err.Error())
return
}
C.UpdateMenu(c.app.app, c.app.string2CString(string(menuJSON)))
func (c *Client) UpdateMenu(menuJSON string) {
C.SetApplicationMenu(c.app.app, c.app.string2CString(menuJSON))
}
func (c *Client) UpdateTray(menu *menu.Menu) {

View File

@ -485,68 +485,6 @@ void allocateTrayHashMaps(struct Application *app) {
}
}
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel) {
// Setup main application struct
struct Application *result = malloc(sizeof(struct Application));
result->title = title;
result->width = width;
result->height = height;
result->minWidth = 0;
result->minHeight = 0;
result->maxWidth = 0;
result->maxHeight = 0;
result->resizable = resizable;
result->devtools = devtools;
result->fullscreen = fullscreen;
result->maximised = 0;
result->startHidden = startHidden;
result->decorations = 0;
result->logLevel = logLevel;
result->mainWindow = NULL;
result->mouseEvent = NULL;
result->mouseDownMonitor = NULL;
result->mouseUpMonitor = NULL;
// Features
result->frame = 1;
result->hideTitle = 0;
result->hideTitleBar = 0;
result->fullSizeContent = 0;
result->useToolBar = 0;
result->hideToolbarSeparator = 0;
result->appearance = NULL;
result->windowBackgroundIsTranslucent = 0;
// Window data
result->delegate = NULL;
// Menu
result->applicationMenu = NULL;
// Tray
result->trayMenuAsJSON = NULL;
result->trayLabel = NULL;
result->trayIconName = NULL;
result->trayIconPosition = NSImageLeft; // Left of the text by default
result->processedTrayMenu = NULL;
result->statusItem = NULL;
// Context Menus
result->contextMenuStore = NULL;
result->contextMenusAsJSON = NULL;
result->processedContextMenus = NULL;
contextMenuData = NULL;
// Window Appearance
result->titlebarAppearsTransparent = 0;
result->webviewIsTranparent = 0;
result->sendMessageToBackend = (ffenestriCallback) messageFromWindowCallback;
return (void*) result;
}
int releaseNSObject(void *const context, struct hashmap_element_s *const e) {
msg(e->data, s("release"));
@ -1121,10 +1059,7 @@ void SetDebug(void *applicationPointer, int flag) {
debug = flag;
}
// SetMenu sets the initial menu for the application
void SetMenu(struct Application *app, const char *menuAsJSON) {
app->applicationMenu = NewApplicationMenu(menuAsJSON);
}
// SetTray sets the initial tray menu for the application
void SetTray(struct Application *app, const char *trayMenuAsJSON, const char *trayLabel, const char *trayIconName) {
@ -1623,8 +1558,8 @@ struct hashmap_s *radioGroupMap) {
}
// UpdateMenu replaces the current menu with the given one
void UpdateMenu(struct Application *app, const char *menuAsJSON) {
// updateMenu replaces the current menu with the given one
void updateMenu(struct Application *app, const char *menuAsJSON) {
Debug(app, "Menu is now: %s", menuAsJSON);
ON_MAIN_THREAD (
DeleteMenu(app->applicationMenu);
@ -1635,6 +1570,17 @@ void UpdateMenu(struct Application *app, const char *menuAsJSON) {
);
}
// SetApplicationMenu sets the initial menu for the application
void SetApplicationMenu(struct Application *app, const char *menuAsJSON) {
if ( app->applicationMenu == NULL ) {
app->applicationMenu = NewApplicationMenu(menuAsJSON);
return;
}
// Update menu
updateMenu(app, menuAsJSON);
}
//void dumpContextMenus(struct Application *app) {
// dumpHashmap("menuItemMapForContextMenus", &menuItemMapForContextMenus);
// printf("&menuItemMapForContextMenus = %p\n", &menuItemMapForContextMenus);
@ -2063,4 +2009,68 @@ void Run(struct Application *app, int argc, char **argv) {
MEMFREE(internalCode);
}
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel) {
// Setup main application struct
struct Application *result = malloc(sizeof(struct Application));
result->title = title;
result->width = width;
result->height = height;
result->minWidth = 0;
result->minHeight = 0;
result->maxWidth = 0;
result->maxHeight = 0;
result->resizable = resizable;
result->devtools = devtools;
result->fullscreen = fullscreen;
result->maximised = 0;
result->startHidden = startHidden;
result->decorations = 0;
result->logLevel = logLevel;
result->mainWindow = NULL;
result->mouseEvent = NULL;
result->mouseDownMonitor = NULL;
result->mouseUpMonitor = NULL;
// Features
result->frame = 1;
result->hideTitle = 0;
result->hideTitleBar = 0;
result->fullSizeContent = 0;
result->useToolBar = 0;
result->hideToolbarSeparator = 0;
result->appearance = NULL;
result->windowBackgroundIsTranslucent = 0;
// Window data
result->delegate = NULL;
// Menu
result->applicationMenu = NULL;
// Tray
result->trayMenuAsJSON = NULL;
result->trayLabel = NULL;
result->trayIconName = NULL;
result->trayIconPosition = NSImageLeft; // Left of the text by default
result->processedTrayMenu = NULL;
result->statusItem = NULL;
// Context Menus
result->contextMenuStore = NULL;
result->contextMenusAsJSON = NULL;
result->processedContextMenus = NULL;
contextMenuData = NULL;
// Window Appearance
result->titlebarAppearsTransparent = 0;
result->webviewIsTranparent = 0;
result->sendMessageToBackend = (ffenestriCallback) messageFromWindowCallback;
return (void*) result;
}
#endif

View File

@ -4,6 +4,7 @@ package ffenestri
#cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1
#cgo darwin LDFLAGS: -framework WebKit -lobjc
#include "ffenestri.h"
#include "ffenestri_darwin.h"
extern void TitlebarAppearsTransparent(void *);
@ -16,7 +17,6 @@ extern void DisableFrame(void *);
extern void SetAppearance(void *, const char *);
extern void WebviewIsTransparent(void *);
extern void WindowBackgroundIsTranslucent(void *);
extern void SetMenu(void *, const char *);
extern void SetTray(void *, const char *, const char *, const char *);
extern void SetContextMenus(void *, const char *);
@ -79,7 +79,7 @@ func (a *Application) processPlatformSettings() error {
//applicationMenu := options.GetApplicationMenu(a.config)
applicationMenu := a.menuManager.GetApplicationMenuJSON()
if applicationMenu != "" {
C.SetMenu(a.app, a.string2CString(applicationMenu))
C.SetApplicationMenu(a.app, a.string2CString(applicationMenu))
}
// Process tray

View File

@ -9,7 +9,10 @@
#include "contextmenustore_darwin.h"
enum MenuItemType {Text = 0, Checkbox = 1, Radio = 2};
enum MenuType {ApplicationMenuType = 0, ContextMenuType = 1};
enum MenuType {ApplicationMenuType = 0, ContextMenuType = 1, TrayMenuType = 2};
static const char *MenuTypeAsString[] = {
"ApplicationMenu", "ContextMenu", "TrayMenu",
};
extern void messageFromWindowCallback(const char *);
@ -133,14 +136,17 @@ void DeleteMenu(Menu *menu) {
}
// Creates a JSON message for the given menuItemID and data
const char* createMenuClickedMessage(const char *menuItemID, const char *data) {
const char* createMenuClickedMessage(const char *menuItemID, const char *data, enum MenuType menuType) {
JsonNode *jsonObject = json_mkobject();
json_append_member(jsonObject, "menuItemID", json_mkstring(menuItemID));
json_append_member(jsonObject, "menuType", json_mkstring(MenuTypeAsString[(int)menuType]));
if (data != NULL) {
json_append_member(jsonObject, "data", json_mkstring(data));
}
const char *result = json_encode(jsonObject);
const char *payload = json_encode(jsonObject);
json_delete(jsonObject);
const char *result = concat("MC", payload);
MEMFREE(payload);
return result;
}
@ -177,19 +183,19 @@ void menuItemCallback(id self, SEL cmd, id sender) {
msg(callbackData->menuItem, s("setState:"), NSControlStateValueOn);
}
const char *menuID = callbackData->menuID;
const char *data = NULL;
enum MenuType menuType = callbackData->menu->menuType;
// Generate message to send to backend
if( callbackData->menu->menuType == ApplicationMenuType ) {
const char *clickMessage = createMenuClickedMessage(callbackData->menuID, NULL);
message = concat("MC", clickMessage);
MEMFREE(clickMessage);
} else if( callbackData->menu->menuType == ContextMenuType ) {
if( menuType == ContextMenuType ) {
// Get the context menu data from the menu
ContextMenuStore* store = (ContextMenuStore*) callbackData->menu->parentData;
const char *clickMessage = createMenuClickedMessage(callbackData->menuID, store->contextMenuData);
message = concat("XC", clickMessage);
MEMFREE(clickMessage);
data = store->contextMenuData;
}
message = createMenuClickedMessage(menuID, data, menuType);
// TODO: Add other menu types here!
// Notify the backend

View File

@ -3,12 +3,17 @@ package menumanager
import (
"fmt"
"github.com/wailsapp/wails/v2/pkg/menu"
"sync"
)
// MenuItemMap holds a mapping between menuIDs and menu items
type MenuItemMap struct {
idToMenuItemMap map[string]*menu.MenuItem
menuItemToIDMap map[*menu.MenuItem]string
// We use a simple counter to keep track of unique menu IDs
menuIDCounter int64
menuIDCounterMutex sync.Mutex
}
func NewMenuItemMap() *MenuItemMap {
@ -37,6 +42,15 @@ func (m *MenuItemMap) Dump() {
}
}
// GenerateMenuID returns a unique string ID for a menu item
func (m *MenuItemMap) generateMenuID() string {
m.menuIDCounterMutex.Lock()
result := fmt.Sprintf("%d", m.menuIDCounter)
m.menuIDCounter++
m.menuIDCounterMutex.Unlock()
return result
}
func (m *MenuItemMap) processMenuItem(item *menu.MenuItem) {
if item.SubMenu != nil {
@ -46,9 +60,13 @@ func (m *MenuItemMap) processMenuItem(item *menu.MenuItem) {
}
// Create a unique ID for this menu item
menuID := fmt.Sprintf("%d", len(m.idToMenuItemMap))
menuID := m.generateMenuID()
// Store references
m.idToMenuItemMap[menuID] = item
m.menuItemToIDMap[item] = menuID
}
func (m *MenuItemMap) getMenuItemByID(menuId string) *menu.MenuItem {
return m.idToMenuItemMap[menuId]
}

View File

@ -11,13 +11,13 @@ type Manager struct {
applicationMenu *menu.Menu
applicationMenuJSON string
// Our menu mappings
menuItemMap *MenuItemMap
// Our application menu mappings
applicationMenuItemMap *MenuItemMap
}
func NewManager() *Manager {
return &Manager{
menuItemMap: NewMenuItemMap(),
applicationMenuItemMap: NewMenuItemMap(),
}
}
@ -26,7 +26,13 @@ func (m *Manager) SetApplicationMenu(applicationMenu *menu.Menu) error {
return nil
}
m.applicationMenu = applicationMenu
m.menuItemMap.AddMenu(applicationMenu)
// Reset the menu map
m.applicationMenuItemMap = NewMenuItemMap()
// Add the menu to the menu map
m.applicationMenuItemMap.AddMenu(applicationMenu)
return m.processApplicationMenu()
}
@ -34,10 +40,20 @@ func (m *Manager) GetApplicationMenuJSON() string {
return m.applicationMenuJSON
}
// UpdateApplicationMenu reprocesses the application menu to pick up structure
// changes etc
// Returns the JSON representation of the updated menu
func (m *Manager) UpdateApplicationMenu() (string, error) {
m.applicationMenuItemMap = NewMenuItemMap()
m.applicationMenuItemMap.AddMenu(m.applicationMenu)
err := m.processApplicationMenu()
return m.applicationMenuJSON, err
}
func (m *Manager) processApplicationMenu() error {
// Process the menu
processedApplicationMenu := m.NewWailsMenu(m.applicationMenu)
processedApplicationMenu := m.NewWailsMenu(m.applicationMenuItemMap, m.applicationMenu)
applicationMenuJSON, err := processedApplicationMenu.AsJSON()
if err != nil {
return err
@ -46,14 +62,27 @@ func (m *Manager) processApplicationMenu() error {
return nil
}
func (m *Manager) getMenuItemByID(menuId string) *menu.MenuItem {
return m.menuItemMap.idToMenuItemMap[menuId]
func (m *Manager) getMenuItemByID(menuMap *MenuItemMap, menuId string) *menu.MenuItem {
return menuMap.idToMenuItemMap[menuId]
}
func (m *Manager) ProcessClick(menuID string, data string) error {
func (m *Manager) ProcessClick(menuID string, data string, menuType string) error {
var menuItemMap *MenuItemMap
switch menuType {
case "ApplicationMenu":
menuItemMap = m.applicationMenuItemMap
//case "ContextMenu":
// // TBD
//case "TrayMenu":
// // TBD
default:
return fmt.Errorf("unknown menutype: %s", menuType)
}
// Get the menu item
menuItem := m.getMenuItemByID(menuID)
menuItem := menuItemMap.getMenuItemByID(menuID)
if menuItem == nil {
return fmt.Errorf("Cannot process menuid %s - unknown", menuID)
}

View File

@ -33,9 +33,9 @@ type ProcessedMenuItem struct {
Background int
}
func (m *Manager) NewProcessedMenuItem(menuItem *menu.MenuItem) *ProcessedMenuItem {
func (m *Manager) NewProcessedMenuItem(menuItemMap *MenuItemMap, menuItem *menu.MenuItem) *ProcessedMenuItem {
ID := m.menuItemMap.menuItemToIDMap[menuItem]
ID := menuItemMap.menuItemToIDMap[menuItem]
result := &ProcessedMenuItem{
ID: ID,
Label: menuItem.Label,
@ -50,7 +50,7 @@ func (m *Manager) NewProcessedMenuItem(menuItem *menu.MenuItem) *ProcessedMenuIt
}
if menuItem.SubMenu != nil {
result.SubMenu = m.NewProcessedMenu(menuItem.SubMenu)
result.SubMenu = m.NewProcessedMenu(menuItemMap, menuItem.SubMenu)
}
return result
@ -60,11 +60,11 @@ type ProcessedMenu struct {
Items []*ProcessedMenuItem
}
func (m *Manager) NewProcessedMenu(menu *menu.Menu) *ProcessedMenu {
func (m *Manager) NewProcessedMenu(menuItemMap *MenuItemMap, menu *menu.Menu) *ProcessedMenu {
result := &ProcessedMenu{}
for _, item := range menu.Items {
processedMenuItem := m.NewProcessedMenuItem(item)
processedMenuItem := m.NewProcessedMenuItem(menuItemMap, item)
result.Items = append(result.Items, processedMenuItem)
}
@ -85,11 +85,11 @@ type RadioGroup struct {
Length int
}
func (m *Manager) NewWailsMenu(menu *menu.Menu) *WailsMenu {
func (m *Manager) NewWailsMenu(menuItemMap *MenuItemMap, menu *menu.Menu) *WailsMenu {
result := &WailsMenu{}
// Process the menus
result.Menu = m.NewProcessedMenu(menu)
result.Menu = m.NewProcessedMenu(menuItemMap, menu)
// Process the radio groups
result.processRadioGroups()

View File

@ -32,7 +32,7 @@ type Client interface {
WindowUnFullscreen()
WindowSetColour(colour int)
DarkModeEnabled(callbackID string)
UpdateMenu(menu *menu.Menu)
UpdateMenu(menuJSON string)
UpdateTray(menu *menu.Menu)
UpdateTrayLabel(label string)
UpdateTrayIcon(name string)

View File

@ -449,11 +449,11 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
command := splitTopic[1]
switch command {
case "update":
case "updateappmenu":
updatedMenu, ok := result.Data().(*menu.Menu)
updatedMenu, ok := result.Data().(string)
if !ok {
d.logger.Error("Invalid data for 'menufrontend:update' : %#v",
d.logger.Error("Invalid data for 'menufrontend:updateappmenu' : %#v",
result.Data())
return
}

View File

@ -36,7 +36,7 @@ func (m *menuRuntime) On(menuID string, callback func(*menu.MenuItem)) {
}
func (m *menuRuntime) Update() {
m.bus.Publish("menu:update", m.menu)
m.bus.Publish("menu:updateappmenu", nil)
}
func (m *menuRuntime) GetByID(menuID string) *menu.MenuItem {

View File

@ -99,18 +99,19 @@ func (m *Menu) Start() error {
type ClickCallbackMessage struct {
MenuItemID string `json:"menuItemID"`
MenuType string `json:"menuType"`
Data string `json:"data"`
}
var callbackData ClickCallbackMessage
message := []byte(menuMessage.Data().(string))
err := json.Unmarshal(message, &callbackData)
payload := []byte(menuMessage.Data().(string))
err := json.Unmarshal(payload, &callbackData)
if err != nil {
m.logger.Error("%s", err.Error())
return
}
err = m.menuManager.ProcessClick(callbackData.MenuItemID, callbackData.Data)
err = m.menuManager.ProcessClick(callbackData.MenuItemID, callbackData.Data, callbackData.MenuType)
if err != nil {
m.logger.Trace("%s", err.Error())
}
@ -121,12 +122,17 @@ func (m *Menu) Start() error {
m.listeners[id] = append(m.listeners[id], listenerDetails.Callback)
// Make sure we catch any menu updates
case "update":
case "updateappmenu":
updatedMenu, err := m.menuManager.UpdateApplicationMenu()
if err != nil {
m.logger.Trace("%s", err.Error())
return
}
//updatedMenu := menuMessage.Data().(*menu.Menu)
//m.processMenu(updatedMenu)
//
//// Notify frontend of menu change
//m.bus.Publish("menufrontend:update", updatedMenu)
m.bus.Publish("menufrontend:updateappmenu", updatedMenu)
default:
m.logger.Error("unknown menu message: %+v", menuMessage)

View File

@ -148,6 +148,12 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
// Default go build command
commands := slicer.String([]string{"build"})
// Add better debugging flags
if options.Mode == Debug {
commands.Add("-gcflags")
commands.Add(`"all=-N -l"`)
}
// TODO: Work out if we can make this more efficient
// We need to do a full build as CGO doesn't detect updates
// to .h files, and we package assets into .h file. We could
@ -180,11 +186,6 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
}
}
// Add better debugging flags
if options.Mode == Debug {
commands.Add(`-gcflags=all="-N -l"`)
}
// Get application build directory
appDir := options.BuildDirectory
err := cleanBuildDirectory(options)
@ -210,6 +211,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
options.CompiledBinary = compiledBinary
// Create the command
fmt.Printf("Compile command: %+v", commands.AsSlice())
cmd := exec.Command(options.Compiler, commands.AsSlice()...)
// Set the directory

View File

@ -19,6 +19,9 @@ type Menu struct {
lock sync.Mutex
dynamicMenuItems map[string]*menu.MenuItem
anotherDynamicMenuCounter int
// Menus
removeMenuItem *menu.MenuItem
}
// WailsInit is called at application startup
@ -26,26 +29,6 @@ func (m *Menu) WailsInit(runtime *wails.Runtime) error {
// Perform your setup here
m.runtime = runtime
// Setup Menu Listeners
m.runtime.Menu.On("hello", func(mi *menu.MenuItem) {
fmt.Printf("The '%s' menu was clicked\n", mi.Label)
})
m.runtime.Menu.On("checkbox-menu", func(mi *menu.MenuItem) {
fmt.Printf("The '%s' menu was clicked\n", mi.Label)
fmt.Printf("It is now %v\n", mi.Checked)
})
m.runtime.Menu.On("😀option-1", func(mi *menu.MenuItem) {
fmt.Printf("We can use UTF-8 IDs: %s\n", mi.Label)
})
m.runtime.Menu.On("show-dynamic-menus-2", func(mi *menu.MenuItem) {
mi.Hidden = true
// Create dynamic menu items 2 submenu
m.createDynamicMenuTwo()
})
// Setup dynamic menus
m.runtime.Menu.On("Add Menu Item", m.addMenu)
return nil
}
@ -59,13 +42,14 @@ func (m *Menu) decrementcounter() int {
return m.dynamicMenuCounter
}
func (m *Menu) addMenu(mi *menu.MenuItem) {
func (m *Menu) addMenu(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)
@ -74,10 +58,8 @@ func (m *Menu) addMenu(mi *menu.MenuItem) {
// 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("-"), nil)
parent.Prepend(removeMenu)
m.runtime.Menu.On("Remove Last Item", m.removeMenu)
m.removeMenuItem = menu.Text("Remove "+menuText, "Remove Last Item", keys.CmdOrCtrl("-"), m.removeMenu)
parent.Prepend(m.removeMenuItem)
} else {
removeMenu := m.runtime.Menu.GetByID("Remove Last Item")
// Test if the remove menu hasn't already been removed in another thread
@ -88,40 +70,41 @@ func (m *Menu) addMenu(mi *menu.MenuItem) {
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.Text(menuText, menuText, menu.Key("[")))
m.runtime.Menu.Update()
func (m *Menu) removeMenu(_ *menu.CallbackData) {
//
//// Lock because this method will be called in a goroutine
//m.lock.Lock()
//defer m.lock.Unlock()
//
//// Remove the last menu item by ID
//m.runtime.Menu.RemoveMenuItem(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.Text(menuText, menuText, menu.Key("[")))
//m.runtime.Menu.Update()
}
func (m *Menu) createDynamicMenuTwo() {
func (m *Menu) createDynamicMenuTwo(data *menu.CallbackData) {
println("\n\n\n\n\n\n\nCreating dynamic menu two\n\n\n\n\n\n")
// Hide this menu
data.MenuItem.Hidden = true
// Create our submenu
dm2 := menu.SubMenu("Dynamic Menus 2", menu.NewMenuFromItems(
@ -251,7 +234,7 @@ func (m *Menu) createApplicationMenu() *menu.Menu {
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, nil),
menu.Text("Show Dynamic Menus 2 Submenu", "show-dynamic-menus-2", nil, m.createDynamicMenuTwo),
menu.SubMenu("Accelerators", menu.NewMenuFromItems(
menu.SubMenu("Modifiers", menu.NewMenuFromItems(
menu.Text("Shift accelerator", "Shift", keys.Shift("o"), nil),
@ -305,7 +288,7 @@ func (m *Menu) createApplicationMenu() *menu.Menu {
)),
)),
menu.SubMenuWithID("Dynamic Menus 1", "Dynamic Menus 1", menu.NewMenuFromItems(
menu.Text("Add Menu Item", "Add Menu Item", keys.CmdOrCtrl("+"), nil),
menu.Text("Add Menu Item", "Add Menu Item", keys.CmdOrCtrl("+"), m.addMenu),
menu.Separator(),
)),
&menu.MenuItem{
@ -325,6 +308,10 @@ func (m *Menu) createApplicationMenu() *menu.Menu {
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", "checkbox-menu 2", false, nil, nil),
menu.Separator(),