github.com/secoba/wails/v2@v2.6.4/internal/frontend/desktop/darwin/menu.go (about)

     1  //go:build darwin
     2  // +build darwin
     3  
     4  package darwin
     5  
     6  /*
     7  #cgo CFLAGS: -x objective-c
     8  #cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
     9  #import <Foundation/Foundation.h>
    10  #import "Application.h"
    11  #import "WailsContext.h"
    12  
    13  #include <stdlib.h>
    14  */
    15  import "C"
    16  
    17  import (
    18  	"unsafe"
    19  
    20  	"github.com/secoba/wails/v2/pkg/menu"
    21  	"github.com/secoba/wails/v2/pkg/menu/keys"
    22  )
    23  
    24  type NSMenu struct {
    25  	context unsafe.Pointer
    26  	nsmenu  unsafe.Pointer
    27  }
    28  
    29  func NewNSMenu(context unsafe.Pointer, name string) *NSMenu {
    30  	c := NewCalloc()
    31  	defer c.Free()
    32  	title := c.String(name)
    33  	nsmenu := C.NewMenu(title)
    34  	return &NSMenu{
    35  		context: context,
    36  		nsmenu:  nsmenu,
    37  	}
    38  }
    39  
    40  func (m *NSMenu) AddSubMenu(label string) *NSMenu {
    41  	result := NewNSMenu(m.context, label)
    42  	C.AppendSubmenu(m.nsmenu, result.nsmenu)
    43  	return result
    44  }
    45  
    46  func (m *NSMenu) AppendRole(role menu.Role) {
    47  	C.AppendRole(m.context, m.nsmenu, C.int(role))
    48  }
    49  
    50  type MenuItem struct {
    51  	id                uint
    52  	nsmenuitem        unsafe.Pointer
    53  	wailsMenuItem     *menu.MenuItem
    54  	radioGroupMembers []*MenuItem
    55  }
    56  
    57  func (m *NSMenu) AddMenuItem(menuItem *menu.MenuItem) *MenuItem {
    58  	c := NewCalloc()
    59  	defer c.Free()
    60  	var modifier C.int
    61  	var key *C.char
    62  	if menuItem.Accelerator != nil {
    63  		modifier = C.int(keys.ToMacModifier(menuItem.Accelerator))
    64  		key = c.String(menuItem.Accelerator.Key)
    65  	}
    66  
    67  	result := &MenuItem{
    68  		wailsMenuItem: menuItem,
    69  	}
    70  
    71  	result.id = createMenuItemID(result)
    72  	result.nsmenuitem = C.AppendMenuItem(m.context, m.nsmenu, c.String(menuItem.Label), key, modifier, bool2Cint(menuItem.Disabled), bool2Cint(menuItem.Checked), C.int(result.id))
    73  	return result
    74  }
    75  
    76  //func (w *Window) SetApplicationMenu(menu *menu.Menu) {
    77  //w.applicationMenu = menu
    78  //processMenu(w, menu)
    79  //}
    80  
    81  func processMenu(parent *NSMenu, wailsMenu *menu.Menu) {
    82  	var radioGroups []*MenuItem
    83  
    84  	for _, menuItem := range wailsMenu.Items {
    85  		if menuItem.SubMenu != nil {
    86  			if len(radioGroups) > 0 {
    87  				processRadioGroups(radioGroups)
    88  				radioGroups = []*MenuItem{}
    89  			}
    90  			submenu := parent.AddSubMenu(menuItem.Label)
    91  			processMenu(submenu, menuItem.SubMenu)
    92  		} else {
    93  			lastMenuItem := processMenuItem(parent, menuItem)
    94  			if menuItem.Type == menu.RadioType {
    95  				radioGroups = append(radioGroups, lastMenuItem)
    96  			} else {
    97  				if len(radioGroups) > 0 {
    98  					processRadioGroups(radioGroups)
    99  					radioGroups = []*MenuItem{}
   100  				}
   101  			}
   102  		}
   103  	}
   104  }
   105  
   106  func processRadioGroups(groups []*MenuItem) {
   107  	for _, item := range groups {
   108  		item.radioGroupMembers = groups
   109  	}
   110  }
   111  
   112  func processMenuItem(parent *NSMenu, menuItem *menu.MenuItem) *MenuItem {
   113  	if menuItem.Hidden {
   114  		return nil
   115  	}
   116  	if menuItem.Role != 0 {
   117  		parent.AppendRole(menuItem.Role)
   118  		return nil
   119  	}
   120  	if menuItem.Type == menu.SeparatorType {
   121  		C.AppendSeparator(parent.nsmenu)
   122  		return nil
   123  	}
   124  
   125  	return parent.AddMenuItem(menuItem)
   126  }
   127  
   128  func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) {
   129  	f.mainWindow.SetApplicationMenu(menu)
   130  }
   131  
   132  func (f *Frontend) MenuUpdateApplicationMenu() {
   133  	f.mainWindow.UpdateApplicationMenu()
   134  }