mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 05:08:54 -07:00
Support UpdateContextMenus. Submenus are now *menu.Menu. Tidy up++
This commit is contained in:
@@ -207,8 +207,6 @@ void ProcessContextMenus(ContextMenuStore* store) {
|
||||
|
||||
void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *contextMenuID, const char *contextMenuData) {
|
||||
|
||||
printf("Show context menu '%s'. Also got data '%s'.\n\n", contextMenuID, contextMenuData);
|
||||
|
||||
// If no context menu ID was given, abort
|
||||
if( contextMenuID == NULL ) {
|
||||
return;
|
||||
@@ -241,8 +239,6 @@ void ShowContextMenu(ContextMenuStore* store, id mainWindow, const char *context
|
||||
contextMenu->nsmenu = GetMenu(contextMenu->menu);
|
||||
}
|
||||
|
||||
printf("\n\nContext menu NSMenu = %p\n\n", contextMenu->menu->menu);
|
||||
|
||||
// Show popup
|
||||
msg(c("NSMenu"), s("popUpContextMenu:withEvent:forView:"), contextMenu->nsmenu, menuEvent, contentView);
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package ffenestri
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unsafe"
|
||||
@@ -152,7 +154,10 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug
|
||||
dispatcher = incomingDispatcher.RegisterClient(newClient(a))
|
||||
|
||||
// Process platform settings
|
||||
a.processPlatformSettings()
|
||||
err := a.processPlatformSettings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check we could initialise the application
|
||||
if app != nil {
|
||||
@@ -175,3 +180,28 @@ func (a *Application) Run(incomingDispatcher Dispatcher, bindings string, debug
|
||||
func messageFromWindowCallback(data *C.char) {
|
||||
dispatcher.DispatchMessage(C.GoString(data))
|
||||
}
|
||||
|
||||
type ProcessedContextMenu struct {
|
||||
ID string
|
||||
ProcessedMenu *ProcessedMenu
|
||||
}
|
||||
|
||||
func processContextMenus(contextMenus *menu.ContextMenus) (string, error) {
|
||||
var processedContextMenus []*ProcessedContextMenu
|
||||
|
||||
// We need to iterate each context menu and pre-process it
|
||||
for contextMenuID, contextMenu := range contextMenus.Items {
|
||||
thisContextMenu := &ProcessedContextMenu{
|
||||
ID: contextMenuID,
|
||||
ProcessedMenu: NewProcessedMenu(contextMenu),
|
||||
}
|
||||
processedContextMenus = append(processedContextMenus, thisContextMenu)
|
||||
}
|
||||
|
||||
contextMenusJSON, err := json.Marshal(processedContextMenus)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(contextMenusJSON), nil
|
||||
}
|
||||
|
||||
@@ -233,10 +233,10 @@ func (c *Client) UpdateContextMenus(contextMenus *menu.ContextMenus) {
|
||||
return
|
||||
}
|
||||
// Process the menu
|
||||
contextMenusJSON, err := json.Marshal(contextMenus)
|
||||
contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
if err != nil {
|
||||
c.app.logger.Error("Error processing updated Context Menus: %s", err.Error())
|
||||
c.app.logger.Error("Error processing updated Context Menu: %s", err.Error())
|
||||
return
|
||||
}
|
||||
C.UpdateContextMenus(c.app.app, c.app.string2CString(string(contextMenusJSON)))
|
||||
C.UpdateContextMenus(c.app.app, c.app.string2CString(contextMenusJSON))
|
||||
}
|
||||
|
||||
@@ -1805,17 +1805,19 @@ void UpdateTray(struct Application *app, const char *trayMenuAsJSON) {
|
||||
}
|
||||
|
||||
void UpdateContextMenus(struct Application *app, const char *contextMenusAsJSON) {
|
||||
// ON_MAIN_THREAD (
|
||||
//
|
||||
// dumpContextMenus(app);
|
||||
//
|
||||
// // Free up memory
|
||||
// destroyContextMenus(app);
|
||||
//
|
||||
// // Set the context menu JSON
|
||||
// app->contextMenusAsJSON = contextMenusAsJSON;
|
||||
// parseContextMenus(app);
|
||||
// );
|
||||
|
||||
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[]) {
|
||||
|
||||
@@ -24,7 +24,6 @@ extern void SetContextMenus(void *, const char *);
|
||||
import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
@@ -119,29 +118,11 @@ func (a *Application) processPlatformSettings() error {
|
||||
// Process context menus
|
||||
contextMenus := options.GetContextMenus(a.config)
|
||||
if contextMenus != nil {
|
||||
|
||||
type ProcessedContextMenu struct {
|
||||
ID string
|
||||
ProcessedMenu *ProcessedMenu
|
||||
}
|
||||
|
||||
var processedContextMenus []*ProcessedContextMenu
|
||||
|
||||
// We need to iterate each context menu and pre-process it
|
||||
for contextMenuID, contextMenu := range contextMenus.Items {
|
||||
thisContextMenu := &ProcessedContextMenu{
|
||||
ID: contextMenuID,
|
||||
ProcessedMenu: NewProcessedMenu(contextMenu),
|
||||
}
|
||||
processedContextMenus = append(processedContextMenus, thisContextMenu )
|
||||
}
|
||||
|
||||
contextMenusJSON, err := json.Marshal(processedContextMenus)
|
||||
fmt.Printf("\n\nCONTEXT MENUS:\n %+v\n\n", string(contextMenusJSON))
|
||||
contextMenusJSON, err := processContextMenus(contextMenus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
C.SetContextMenus(a.app, a.string2CString(string(contextMenusJSON)))
|
||||
C.SetContextMenus(a.app, a.string2CString(contextMenusJSON))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -51,7 +51,7 @@ func (p *ProcessedMenu) processMenuItem(item *menu.MenuItem) {
|
||||
p.finaliseRadioGroup()
|
||||
|
||||
// Process each submenu item
|
||||
for _, subitem := range item.SubMenu {
|
||||
for _, subitem := range item.SubMenu.Items {
|
||||
p.processMenuItem(subitem)
|
||||
}
|
||||
case menu.RadioType:
|
||||
|
||||
@@ -652,9 +652,15 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) {
|
||||
msg(thisMenuItem, s("setSubmenu:"), thisMenu);
|
||||
msg(parentMenu, s("addItem:"), thisMenuItem);
|
||||
|
||||
JsonNode *submenuItems = json_find_member(submenu, "Items");
|
||||
// If we have no items, just return
|
||||
if ( submenuItems == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop over submenu items
|
||||
JsonNode *item;
|
||||
json_foreach(item, submenu) {
|
||||
json_foreach(item, submenuItems) {
|
||||
// Get item label
|
||||
processMenuItem(menu, thisMenu, item);
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ func (c *ContextMenus) processContextMenus(contextMenus *menu.ContextMenus) {
|
||||
func (c *ContextMenus) processMenuItem(item *menu.MenuItem) {
|
||||
|
||||
if item.SubMenu != nil {
|
||||
for _, submenuitem := range item.SubMenu {
|
||||
for _, submenuitem := range item.SubMenu.Items {
|
||||
c.processMenuItem(submenuitem)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -153,7 +153,7 @@ func (m *Menu) processMenu(applicationMenu *menu.Menu) {
|
||||
func (m *Menu) processMenuItem(item *menu.MenuItem) {
|
||||
|
||||
if item.SubMenu != nil {
|
||||
for _, submenuitem := range item.SubMenu {
|
||||
for _, submenuitem := range item.SubMenu.Items {
|
||||
m.processMenuItem(submenuitem)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -160,7 +160,7 @@ func (t *Tray) processMenu(trayMenu *menu.Menu) {
|
||||
func (t *Tray) processMenuItem(item *menu.MenuItem) {
|
||||
|
||||
if item.SubMenu != nil {
|
||||
for _, submenuitem := range item.SubMenu {
|
||||
for _, submenuitem := range item.SubMenu.Items {
|
||||
t.processMenuItem(submenuitem)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -12,6 +12,10 @@ func (m *Menu) Append(item *MenuItem) {
|
||||
m.Items = append(m.Items, item)
|
||||
}
|
||||
|
||||
func (m *Menu) Prepend(item *MenuItem) {
|
||||
m.Items = append([]*MenuItem{item}, m.Items...)
|
||||
}
|
||||
|
||||
func NewMenuFromItems(first *MenuItem, rest ...*MenuItem) *Menu {
|
||||
|
||||
var result = NewMenu()
|
||||
@@ -49,3 +53,9 @@ func (m *Menu) RemoveByID(id string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Menu) setParent(menuItem *MenuItem) {
|
||||
for _, item := range m.Items {
|
||||
item.parent = menuItem
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ type MenuItem struct {
|
||||
// Checked indicates if the item is selected (used by Checkbox and Radio types only)
|
||||
Checked bool
|
||||
// Submenu contains a list of menu items that will be shown as a submenu
|
||||
SubMenu []*MenuItem `json:"SubMenu,omitempty"`
|
||||
//SubMenu []*MenuItem `json:"SubMenu,omitempty"`
|
||||
SubMenu *Menu `json:"SubMenu,omitempty"`
|
||||
|
||||
// Foreground colour in hex RGBA format EG: 0xFF0000FF = #FF0000FF = red
|
||||
Foreground int
|
||||
@@ -48,7 +49,7 @@ func (m *MenuItem) Append(item *MenuItem) bool {
|
||||
return false
|
||||
}
|
||||
item.parent = m
|
||||
m.SubMenu = append(m.SubMenu, item)
|
||||
m.SubMenu.Append(item)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -61,7 +62,7 @@ func (m *MenuItem) Prepend(item *MenuItem) bool {
|
||||
return false
|
||||
}
|
||||
item.parent = m
|
||||
m.SubMenu = append([]*MenuItem{item}, m.SubMenu...)
|
||||
m.SubMenu.Prepend(item)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -72,8 +73,13 @@ func (m *MenuItem) getByID(id string) *MenuItem {
|
||||
return m
|
||||
}
|
||||
|
||||
// If we have no submenu then exit early
|
||||
if m.SubMenu == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check submenus
|
||||
for _, submenu := range m.SubMenu {
|
||||
for _, submenu := range m.SubMenu.Items {
|
||||
result := submenu.getByID(id)
|
||||
if result != nil {
|
||||
return result
|
||||
@@ -85,9 +91,14 @@ func (m *MenuItem) getByID(id string) *MenuItem {
|
||||
|
||||
func (m *MenuItem) removeByID(id string) bool {
|
||||
|
||||
for index, item := range m.SubMenu {
|
||||
// If we have no submenu, return
|
||||
if m.SubMenu == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for index, item := range m.SubMenu.Items {
|
||||
if item.ID == id {
|
||||
m.SubMenu = append(m.SubMenu[:index], m.SubMenu[index+1:]...)
|
||||
m.SubMenu.Items = append(m.SubMenu.Items[:index], m.SubMenu.Items[index+1:]...)
|
||||
return true
|
||||
}
|
||||
if item.isSubMenu() {
|
||||
@@ -181,7 +192,7 @@ func (m *MenuItem) getItemIndex(target *MenuItem) int {
|
||||
}
|
||||
|
||||
// hunt down that bad boy
|
||||
for index, item := range m.SubMenu {
|
||||
for index, item := range m.SubMenu.Items {
|
||||
if item == target {
|
||||
return index
|
||||
}
|
||||
@@ -196,7 +207,7 @@ func (m *MenuItem) getItemIndex(target *MenuItem) int {
|
||||
func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool {
|
||||
|
||||
// If index is OOB, return false
|
||||
if index > len(m.SubMenu) {
|
||||
if index > len(m.SubMenu.Items) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -204,13 +215,13 @@ func (m *MenuItem) insertItemAtIndex(index int, target *MenuItem) bool {
|
||||
target.parent = m
|
||||
|
||||
// If index is last item, then just regular append
|
||||
if index == len(m.SubMenu) {
|
||||
m.SubMenu = append(m.SubMenu, target)
|
||||
if index == len(m.SubMenu.Items) {
|
||||
m.SubMenu.Items = append(m.SubMenu.Items, target)
|
||||
return true
|
||||
}
|
||||
|
||||
m.SubMenu = append(m.SubMenu[:index+1], m.SubMenu[index:]...)
|
||||
m.SubMenu[index] = target
|
||||
m.SubMenu.Items = append(m.SubMenu.Items[:index+1], m.SubMenu.Items[index:]...)
|
||||
m.SubMenu.Items[index] = target
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -254,34 +265,28 @@ func Checkbox(label string, id string, checked bool, accelerator *keys.Accelerat
|
||||
}
|
||||
|
||||
// SubMenu is a helper to create Submenus
|
||||
func SubMenu(label string, items []*MenuItem) *MenuItem {
|
||||
func SubMenu(label string, menu *Menu) *MenuItem {
|
||||
result := &MenuItem{
|
||||
Label: label,
|
||||
SubMenu: items,
|
||||
SubMenu: menu,
|
||||
Type: SubmenuType,
|
||||
}
|
||||
|
||||
// Fix up parent pointers
|
||||
for _, item := range items {
|
||||
item.parent = result
|
||||
}
|
||||
menu.setParent(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// SubMenuWithID is a helper to create Submenus with an ID
|
||||
func SubMenuWithID(label string, id string, items []*MenuItem) *MenuItem {
|
||||
func SubMenuWithID(label string, id string, menu *Menu) *MenuItem {
|
||||
result := &MenuItem{
|
||||
Label: label,
|
||||
SubMenu: items,
|
||||
SubMenu: menu,
|
||||
ID: id,
|
||||
Type: SubmenuType,
|
||||
}
|
||||
|
||||
// Fix up parent pointers
|
||||
for _, item := range items {
|
||||
item.parent = result
|
||||
}
|
||||
menu.setParent(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ func (c *ContextMenu) WailsInit(runtime *wails.Runtime) error {
|
||||
|
||||
// Setup Menu Listeners
|
||||
c.runtime.ContextMenu.On("Test Context Menu", func(mi *menu.MenuItem, contextData string) {
|
||||
fmt.Printf("\n\nContext Data = '%s'\n\n", contextData)
|
||||
c.lock.Lock()
|
||||
c.counter++
|
||||
mi.Label = fmt.Sprintf("Clicked %d times", c.counter)
|
||||
@@ -35,6 +34,18 @@ func (c *ContextMenu) WailsInit(runtime *wails.Runtime) error {
|
||||
|
||||
func createContextMenus() *menu.ContextMenus {
|
||||
result := menu.NewContextMenus()
|
||||
result.AddMenu("test", menu.NewMenuFromItems(menu.Text("Clicked 0 times", "Test Context Menu", nil)))
|
||||
result.AddMenu("test", menu.NewMenuFromItems(
|
||||
menu.Text("Clicked 0 times", "Test Context Menu", nil),
|
||||
menu.Separator(),
|
||||
menu.Checkbox("I am a checkbox", "checkbox", false, nil),
|
||||
menu.Separator(),
|
||||
menu.Radio("Radio Option 1", "Radio Option 1", true, nil),
|
||||
menu.Radio("Radio Option 2", "Radio Option 2", false, nil),
|
||||
menu.Radio("Radio Option 3", "Radio Option 3", false, nil),
|
||||
menu.Separator(),
|
||||
menu.SubMenu("A Submenu", menu.NewMenuFromItems(
|
||||
menu.Text("Hello", "Hello", nil),
|
||||
)),
|
||||
))
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -124,13 +124,13 @@ func (m *Menu) removeMenu(_ *menu.MenuItem) {
|
||||
func (m *Menu) createDynamicMenuTwo() {
|
||||
|
||||
// Create our submenu
|
||||
dm2 := menu.SubMenu("Dynamic Menus 2", []*menu.MenuItem{
|
||||
dm2 := menu.SubMenu("Dynamic Menus 2", menu.NewMenuFromItems(
|
||||
menu.Text("Insert Before Random Menu Item",
|
||||
"Insert Before Random", keys.CmdOrCtrl("]")),
|
||||
menu.Text("Insert After Random Menu Item",
|
||||
"Insert After Random", keys.CmdOrCtrl("[")),
|
||||
menu.Separator(),
|
||||
})
|
||||
))
|
||||
|
||||
m.runtime.Menu.On("Insert Before Random", m.insertBeforeRandom)
|
||||
m.runtime.Menu.On("Insert After Random", m.insertAfterRandom)
|
||||
@@ -229,7 +229,7 @@ func createApplicationMenu() *menu.Menu {
|
||||
// Create menu
|
||||
myMenu := menu.DefaultMacMenu()
|
||||
|
||||
windowMenu := menu.SubMenu("Test", []*menu.MenuItem{
|
||||
windowMenu := menu.SubMenu("Test", menu.NewMenuFromItems(
|
||||
menu.Togglefullscreen(),
|
||||
menu.Minimize(),
|
||||
menu.Zoom(),
|
||||
@@ -244,17 +244,17 @@ func createApplicationMenu() *menu.Menu {
|
||||
|
||||
menu.Front(),
|
||||
|
||||
menu.SubMenu("Test Submenu", []*menu.MenuItem{
|
||||
menu.SubMenu("Test Submenu", menu.NewMenuFromItems(
|
||||
menu.Text("Plain text", "plain text", nil),
|
||||
menu.Text("Show Dynamic Menus 2 Submenu", "show-dynamic-menus-2", nil),
|
||||
menu.SubMenu("Accelerators", []*menu.MenuItem{
|
||||
menu.SubMenu("Modifiers", []*menu.MenuItem{
|
||||
menu.SubMenu("Accelerators", menu.NewMenuFromItems(
|
||||
menu.SubMenu("Modifiers", menu.NewMenuFromItems(
|
||||
menu.Text("Shift accelerator", "Shift", keys.Shift("o")),
|
||||
menu.Text("Control accelerator", "Control", keys.Control("o")),
|
||||
menu.Text("Command accelerator", "Command", keys.CmdOrCtrl("o")),
|
||||
menu.Text("Option accelerator", "Option", keys.OptionOrAlt("o")),
|
||||
}),
|
||||
menu.SubMenu("System Keys", []*menu.MenuItem{
|
||||
)),
|
||||
menu.SubMenu("System Keys", menu.NewMenuFromItems(
|
||||
menu.Text("Backspace", "Backspace", keys.Key("Backspace")),
|
||||
menu.Text("Tab", "Tab", keys.Key("Tab")),
|
||||
menu.Text("Return", "Return", keys.Key("Return")),
|
||||
@@ -270,8 +270,8 @@ func createApplicationMenu() *menu.Menu {
|
||||
menu.Text("Page Up", "Page Up", keys.Key("Page Up")),
|
||||
menu.Text("Page Down", "Page Down", keys.Key("Page Down")),
|
||||
menu.Text("NumLock", "NumLock", keys.Key("NumLock")),
|
||||
}),
|
||||
menu.SubMenu("Function Keys", []*menu.MenuItem{
|
||||
)),
|
||||
menu.SubMenu("Function Keys", menu.NewMenuFromItems(
|
||||
menu.Text("F1", "F1", keys.Key("F1")),
|
||||
menu.Text("F2", "F2", keys.Key("F2")),
|
||||
menu.Text("F3", "F3", keys.Key("F3")),
|
||||
@@ -292,28 +292,28 @@ func createApplicationMenu() *menu.Menu {
|
||||
menu.Text("F18", "F18", keys.Key("F18")),
|
||||
menu.Text("F19", "F19", keys.Key("F19")),
|
||||
menu.Text("F20", "F20", keys.Key("F20")),
|
||||
}),
|
||||
menu.SubMenu("Standard Keys", []*menu.MenuItem{
|
||||
)),
|
||||
menu.SubMenu("Standard Keys", menu.NewMenuFromItems(
|
||||
menu.Text("Backtick", "Backtick", keys.Key("`")),
|
||||
menu.Text("Plus", "Plus", keys.Key("+")),
|
||||
}),
|
||||
}),
|
||||
menu.SubMenuWithID("Dynamic Menus 1", "Dynamic Menus 1", []*menu.MenuItem{
|
||||
)),
|
||||
)),
|
||||
menu.SubMenuWithID("Dynamic Menus 1", "Dynamic Menus 1", menu.NewMenuFromItems(
|
||||
menu.Text("Add Menu Item", "Add Menu Item", keys.CmdOrCtrl("+")),
|
||||
menu.Separator(),
|
||||
}),
|
||||
{
|
||||
)),
|
||||
&menu.MenuItem{
|
||||
Label: "Disabled Menu",
|
||||
Type: menu.TextType,
|
||||
Accelerator: keys.Combo("p", keys.CmdOrCtrlKey, keys.ShiftKey),
|
||||
Disabled: true,
|
||||
},
|
||||
{
|
||||
&menu.MenuItem{
|
||||
Label: "Hidden Menu",
|
||||
Type: menu.TextType,
|
||||
Hidden: true,
|
||||
},
|
||||
{
|
||||
&menu.MenuItem{
|
||||
ID: "checkbox-menu 1",
|
||||
Label: "Checkbox Menu 1",
|
||||
Type: menu.CheckboxType,
|
||||
@@ -325,8 +325,8 @@ func createApplicationMenu() *menu.Menu {
|
||||
menu.Radio("😀 Option 1", "😀option-1", true, nil),
|
||||
menu.Radio("😺 Option 2", "option-2", false, nil),
|
||||
menu.Radio("❤️ Option 3", "option-3", false, nil),
|
||||
}),
|
||||
})
|
||||
)),
|
||||
))
|
||||
|
||||
myMenu.Append(windowMenu)
|
||||
return myMenu
|
||||
|
||||
Reference in New Issue
Block a user