5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 11:10:47 +08:00
wails/v3/pkg/application/menuitem.go
2023-01-27 21:05:53 +11:00

275 lines
5.2 KiB
Go

package application
import (
"os"
"sync"
"sync/atomic"
)
type menuItemType int
const (
text menuItemType = iota
separator
checkbox
radio
submenu
)
var menuItemID uintptr
var menuItemMap = make(map[uint]*MenuItem)
var menuItemMapLock sync.Mutex
func addToMenuItemMap(menuItem *MenuItem) {
menuItemMapLock.Lock()
menuItemMap[menuItem.id] = menuItem
menuItemMapLock.Unlock()
}
func getMenuItemByID(id uint) *MenuItem {
menuItemMapLock.Lock()
defer menuItemMapLock.Unlock()
return menuItemMap[id]
}
type menuItemImpl interface {
setTooltip(s string)
setLabel(s string)
setDisabled(disabled bool)
setChecked(checked bool)
setAccelerator(accelerator *accelerator)
}
type MenuItem struct {
id uint
label string
tooltip string
disabled bool
checked bool
submenu *Menu
callback func(*Context)
itemType menuItemType
accelerator *accelerator
role Role
impl menuItemImpl
radioGroupMembers []*MenuItem
}
func newMenuItem(label string) *MenuItem {
result := &MenuItem{
id: uint(atomic.AddUintptr(&menuItemID, 1)),
label: label,
itemType: text,
}
addToMenuItemMap(result)
return result
}
func newMenuItemSeperator() *MenuItem {
result := &MenuItem{
itemType: separator,
}
return result
}
func newMenuItemCheckbox(label string, checked bool) *MenuItem {
result := &MenuItem{
id: uint(atomic.AddUintptr(&menuItemID, 1)),
label: label,
checked: checked,
itemType: checkbox,
}
addToMenuItemMap(result)
return result
}
func newMenuItemRadio(label string, checked bool) *MenuItem {
result := &MenuItem{
id: uint(atomic.AddUintptr(&menuItemID, 1)),
label: label,
checked: checked,
itemType: radio,
}
addToMenuItemMap(result)
return result
}
func newSubMenuItem(label string) *MenuItem {
result := &MenuItem{
id: uint(atomic.AddUintptr(&menuItemID, 1)),
label: label,
itemType: submenu,
submenu: &Menu{
label: label,
},
}
addToMenuItemMap(result)
return result
}
func newRole(role Role) *MenuItem {
switch role {
case AppMenu:
return newAppMenu()
case EditMenu:
return newEditMenu()
case FileMenu:
return newFileMenu()
case ViewMenu:
return newViewMenu()
case ServicesMenu:
return newServicesMenu()
case SpeechMenu:
return newSpeechMenu()
case WindowMenu:
return newWindowMenu()
case HelpMenu:
return newHelpMenu()
case Hide:
return newHideMenuItem()
case HideOthers:
return newHideOthersMenuItem()
case UnHide:
return newUnhideMenuItem()
case Undo:
return newUndoMenuItem()
case Redo:
return newRedoMenuItem()
case Cut:
return newCutMenuItem()
case Copy:
return newCopyMenuItem()
case Paste:
return newPasteMenuItem()
case PasteAndMatchStyle:
return newPasteAndMatchStyleMenuItem()
case SelectAll:
return newSelectAllMenuItem()
case Delete:
return newDeleteMenuItem()
case Quit:
return newQuitMenuItem()
case Close:
return newCloseMenuItem()
case About:
return newAboutMenuItem()
case Reload:
return newReloadMenuItem()
case ForceReload:
return newForceReloadMenuItem()
case ToggleFullscreen:
return newToggleFullscreenMenuItem()
case ToggleDevTools:
return newToggleDevToolsMenuItem()
case ResetZoom:
return newZoomResetMenuItem()
case ZoomIn:
return newZoomInMenuItem()
case ZoomOut:
return newZoomOutMenuItem()
case Minimize:
return newMinimizeMenuItem()
case Zoom:
return newZoomMenuItem()
default:
println("No support for role:", role)
os.Exit(1)
}
return nil
}
func newServicesMenu() *MenuItem {
serviceMenu := newSubMenuItem("Services")
serviceMenu.role = ServicesMenu
return serviceMenu
}
func (m *MenuItem) handleClick() {
var ctx = newContext().withClickedMenuItem(m)
if m.itemType == checkbox {
m.checked = !m.checked
ctx.withChecked(m.checked)
m.impl.setChecked(m.checked)
}
if m.itemType == radio {
for _, member := range m.radioGroupMembers {
member.checked = false
member.impl.setChecked(false)
}
m.checked = true
ctx.withChecked(true)
m.impl.setChecked(true)
}
if m.callback != nil {
go m.callback(ctx)
}
}
func (m *MenuItem) SetAccelerator(shortcut string) *MenuItem {
accelerator, err := parseAccelerator(shortcut)
if err != nil {
println("ERROR: invalid accelerator:", err.Error())
return m
}
m.accelerator = accelerator
if m.impl != nil {
m.impl.setAccelerator(accelerator)
}
return m
}
func (m *MenuItem) SetTooltip(s string) *MenuItem {
m.tooltip = s
if m.impl != nil {
m.impl.setTooltip(s)
}
return m
}
func (m *MenuItem) SetLabel(s string) *MenuItem {
m.label = s
if m.impl != nil {
m.impl.setLabel(s)
}
return m
}
func (m *MenuItem) SetEnabled(enabled bool) *MenuItem {
m.disabled = !enabled
if m.impl != nil {
m.impl.setDisabled(m.disabled)
}
return m
}
func (m *MenuItem) SetChecked(checked bool) *MenuItem {
m.checked = checked
if m.impl != nil {
m.impl.setChecked(m.checked)
}
return m
}
func (m *MenuItem) Checked() bool {
return m.checked
}
func (m *MenuItem) OnClick(f func(*Context)) *MenuItem {
m.callback = f
return m
}
func (m *MenuItem) Label() string {
return m.label
}
func (m *MenuItem) Tooltip() string {
return m.tooltip
}
func (m *MenuItem) Enabled() bool {
return !m.disabled
}