mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 02:31:58 +08:00
Fixed and refactored context menu support
This commit is contained in:
parent
de06fc7dcc
commit
e65118e962
@ -63,10 +63,8 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
|
||||
// Process context menus
|
||||
contextMenus := options.GetContextMenus(appoptions)
|
||||
if contextMenus != nil {
|
||||
for contextMenuID, contextMenu := range contextMenus.Items {
|
||||
menuManager.AddContextMenu(contextMenuID, contextMenu)
|
||||
}
|
||||
for _, contextMenu := range contextMenus {
|
||||
menuManager.AddContextMenu(contextMenu)
|
||||
}
|
||||
|
||||
// Process tray menus
|
||||
|
@ -8,9 +8,20 @@
|
||||
#include "contextmenus_darwin.h"
|
||||
#include "menu_darwin.h"
|
||||
|
||||
ContextMenu* NewContextMenu(JsonNode* menuData, ContextMenuStore *store) {
|
||||
ContextMenu* NewContextMenu(const char* contextMenuJSON) {
|
||||
ContextMenu* result = malloc(sizeof(ContextMenu));
|
||||
result->menu = NewMenu(menuData);
|
||||
|
||||
JsonNode* processedJSON = json_decode(contextMenuJSON);
|
||||
if( processedJSON == NULL ) {
|
||||
ABORT("[NewTrayMenu] Unable to parse TrayMenu JSON: %s", contextMenuJSON);
|
||||
}
|
||||
// Save reference to this json
|
||||
result->processedJSON = processedJSON;
|
||||
|
||||
result->ID = mustJSONString(processedJSON, "ID");
|
||||
JsonNode* processedMenu = mustJSONObject(processedJSON, "ProcessedMenu");
|
||||
|
||||
result->menu = NewMenu(processedMenu);
|
||||
result->nsmenu = NULL;
|
||||
result->menu->menuType = ContextMenuType;
|
||||
result->menu->parentData = result;
|
||||
@ -18,9 +29,8 @@ ContextMenu* NewContextMenu(JsonNode* menuData, ContextMenuStore *store) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ContextMenu* GetContextMenuByID(ContextMenuStore* store, const char *contextMenuID) {
|
||||
return (ContextMenu*)hashmap_get(&store->contextMenuStore, (char*)contextMenuID, strlen(contextMenuID));
|
||||
return (ContextMenu*)hashmap_get(&store->contextMenuMap, (char*)contextMenuID, strlen(contextMenuID));
|
||||
}
|
||||
|
||||
void DeleteContextMenu(ContextMenu* contextMenu) {
|
||||
@ -32,6 +42,12 @@ void DeleteContextMenu(ContextMenu* contextMenu) {
|
||||
MEMFREE(contextMenu->contextMenuData);
|
||||
}
|
||||
|
||||
// Free JSON
|
||||
if (contextMenu->processedJSON != NULL ) {
|
||||
json_delete(contextMenu->processedJSON);
|
||||
contextMenu->processedJSON = NULL;
|
||||
}
|
||||
|
||||
// Free context menu
|
||||
free(contextMenu);
|
||||
}
|
||||
@ -41,43 +57,6 @@ int freeContextMenu(void *const context, struct hashmap_element_s *const e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ProcessContextMenus(ContextMenuStore* store) {
|
||||
|
||||
// Decode the context menus JSON
|
||||
store->processedContextMenus = json_decode(store->contextMenusAsJSON);
|
||||
if( store->processedContextMenus == NULL ) {
|
||||
ABORT("[ProcessContextMenus] Unable to parse Context Menus JSON: %s", store->contextMenusAsJSON);
|
||||
}
|
||||
|
||||
// // Get the context menu items
|
||||
// JsonNode *contextMenuItems = json_find_member(store->processedContextMenus, "Items");
|
||||
// if( contextMenuItems == NULL ) {
|
||||
// ABORT("[ProcessContextMenus] Unable to find Items in processedContextMenus!");
|
||||
// }
|
||||
|
||||
// Iterate context menus
|
||||
JsonNode *contextMenu;
|
||||
json_foreach(contextMenu, store->processedContextMenus) {
|
||||
|
||||
const char* ID = getJSONString(contextMenu, "ID");
|
||||
if ( ID == NULL ) {
|
||||
ABORT("Unable to read ID of contextMenu\n");
|
||||
}
|
||||
|
||||
JsonNode* processedMenu = json_find_member(contextMenu, "ProcessedMenu");
|
||||
if ( processedMenu == NULL ) {
|
||||
ABORT("Unable to read ProcessedMenu of contextMenu\n");
|
||||
}
|
||||
// Create a new context menu instance
|
||||
ContextMenu *thisContextMenu = NewContextMenu(processedMenu, store);
|
||||
thisContextMenu->ID = ID;
|
||||
|
||||
// Store the item in the context menu map
|
||||
hashmap_put(&store->contextMenuStore, (char*)ID, strlen(ID), thisContextMenu);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *contextMenuID, const char *contextMenuData) {
|
||||
|
||||
// If no context menu ID was given, abort
|
||||
|
@ -14,17 +14,19 @@ typedef struct {
|
||||
id nsmenu;
|
||||
Menu* menu;
|
||||
|
||||
// The optional data that may be passed with a context menu selection
|
||||
JsonNode* processedJSON;
|
||||
|
||||
// Context menu data is given by the frontend when clicking a context menu.
|
||||
// We send this to the backend when an item is selected
|
||||
const char* contextMenuData;
|
||||
} ContextMenu;
|
||||
|
||||
|
||||
ContextMenu* NewContextMenu(JsonNode* menuData, ContextMenuStore* store);
|
||||
ContextMenu* NewContextMenu(const char* contextMenuJSON);
|
||||
|
||||
ContextMenu* GetContextMenuByID( ContextMenuStore* store, const char *contextMenuID);
|
||||
void DeleteContextMenu(ContextMenu* contextMenu);
|
||||
int freeContextMenu(void *const context, struct hashmap_element_s *const e);
|
||||
void ProcessContextMenus( ContextMenuStore* store);
|
||||
|
||||
void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *contextMenuID, const char *contextMenuData);
|
||||
|
||||
|
@ -2,22 +2,48 @@
|
||||
#include "contextmenus_darwin.h"
|
||||
#include "contextmenustore_darwin.h"
|
||||
|
||||
ContextMenuStore* NewContextMenuStore(const char* contextMenusAsJSON) {
|
||||
ContextMenuStore* NewContextMenuStore() {
|
||||
|
||||
ContextMenuStore* result = malloc(sizeof(ContextMenuStore));
|
||||
|
||||
// Init members
|
||||
result->contextMenusAsJSON = contextMenusAsJSON;
|
||||
result->processedContextMenus = NULL;
|
||||
|
||||
// Allocate Context Menu Store
|
||||
if( 0 != hashmap_create((const unsigned)4, &result->contextMenuStore)) {
|
||||
if( 0 != hashmap_create((const unsigned)4, &result->contextMenuMap)) {
|
||||
ABORT("[NewContextMenus] Not enough memory to allocate contextMenuStore!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void AddContextMenuToStore(ContextMenuStore* store, const char* contextMenuJSON) {
|
||||
ContextMenu* newMenu = NewContextMenu(contextMenuJSON);
|
||||
|
||||
//TODO: check if there is already an entry for this menu
|
||||
hashmap_put(&store->contextMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||
}
|
||||
|
||||
ContextMenu* GetContextMenuFromStore(ContextMenuStore* store, const char* menuID) {
|
||||
// Get the current menu
|
||||
return hashmap_get(&store->contextMenuMap, menuID, strlen(menuID));
|
||||
}
|
||||
|
||||
void UpdateContextMenuInStore(ContextMenuStore* store, const char* menuJSON) {
|
||||
ContextMenu* newContextMenu = NewContextMenu(menuJSON);
|
||||
|
||||
// Get the current menu
|
||||
ContextMenu *currentMenu = GetContextMenuFromStore(store, newContextMenu->ID);
|
||||
if ( currentMenu == NULL ) {
|
||||
ABORT("Attempted to update unknown context menu with ID '%s'.", newContextMenu->ID);
|
||||
}
|
||||
|
||||
hashmap_remove(&store->contextMenuMap, newContextMenu->ID, strlen(newContextMenu->ID));
|
||||
|
||||
// Save the status bar reference
|
||||
DeleteContextMenu(currentMenu);
|
||||
|
||||
hashmap_put(&store->contextMenuMap, newContextMenu->ID, strlen(newContextMenu->ID), newContextMenu);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DeleteContextMenuStore(ContextMenuStore* store) {
|
||||
|
||||
@ -27,19 +53,13 @@ void DeleteContextMenuStore(ContextMenuStore* store) {
|
||||
}
|
||||
|
||||
// Delete context menus
|
||||
if( hashmap_num_entries(&store->contextMenuStore) > 0 ) {
|
||||
if (0 != hashmap_iterate_pairs(&store->contextMenuStore, freeContextMenu, NULL)) {
|
||||
if( hashmap_num_entries(&store->contextMenuMap) > 0 ) {
|
||||
if (0 != hashmap_iterate_pairs(&store->contextMenuMap, freeContextMenu, NULL)) {
|
||||
ABORT("[DeleteContextMenuStore] Failed to release contextMenuStore entries!");
|
||||
}
|
||||
}
|
||||
|
||||
// Free context menu hashmap
|
||||
hashmap_destroy(&store->contextMenuStore);
|
||||
|
||||
// Destroy processed Context Menus
|
||||
if( store->processedContextMenus != NULL) {
|
||||
json_delete(store->processedContextMenus);
|
||||
store->processedContextMenus = NULL;
|
||||
}
|
||||
hashmap_destroy(&store->contextMenuMap);
|
||||
|
||||
}
|
||||
|
@ -8,19 +8,20 @@
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
int dummy;
|
||||
|
||||
// This is our context menu store which keeps track
|
||||
// of all instances of ContextMenus
|
||||
struct hashmap_s contextMenuStore;
|
||||
|
||||
// The raw JSON defining the context menus
|
||||
const char* contextMenusAsJSON;
|
||||
|
||||
// The processed context menus
|
||||
JsonNode* processedContextMenus;
|
||||
struct hashmap_s contextMenuMap;
|
||||
|
||||
} ContextMenuStore;
|
||||
|
||||
ContextMenuStore* NewContextMenuStore(const char* contextMenusAsJSON);
|
||||
ContextMenuStore* NewContextMenuStore();
|
||||
|
||||
void DeleteContextMenuStore(ContextMenuStore* store);
|
||||
void UpdateContextMenuInStore(ContextMenuStore* store, const char* menuJSON);
|
||||
|
||||
void AddContextMenuToStore(ContextMenuStore* store, const char* contextMenuJSON);
|
||||
|
||||
#endif //CONTEXTMENUSTORE_DARWIN_H
|
||||
|
@ -35,11 +35,9 @@ extern void SaveDialog(struct Application*, char *callbackID, char *title, char
|
||||
extern void MessageDialog(struct Application*, 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(struct Application*, char *callbackID);
|
||||
extern void SetApplicationMenu(struct Application*, const char *);
|
||||
extern void UpdateTray(struct Application*, char *menuAsJSON);
|
||||
extern void UpdateContextMenus(struct Application*, char *contextMenusAsJSON);
|
||||
extern void UpdateTrayLabel(struct Application*, const char *label);
|
||||
extern void UpdateTrayIcon(struct Application*, const char *label);
|
||||
extern void AddTrayMenu(struct Application*, const char *trayAsJSON);
|
||||
extern void UpdateTrayMenu(struct Application*, const char *trayAsJSON);
|
||||
extern void AddTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||
extern void UpdateTrayMenu(struct Application*, const char *menuTrayJSON);
|
||||
extern void AddContextMenu(struct Application*, char *contextMenuJSON);
|
||||
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
|
||||
|
||||
#endif
|
||||
|
@ -12,7 +12,6 @@ package ffenestri
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"strconv"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
@ -193,17 +192,6 @@ func (c *Client) UpdateTrayMenu(trayMenuJSON string) {
|
||||
C.UpdateTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON))
|
||||
}
|
||||
|
||||
func (c *Client) UpdateContextMenus(contextMenus *menu.ContextMenus) {
|
||||
//
|
||||
// // Guard against nil contextMenus
|
||||
// if contextMenus == nil {
|
||||
// return
|
||||
// }
|
||||
// // Process the menu
|
||||
// contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
// if err != nil {
|
||||
// c.app.logger.Error("Error processing updated Context Menu: %s", err.Error())
|
||||
// return
|
||||
// }
|
||||
// C.UpdateContextMenus(c.app.app, c.app.string2CString(contextMenusJSON))
|
||||
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
|
||||
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
|
||||
}
|
||||
|
@ -117,8 +117,6 @@ struct Application {
|
||||
|
||||
// Context Menus
|
||||
ContextMenuStore *contextMenuStore;
|
||||
const char *contextMenusAsJSON;
|
||||
JsonNode *processedContextMenus;
|
||||
|
||||
// Callback
|
||||
ffenestriCallback sendMessageToBackend;
|
||||
@ -427,9 +425,12 @@ void DestroyApplication(struct Application *app) {
|
||||
DeleteMenu(app->applicationMenu);
|
||||
}
|
||||
|
||||
// Delete the tray menu store
|
||||
// Delete the tray menu store
|
||||
DeleteTrayMenuStore(app->trayMenuStore);
|
||||
|
||||
// Delete the context menu store
|
||||
DeleteContextMenuStore(app->contextMenuStore);
|
||||
|
||||
// Destroy the context menus
|
||||
destroyContextMenus(app);
|
||||
|
||||
@ -439,11 +440,6 @@ void DestroyApplication(struct Application *app) {
|
||||
// Unload the tray Icons
|
||||
UnloadTrayIcons();
|
||||
|
||||
// Clear context menu data if we have it
|
||||
if( contextMenuData != NULL ) {
|
||||
MEMFREE(contextMenuData);
|
||||
}
|
||||
|
||||
// Remove script handlers
|
||||
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("contextMenu"));
|
||||
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("windowDrag"));
|
||||
@ -916,17 +912,20 @@ void SetDebug(void *applicationPointer, int flag) {
|
||||
|
||||
|
||||
// SetContextMenus sets the context menu map for this application
|
||||
void SetContextMenus(struct Application *app, const char *contextMenusAsJSON) {
|
||||
app->contextMenuStore = NewContextMenuStore(contextMenusAsJSON);
|
||||
void AddContextMenu(struct Application *app, const char *contextMenuJSON) {
|
||||
AddContextMenuToStore(app->contextMenuStore, contextMenuJSON);
|
||||
}
|
||||
|
||||
|
||||
void AddTrayMenu(struct Application *app, const char *trayJSON) {
|
||||
AddTrayMenuToStore(app->trayMenuStore, trayJSON);
|
||||
void UpdateContextMenu(struct Application *app, const char* contextMenuJSON) {
|
||||
UpdateContextMenuInStore(app->contextMenuStore, contextMenuJSON);
|
||||
}
|
||||
|
||||
void UpdateTrayMenu(struct Application *app, const char* trayJSON) {
|
||||
UpdateTrayMenuInStore(app->trayMenuStore, trayJSON);
|
||||
void AddTrayMenu(struct Application *app, const char *trayMenuJSON) {
|
||||
AddTrayMenuToStore(app->trayMenuStore, trayMenuJSON);
|
||||
}
|
||||
|
||||
void UpdateTrayMenu(struct Application *app, const char* trayMenuJSON) {
|
||||
UpdateTrayMenuInStore(app->trayMenuStore, trayMenuJSON);
|
||||
}
|
||||
|
||||
void SetBindings(struct Application *app, const char *bindings) {
|
||||
@ -1428,84 +1427,6 @@ void SetApplicationMenu(struct Application *app, const char *menuAsJSON) {
|
||||
updateMenu(app, menuAsJSON);
|
||||
}
|
||||
|
||||
//void dumpContextMenus(struct Application *app) {
|
||||
// dumpHashmap("menuItemMapForContextMenus", &menuItemMapForContextMenus);
|
||||
// printf("&menuItemMapForContextMenus = %p\n", &menuItemMapForContextMenus);
|
||||
//
|
||||
// //Free radio groups hashmap
|
||||
// dumpHashmap("radioGroupMapForContextMenus", &radioGroupMapForContextMenus);
|
||||
// printf("&radioGroupMapForContextMenus = %p\n", &radioGroupMapForContextMenus);
|
||||
//
|
||||
// //Free context menu map
|
||||
// dumpHashmap("contextMenuMap", &contextMenuMap);
|
||||
// printf("&contextMenuMap = %p\n", &contextMenuMap);
|
||||
//}
|
||||
|
||||
//void parseContextMenus(struct Application *app) {
|
||||
//
|
||||
// // Parse the context menu json
|
||||
// app->processedContextMenus = json_decode(app->contextMenusAsJSON);
|
||||
//
|
||||
// if( app->processedContextMenus == NULL ) {
|
||||
// // Parse error!
|
||||
// Fatal(app, "Unable to parse Context Menus JSON: %s", app->contextMenusAsJSON);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// JsonNode *contextMenuItems = json_find_member(app->processedContextMenus, "Items");
|
||||
// if( contextMenuItems == NULL ) {
|
||||
// // Parse error!
|
||||
// Fatal(app, "Unable to find Items:", app->processedContextMenus);
|
||||
// return;
|
||||
// }
|
||||
// // Iterate context menus
|
||||
// JsonNode *contextMenu;
|
||||
// json_foreach(contextMenu, contextMenuItems) {
|
||||
// // Create a new menu
|
||||
// id menu = createMenu(str(""));
|
||||
//
|
||||
// // parse the menu
|
||||
// parseMenu(app, menu, contextMenu, &menuItemMapForContextMenus,
|
||||
// "checkboxMenuCallbackForContextMenus:", "radioMenuCallbackForContextMenus:", "menuCallbackForContextMenus:");
|
||||
//
|
||||
// // Store the item in the context menu map
|
||||
// hashmap_put(&contextMenuMap, (char*)contextMenu->key, strlen(contextMenu->key), menu);
|
||||
// }
|
||||
//
|
||||
//// dumpContextMenus(app);
|
||||
//}
|
||||
|
||||
void UpdateTrayLabel(struct Application *app, const char *label) {
|
||||
// TBD
|
||||
}
|
||||
|
||||
void UpdateTrayIcon(struct Application *app, const char *name) {
|
||||
// TBD
|
||||
}
|
||||
|
||||
// UpdateTray replaces the current tray menu with the given one
|
||||
void UpdateTray(struct Application *app, const char *trayMenuAsJSON) {
|
||||
ON_MAIN_THREAD (
|
||||
// TBD
|
||||
);
|
||||
}
|
||||
|
||||
void UpdateContextMenus(struct Application *app, const char *contextMenusAsJSON) {
|
||||
|
||||
ON_MAIN_THREAD (
|
||||
|
||||
// Free up memory
|
||||
DeleteContextMenuStore(app->contextMenuStore);
|
||||
|
||||
// Recreate Context Menus
|
||||
app->contextMenuStore = NewContextMenuStore(contextMenusAsJSON);
|
||||
|
||||
// Process them
|
||||
ProcessContextMenus(app->contextMenuStore);
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void processDialogIcons(struct hashmap_s *hashmap, const unsigned char *dialogIcons[]) {
|
||||
|
||||
unsigned int count = 0;
|
||||
@ -1727,11 +1648,6 @@ void Run(struct Application *app, int argc, char **argv) {
|
||||
// Setup initial trays
|
||||
ShowTrayMenusInStore(app->trayMenuStore);
|
||||
|
||||
// If we have context menus, process them
|
||||
if( app->contextMenuStore != NULL ) {
|
||||
ProcessContextMenus(app->contextMenuStore);
|
||||
}
|
||||
|
||||
// Process dialog icons
|
||||
processUserDialogIcons(app);
|
||||
|
||||
@ -1793,10 +1709,7 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
||||
result->trayMenuStore = NewTrayMenuStore();
|
||||
|
||||
// Context Menus
|
||||
result->contextMenuStore = NULL;
|
||||
result->contextMenusAsJSON = NULL;
|
||||
result->processedContextMenus = NULL;
|
||||
contextMenuData = NULL;
|
||||
result->contextMenuStore = NewContextMenuStore();
|
||||
|
||||
// Window Appearance
|
||||
result->titlebarAppearsTransparent = 0;
|
||||
|
@ -72,20 +72,20 @@ func (a *Application) processPlatformSettings() error {
|
||||
}
|
||||
if trays != nil {
|
||||
for _, tray := range trays {
|
||||
println("Adding tray menu: " + tray)
|
||||
C.AddTrayMenu(a.app, a.string2CString(tray))
|
||||
}
|
||||
}
|
||||
|
||||
// Process context menus
|
||||
//contextMenus := options.GetContextMenus(a.config)
|
||||
//if contextMenus != nil {
|
||||
// contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// C.SetContextMenus(a.app, a.string2CString(contextMenusJSON))
|
||||
//}
|
||||
contextMenus, err := a.menuManager.GetContextMenus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if contextMenus != nil {
|
||||
for _, contextMenu := range contextMenus {
|
||||
C.AddContextMenu(a.app, a.string2CString(contextMenu))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ void DumpTrayMenuStore(TrayMenuStore* store) {
|
||||
|
||||
void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON) {
|
||||
TrayMenu* newMenu = NewTrayMenu(menuJSON);
|
||||
|
||||
//TODO: check if there is already an entry for this menu
|
||||
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
|
||||
|
||||
}
|
||||
|
@ -1,47 +1,60 @@
|
||||
package menumanager
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
type ContextMenu struct {
|
||||
ID string
|
||||
JSON string
|
||||
menuItemMap *MenuItemMap
|
||||
menu *menu.Menu
|
||||
ID string
|
||||
ProcessedMenu *WailsMenu
|
||||
menuItemMap *MenuItemMap
|
||||
menu *menu.Menu
|
||||
}
|
||||
|
||||
func NewContextMenu(ID string, menu *menu.Menu) *ContextMenu {
|
||||
func (t *ContextMenu) AsJSON() (string, error) {
|
||||
data, err := json.Marshal(t)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func NewContextMenu(contextMenu *menu.ContextMenu) *ContextMenu {
|
||||
|
||||
result := &ContextMenu{
|
||||
ID: ID,
|
||||
JSON: "",
|
||||
menu: menu,
|
||||
ID: contextMenu.ID,
|
||||
menu: contextMenu.Menu,
|
||||
menuItemMap: NewMenuItemMap(),
|
||||
}
|
||||
|
||||
result.menuItemMap.AddMenu(menu)
|
||||
result.menuItemMap.AddMenu(contextMenu.Menu)
|
||||
result.ProcessedMenu = NewWailsMenu(result.menuItemMap, result.menu)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *Manager) AddContextMenu(menuID string, menu *menu.Menu) error {
|
||||
contextMenu := NewContextMenu(menuID, menu)
|
||||
m.contextMenus[menuID] = contextMenu
|
||||
return contextMenu.process()
|
||||
func (m *Manager) AddContextMenu(contextMenu *menu.ContextMenu) {
|
||||
|
||||
newContextMenu := NewContextMenu(contextMenu)
|
||||
|
||||
// Save the references
|
||||
m.contextMenus[contextMenu.ID] = newContextMenu
|
||||
m.contextMenuPointers[contextMenu] = contextMenu.ID
|
||||
}
|
||||
|
||||
func (c *ContextMenu) process() error {
|
||||
|
||||
// Process the menu
|
||||
processedApplicationMenu := NewWailsMenu(c.menuItemMap, c.menu)
|
||||
JSON, err := processedApplicationMenu.AsJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
func (m *Manager) UpdateContextMenu(contextMenu *menu.ContextMenu) (string, error) {
|
||||
contextMenuID, contextMenuKnown := m.contextMenuPointers[contextMenu]
|
||||
if !contextMenuKnown {
|
||||
return "", fmt.Errorf("unknown Context Menu '%s'. Please add the context menu using AddContextMenu()", contextMenu.ID)
|
||||
}
|
||||
c.JSON = JSON
|
||||
fmt.Printf("Processed context menu '%s':", c.ID)
|
||||
println(JSON)
|
||||
return nil
|
||||
|
||||
// Create the updated context menu
|
||||
updatedContextMenu := NewContextMenu(contextMenu)
|
||||
|
||||
// Save the reference
|
||||
m.contextMenus[contextMenuID] = updatedContextMenu
|
||||
|
||||
return updatedContextMenu.AsJSON()
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ type Manager struct {
|
||||
applicationMenuItemMap *MenuItemMap
|
||||
|
||||
// Context menus
|
||||
contextMenus map[string]*ContextMenu
|
||||
contextMenus map[string]*ContextMenu
|
||||
contextMenuPointers map[*menu.ContextMenu]string
|
||||
|
||||
// Tray menu stores
|
||||
trayMenus map[string]*TrayMenu
|
||||
@ -26,6 +27,7 @@ func NewManager() *Manager {
|
||||
return &Manager{
|
||||
applicationMenuItemMap: NewMenuItemMap(),
|
||||
contextMenus: make(map[string]*ContextMenu),
|
||||
contextMenuPointers: make(map[*menu.ContextMenu]string),
|
||||
trayMenus: make(map[string]*TrayMenu),
|
||||
trayMenuPointers: make(map[*menu.TrayMenu]string),
|
||||
}
|
||||
|
@ -90,3 +90,16 @@ func (m *Manager) GetTrayMenus() ([]string, error) {
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (m *Manager) GetContextMenus() ([]string, error) {
|
||||
result := []string{}
|
||||
for _, contextMenu := range m.contextMenus {
|
||||
JSON, err := contextMenu.AsJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, JSON)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package messagedispatcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/messagedispatcher/message"
|
||||
"github.com/wailsapp/wails/v2/internal/servicebus"
|
||||
@ -33,8 +31,8 @@ type Client interface {
|
||||
WindowSetColour(colour int)
|
||||
DarkModeEnabled(callbackID string)
|
||||
SetApplicationMenu(menuJSON string)
|
||||
UpdateTrayMenu(menuJSON string)
|
||||
UpdateContextMenus(contextMenus *menu.ContextMenus)
|
||||
UpdateTrayMenu(trayMenuJSON string)
|
||||
UpdateContextMenu(contextMenuJSON string)
|
||||
}
|
||||
|
||||
// DispatchClient is what the frontends use to interface with the
|
||||
|
@ -2,7 +2,6 @@ package messagedispatcher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -17,15 +16,14 @@ import (
|
||||
// Dispatcher translates messages received from the frontend
|
||||
// and publishes them onto the service bus
|
||||
type Dispatcher struct {
|
||||
quitChannel <-chan *servicebus.Message
|
||||
resultChannel <-chan *servicebus.Message
|
||||
eventChannel <-chan *servicebus.Message
|
||||
windowChannel <-chan *servicebus.Message
|
||||
dialogChannel <-chan *servicebus.Message
|
||||
systemChannel <-chan *servicebus.Message
|
||||
menuChannel <-chan *servicebus.Message
|
||||
contextMenuChannel <-chan *servicebus.Message
|
||||
running bool
|
||||
quitChannel <-chan *servicebus.Message
|
||||
resultChannel <-chan *servicebus.Message
|
||||
eventChannel <-chan *servicebus.Message
|
||||
windowChannel <-chan *servicebus.Message
|
||||
dialogChannel <-chan *servicebus.Message
|
||||
systemChannel <-chan *servicebus.Message
|
||||
menuChannel <-chan *servicebus.Message
|
||||
running bool
|
||||
|
||||
servicebus *servicebus.ServiceBus
|
||||
logger logger.CustomLogger
|
||||
@ -77,23 +75,17 @@ func New(servicebus *servicebus.ServiceBus, logger *logger.Logger) (*Dispatcher,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contextMenuChannel, err := servicebus.Subscribe("contextmenufrontend:")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &Dispatcher{
|
||||
servicebus: servicebus,
|
||||
eventChannel: eventChannel,
|
||||
logger: logger.CustomLogger("Message Dispatcher"),
|
||||
clients: make(map[string]*DispatchClient),
|
||||
resultChannel: resultChannel,
|
||||
quitChannel: quitChannel,
|
||||
windowChannel: windowChannel,
|
||||
dialogChannel: dialogChannel,
|
||||
systemChannel: systemChannel,
|
||||
menuChannel: menuChannel,
|
||||
contextMenuChannel: contextMenuChannel,
|
||||
servicebus: servicebus,
|
||||
eventChannel: eventChannel,
|
||||
logger: logger.CustomLogger("Message Dispatcher"),
|
||||
clients: make(map[string]*DispatchClient),
|
||||
resultChannel: resultChannel,
|
||||
quitChannel: quitChannel,
|
||||
windowChannel: windowChannel,
|
||||
dialogChannel: dialogChannel,
|
||||
systemChannel: systemChannel,
|
||||
menuChannel: menuChannel,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
@ -125,8 +117,6 @@ func (d *Dispatcher) Start() error {
|
||||
d.processSystemMessage(systemMessage)
|
||||
case menuMessage := <-d.menuChannel:
|
||||
d.processMenuMessage(menuMessage)
|
||||
case contextMenuMessage := <-d.contextMenuChannel:
|
||||
d.processContextMenuMessage(contextMenuMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,25 +458,10 @@ func (d *Dispatcher) processMenuMessage(result *servicebus.Message) {
|
||||
for _, client := range d.clients {
|
||||
client.frontend.UpdateTrayMenu(updatedTrayMenu)
|
||||
}
|
||||
|
||||
default:
|
||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||
}
|
||||
}
|
||||
func (d *Dispatcher) processContextMenuMessage(result *servicebus.Message) {
|
||||
splitTopic := strings.Split(result.Topic(), ":")
|
||||
if len(splitTopic) < 2 {
|
||||
d.logger.Error("Invalid contextmenu message : %#v", result.Data())
|
||||
return
|
||||
}
|
||||
|
||||
command := splitTopic[1]
|
||||
switch command {
|
||||
case "update":
|
||||
|
||||
updatedContextMenus, ok := result.Data().(*menu.ContextMenus)
|
||||
case "updatecontextmenu":
|
||||
updatedContextMenu, ok := result.Data().(string)
|
||||
if !ok {
|
||||
d.logger.Error("Invalid data for 'contextmenufrontend:update' : %#v",
|
||||
d.logger.Error("Invalid data for 'menufrontend:updatecontextmenu' : %#v",
|
||||
result.Data())
|
||||
return
|
||||
}
|
||||
@ -494,10 +469,10 @@ func (d *Dispatcher) processContextMenuMessage(result *servicebus.Message) {
|
||||
// TODO: Work out what we mean in a multi window environment...
|
||||
// For now we will just pick the first one
|
||||
for _, client := range d.clients {
|
||||
client.frontend.UpdateContextMenus(updatedContextMenus)
|
||||
client.frontend.UpdateContextMenu(updatedContextMenu)
|
||||
}
|
||||
|
||||
default:
|
||||
d.logger.Error("Unknown contextmenufrontend command: %s", command)
|
||||
d.logger.Error("Unknown menufrontend command: %s", command)
|
||||
}
|
||||
}
|
||||
|
@ -110,16 +110,16 @@ func (m *Menu) Start() error {
|
||||
m.bus.Publish("menufrontend:updateappmenu", updatedMenu)
|
||||
|
||||
case "updatecontextmenu":
|
||||
m.logger.Info("Update Context Menu TBD")
|
||||
//contextMenu := menuMessage.Data().(*menu.ContextMenu)
|
||||
//updatedMenu, err := m.menuManager.UpdateContextMenu(contextMenu)
|
||||
//if err != nil {
|
||||
// m.logger.Trace("%s", err.Error())
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//// Notify frontend of menu change
|
||||
//m.bus.Publish("menufrontend:updatecontextmenu", updatedMenu)
|
||||
contextMenu := menuMessage.Data().(*menu.ContextMenu)
|
||||
updatedMenu, err := m.menuManager.UpdateContextMenu(contextMenu)
|
||||
if err != nil {
|
||||
m.logger.Trace("%s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Notify frontend of menu change
|
||||
m.bus.Publish("menufrontend:updatecontextmenu", updatedMenu)
|
||||
|
||||
case "updatetraymenu":
|
||||
trayMenu := menuMessage.Data().(*menu.TrayMenu)
|
||||
updatedMenu, err := m.menuManager.UpdateTrayMenu(trayMenu)
|
||||
|
@ -1,19 +1,5 @@
|
||||
package menu
|
||||
|
||||
type ContextMenus struct {
|
||||
Items map[string]*Menu
|
||||
}
|
||||
|
||||
func NewContextMenus() *ContextMenus {
|
||||
return &ContextMenus{
|
||||
Items: make(map[string]*Menu),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ContextMenus) AddMenu(ID string, menu *Menu) {
|
||||
c.Items[ID] = menu
|
||||
}
|
||||
|
||||
type ContextMenu struct {
|
||||
ID string
|
||||
Menu *Menu
|
||||
|
@ -10,5 +10,5 @@ type Options struct {
|
||||
WindowBackgroundIsTranslucent bool
|
||||
Menu *menu.Menu
|
||||
TrayMenus []*menu.TrayMenu
|
||||
ContextMenus *menu.ContextMenus
|
||||
ContextMenus []*menu.ContextMenu
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ type App struct {
|
||||
StartHidden bool
|
||||
DevTools bool
|
||||
RGBA int
|
||||
ContextMenus *menu.ContextMenus
|
||||
ContextMenus []*menu.ContextMenu
|
||||
TrayMenus []*menu.TrayMenu
|
||||
Menu *menu.Menu
|
||||
Mac *mac.Options
|
||||
@ -89,15 +89,13 @@ func GetApplicationMenu(appoptions *App) *menu.Menu {
|
||||
return result
|
||||
}
|
||||
|
||||
func GetContextMenus(appoptions *App) *menu.ContextMenus {
|
||||
var result *menu.ContextMenus
|
||||
func GetContextMenus(appoptions *App) []*menu.ContextMenu {
|
||||
var result []*menu.ContextMenu
|
||||
|
||||
result = appoptions.ContextMenus
|
||||
var contextMenuOverrides *menu.ContextMenus
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
if appoptions.Mac != nil {
|
||||
contextMenuOverrides = appoptions.Mac.ContextMenus
|
||||
result = appoptions.Mac.ContextMenus
|
||||
}
|
||||
//case "linux":
|
||||
// if appoptions.Linux != nil {
|
||||
@ -109,11 +107,8 @@ func GetContextMenus(appoptions *App) *menu.ContextMenus {
|
||||
// }
|
||||
}
|
||||
|
||||
// Overwrite defaults with OS Specific context menus
|
||||
if contextMenuOverrides != nil {
|
||||
for id, contextMenu := range contextMenuOverrides.Items {
|
||||
result.AddMenu(id, contextMenu)
|
||||
}
|
||||
if result == nil {
|
||||
result = appoptions.ContextMenus
|
||||
}
|
||||
|
||||
return result
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
@ -9,9 +10,11 @@ import (
|
||||
|
||||
// ContextMenu struct
|
||||
type ContextMenu struct {
|
||||
runtime *wails.Runtime
|
||||
counter int
|
||||
lock sync.Mutex
|
||||
runtime *wails.Runtime
|
||||
counter int
|
||||
lock sync.Mutex
|
||||
testContextMenu *menu.ContextMenu
|
||||
clickedMenu *menu.MenuItem
|
||||
}
|
||||
|
||||
// WailsInit is called at application startup
|
||||
@ -22,10 +25,19 @@ func (c *ContextMenu) WailsInit(runtime *wails.Runtime) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createContextMenus() *menu.ContextMenus {
|
||||
result := menu.NewContextMenus()
|
||||
result.AddMenu("test", menu.NewMenuFromItems(
|
||||
menu.Text("Clicked 0 times", nil, nil),
|
||||
// Setup Menu Listeners
|
||||
func (c *ContextMenu) updateContextMenu(_ *menu.CallbackData) {
|
||||
c.lock.Lock()
|
||||
c.counter++
|
||||
c.clickedMenu.Label = fmt.Sprintf("Clicked %d times", c.counter)
|
||||
c.lock.Unlock()
|
||||
c.runtime.Menu.UpdateContextMenu(c.testContextMenu)
|
||||
}
|
||||
|
||||
func (c *ContextMenu) createContextMenus() []*menu.ContextMenu {
|
||||
c.clickedMenu = menu.Text("Clicked 0 times", nil, c.updateContextMenu)
|
||||
c.testContextMenu = menu.NewContextMenu("test", menu.NewMenuFromItems(
|
||||
c.clickedMenu,
|
||||
menu.Separator(),
|
||||
menu.Checkbox("I am a checkbox", false, nil, nil),
|
||||
menu.Separator(),
|
||||
@ -37,5 +49,7 @@ func createContextMenus() *menu.ContextMenus {
|
||||
menu.Text("Hello", nil, nil),
|
||||
)),
|
||||
))
|
||||
return result
|
||||
return []*menu.ContextMenu{
|
||||
c.testContextMenu,
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ func main() {
|
||||
|
||||
Menu := &Menu{}
|
||||
Tray := &Tray{}
|
||||
ContextMenu := &ContextMenu{}
|
||||
|
||||
// Create application with options
|
||||
app, err := wails.CreateAppWithOptions(&options.App{
|
||||
@ -23,7 +24,7 @@ func main() {
|
||||
//Tray: menu.NewMenuFromItems(menu.AppMenu()),
|
||||
//Menu: menu.NewMenuFromItems(menu.AppMenu()),
|
||||
//StartHidden: true,
|
||||
ContextMenus: createContextMenus(),
|
||||
ContextMenus: ContextMenu.createContextMenus(),
|
||||
Mac: &mac.Options{
|
||||
WebviewIsTransparent: true,
|
||||
WindowBackgroundIsTranslucent: true,
|
||||
@ -47,7 +48,7 @@ func main() {
|
||||
app.Bind(&Window{})
|
||||
app.Bind(Menu)
|
||||
app.Bind(Tray)
|
||||
app.Bind(&ContextMenu{})
|
||||
app.Bind(ContextMenu)
|
||||
|
||||
err = app.Run()
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user