5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-03 22:50:59 +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 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 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 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 UpdateTray(void *app, char *menuAsJSON);
extern void UpdateContextMenus(void *app, char *contextMenusAsJSON); extern void UpdateContextMenus(void *app, char *contextMenusAsJSON);
extern void UpdateTrayLabel(void *app, const char *label); 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)) C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
} }
func (c *Client) UpdateMenu(menu *menu.Menu) { func (c *Client) UpdateMenu(menuJSON string) {
C.SetApplicationMenu(c.app.app, c.app.string2CString(menuJSON))
// 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) UpdateTray(menu *menu.Menu) { 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) { int releaseNSObject(void *const context, struct hashmap_element_s *const e) {
msg(e->data, s("release")); msg(e->data, s("release"));
@ -1121,10 +1059,7 @@ void SetDebug(void *applicationPointer, int flag) {
debug = 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 // SetTray sets the initial tray menu for the application
void SetTray(struct Application *app, const char *trayMenuAsJSON, const char *trayLabel, const char *trayIconName) { 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 // updateMenu replaces the current menu with the given one
void UpdateMenu(struct Application *app, const char *menuAsJSON) { void updateMenu(struct Application *app, const char *menuAsJSON) {
Debug(app, "Menu is now: %s", menuAsJSON); Debug(app, "Menu is now: %s", menuAsJSON);
ON_MAIN_THREAD ( ON_MAIN_THREAD (
DeleteMenu(app->applicationMenu); 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) { //void dumpContextMenus(struct Application *app) {
// dumpHashmap("menuItemMapForContextMenus", &menuItemMapForContextMenus); // dumpHashmap("menuItemMapForContextMenus", &menuItemMapForContextMenus);
// printf("&menuItemMapForContextMenus = %p\n", &menuItemMapForContextMenus); // printf("&menuItemMapForContextMenus = %p\n", &menuItemMapForContextMenus);
@ -2063,4 +2009,68 @@ void Run(struct Application *app, int argc, char **argv) {
MEMFREE(internalCode); 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 #endif

View File

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

View File

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

View File

@ -3,12 +3,17 @@ package menumanager
import ( import (
"fmt" "fmt"
"github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/menu"
"sync"
) )
// MenuItemMap holds a mapping between menuIDs and menu items // MenuItemMap holds a mapping between menuIDs and menu items
type MenuItemMap struct { type MenuItemMap struct {
idToMenuItemMap map[string]*menu.MenuItem idToMenuItemMap map[string]*menu.MenuItem
menuItemToIDMap map[*menu.MenuItem]string 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 { 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) { func (m *MenuItemMap) processMenuItem(item *menu.MenuItem) {
if item.SubMenu != nil { if item.SubMenu != nil {
@ -46,9 +60,13 @@ func (m *MenuItemMap) processMenuItem(item *menu.MenuItem) {
} }
// Create a unique ID for this menu item // Create a unique ID for this menu item
menuID := fmt.Sprintf("%d", len(m.idToMenuItemMap)) menuID := m.generateMenuID()
// Store references // Store references
m.idToMenuItemMap[menuID] = item m.idToMenuItemMap[menuID] = item
m.menuItemToIDMap[item] = menuID 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 applicationMenu *menu.Menu
applicationMenuJSON string applicationMenuJSON string
// Our menu mappings // Our application menu mappings
menuItemMap *MenuItemMap applicationMenuItemMap *MenuItemMap
} }
func NewManager() *Manager { func NewManager() *Manager {
return &Manager{ return &Manager{
menuItemMap: NewMenuItemMap(), applicationMenuItemMap: NewMenuItemMap(),
} }
} }
@ -26,7 +26,13 @@ func (m *Manager) SetApplicationMenu(applicationMenu *menu.Menu) error {
return nil return nil
} }
m.applicationMenu = applicationMenu 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() return m.processApplicationMenu()
} }
@ -34,10 +40,20 @@ func (m *Manager) GetApplicationMenuJSON() string {
return m.applicationMenuJSON 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 { func (m *Manager) processApplicationMenu() error {
// Process the menu // Process the menu
processedApplicationMenu := m.NewWailsMenu(m.applicationMenu) processedApplicationMenu := m.NewWailsMenu(m.applicationMenuItemMap, m.applicationMenu)
applicationMenuJSON, err := processedApplicationMenu.AsJSON() applicationMenuJSON, err := processedApplicationMenu.AsJSON()
if err != nil { if err != nil {
return err return err
@ -46,14 +62,27 @@ func (m *Manager) processApplicationMenu() error {
return nil return nil
} }
func (m *Manager) getMenuItemByID(menuId string) *menu.MenuItem { func (m *Manager) getMenuItemByID(menuMap *MenuItemMap, menuId string) *menu.MenuItem {
return m.menuItemMap.idToMenuItemMap[menuId] 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 // Get the menu item
menuItem := m.getMenuItemByID(menuID) menuItem := menuItemMap.getMenuItemByID(menuID)
if menuItem == nil { if menuItem == nil {
return fmt.Errorf("Cannot process menuid %s - unknown", menuID) return fmt.Errorf("Cannot process menuid %s - unknown", menuID)
} }

View File

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

View File

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

View File

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

View File

@ -36,7 +36,7 @@ func (m *menuRuntime) On(menuID string, callback func(*menu.MenuItem)) {
} }
func (m *menuRuntime) Update() { 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 { func (m *menuRuntime) GetByID(menuID string) *menu.MenuItem {

View File

@ -99,18 +99,19 @@ func (m *Menu) Start() error {
type ClickCallbackMessage struct { type ClickCallbackMessage struct {
MenuItemID string `json:"menuItemID"` MenuItemID string `json:"menuItemID"`
MenuType string `json:"menuType"`
Data string `json:"data"` Data string `json:"data"`
} }
var callbackData ClickCallbackMessage var callbackData ClickCallbackMessage
message := []byte(menuMessage.Data().(string)) payload := []byte(menuMessage.Data().(string))
err := json.Unmarshal(message, &callbackData) err := json.Unmarshal(payload, &callbackData)
if err != nil { if err != nil {
m.logger.Error("%s", err.Error()) m.logger.Error("%s", err.Error())
return return
} }
err = m.menuManager.ProcessClick(callbackData.MenuItemID, callbackData.Data) err = m.menuManager.ProcessClick(callbackData.MenuItemID, callbackData.Data, callbackData.MenuType)
if err != nil { if err != nil {
m.logger.Trace("%s", err.Error()) m.logger.Trace("%s", err.Error())
} }
@ -121,12 +122,17 @@ func (m *Menu) Start() error {
m.listeners[id] = append(m.listeners[id], listenerDetails.Callback) m.listeners[id] = append(m.listeners[id], listenerDetails.Callback)
// Make sure we catch any menu updates // 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) //updatedMenu := menuMessage.Data().(*menu.Menu)
//m.processMenu(updatedMenu) //m.processMenu(updatedMenu)
// //
//// Notify frontend of menu change //// Notify frontend of menu change
//m.bus.Publish("menufrontend:update", updatedMenu) m.bus.Publish("menufrontend:updateappmenu", updatedMenu)
default: default:
m.logger.Error("unknown menu message: %+v", menuMessage) 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 // Default go build command
commands := slicer.String([]string{"build"}) 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 // TODO: Work out if we can make this more efficient
// We need to do a full build as CGO doesn't detect updates // 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 // 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 // Get application build directory
appDir := options.BuildDirectory appDir := options.BuildDirectory
err := cleanBuildDirectory(options) err := cleanBuildDirectory(options)
@ -210,6 +211,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
options.CompiledBinary = compiledBinary options.CompiledBinary = compiledBinary
// Create the command // Create the command
fmt.Printf("Compile command: %+v", commands.AsSlice())
cmd := exec.Command(options.Compiler, commands.AsSlice()...) cmd := exec.Command(options.Compiler, commands.AsSlice()...)
// Set the directory // Set the directory

View File

@ -19,6 +19,9 @@ type Menu struct {
lock sync.Mutex lock sync.Mutex
dynamicMenuItems map[string]*menu.MenuItem dynamicMenuItems map[string]*menu.MenuItem
anotherDynamicMenuCounter int anotherDynamicMenuCounter int
// Menus
removeMenuItem *menu.MenuItem
} }
// WailsInit is called at application startup // WailsInit is called at application startup
@ -26,26 +29,6 @@ func (m *Menu) WailsInit(runtime *wails.Runtime) error {
// Perform your setup here // Perform your setup here
m.runtime = runtime 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 return nil
} }
@ -59,13 +42,14 @@ func (m *Menu) decrementcounter() int {
return m.dynamicMenuCounter 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 // Lock because this method will be called in a gorouting
m.lock.Lock() m.lock.Lock()
defer m.lock.Unlock() defer m.lock.Unlock()
// Get this menu's parent // Get this menu's parent
mi := data.MenuItem
parent := mi.Parent() parent := mi.Parent()
counter := m.incrementcounter() counter := m.incrementcounter()
menuText := "Dynamic Menu Item " + strconv.Itoa(counter) 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 this is the first dynamic menu added, let's add a remove menu item
if counter == 1 { if counter == 1 {
removeMenu := menu.Text("Remove "+menuText, m.removeMenuItem = menu.Text("Remove "+menuText, "Remove Last Item", keys.CmdOrCtrl("-"), m.removeMenu)
"Remove Last Item", keys.CmdOrCtrl("-"), nil) parent.Prepend(m.removeMenuItem)
parent.Prepend(removeMenu)
m.runtime.Menu.On("Remove Last Item", m.removeMenu)
} else { } else {
removeMenu := m.runtime.Menu.GetByID("Remove Last Item") removeMenu := m.runtime.Menu.GetByID("Remove Last Item")
// Test if the remove menu hasn't already been removed in another thread // 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() m.runtime.Menu.Update()
} }
func (m *Menu) removeMenu(_ *menu.MenuItem) { func (m *Menu) removeMenu(_ *menu.CallbackData) {
//
// Lock because this method will be called in a goroutine //// Lock because this method will be called in a goroutine
m.lock.Lock() //m.lock.Lock()
defer m.lock.Unlock() //defer m.lock.Unlock()
//
// Get the id of the last dynamic menu //// Remove the last menu item by ID
menuID := "Dynamic Menu Item " + strconv.Itoa(m.dynamicMenuCounter) //m.runtime.Menu.RemoveMenuItem(menuID)
//
// Remove the last menu item by ID //// Update the counter
m.runtime.Menu.RemoveByID(menuID) //counter := m.decrementcounter()
//
// Update the counter //// If we deleted the last dynamic menu, remove the "Remove Last Item" menu
counter := m.decrementcounter() //if counter == 0 {
// m.runtime.Menu.RemoveByID("Remove Last Item")
// If we deleted the last dynamic menu, remove the "Remove Last Item" menu //} else {
if counter == 0 { // // Update label
m.runtime.Menu.RemoveByID("Remove Last Item") // menuText := "Dynamic Menu Item " + strconv.Itoa(counter)
} else { // removeMenu := m.runtime.Menu.GetByID("Remove Last Item")
// Update label // // Test if the remove menu hasn't already been removed in another thread
menuText := "Dynamic Menu Item " + strconv.Itoa(counter) // if removeMenu == nil {
removeMenu := m.runtime.Menu.GetByID("Remove Last Item") // return
// Test if the remove menu hasn't already been removed in another thread // }
if removeMenu == nil { // removeMenu.Label = "Remove " + menuText
return //}
} //
removeMenu.Label = "Remove " + menuText //// parent.Append(menu.Text(menuText, menuText, menu.Key("[")))
} //m.runtime.Menu.Update()
// 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 // Create our submenu
dm2 := menu.SubMenu("Dynamic Menus 2", menu.NewMenuFromItems( 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.SubMenu("Test Submenu", menu.NewMenuFromItems(
menu.Text("Plain text", "plain text", nil, m.processPlainText), 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("Accelerators", menu.NewMenuFromItems(
menu.SubMenu("Modifiers", menu.NewMenuFromItems( menu.SubMenu("Modifiers", menu.NewMenuFromItems(
menu.Text("Shift accelerator", "Shift", keys.Shift("o"), nil), 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.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.Separator(),
)), )),
&menu.MenuItem{ &menu.MenuItem{
@ -325,6 +308,10 @@ func (m *Menu) createApplicationMenu() *menu.Menu {
Type: menu.CheckboxType, Type: menu.CheckboxType,
Accelerator: keys.CmdOrCtrl("l"), Accelerator: keys.CmdOrCtrl("l"),
Checked: true, 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.Checkbox("Checkbox Menu 2", "checkbox-menu 2", false, nil, nil),
menu.Separator(), menu.Separator(),