5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-12 15:09:33 +08:00

Significant updates to mac menu items. More roles. More fixes to come.

This commit is contained in:
Lea O'Anthony 2024-09-12 20:51:07 +10:00
parent ef8c886b10
commit 6787ce9c40
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
18 changed files with 745 additions and 561 deletions

View File

@ -29,9 +29,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [linux] Fixed linux compile error introduced by IgnoreMouseEvents addition by [atterpac](https://github.com/atterpac) in [#3721](https://github.com/wailsapp/wails/pull/3721)
- [windows] Fixed syso icon file generation bug by [atterpac](https://github.com/atterpac) in [#3675](https://github.com/wailsapp/wails/pull/3675)
- [linux] Fix to run natively in wayland incorporated from [#1811](https://github.com/wailsapp/wails/pull/1811) in [#3614](https://github.com/wailsapp/wails/pull/3614) by [@stendler](https://github.com/stendler)
- Do not bind internal service methods in [#3720](https://github.com/wailsapp/wails/pull/3720)
by [leaanthony](https://github.com/leaanthony)
- Do not bind internal service methods in [#3720](https://github.com/wailsapp/wails/pull/3720) by [leaanthony](https://github.com/leaanthony)
- [windows] Fixed system tray startup panic in [#3693](https://github.com/wailsapp/wails/issues/3693) by [@DeltaLaboratory](https://github.com/DeltaLaboratory)
- Do not bind internal service methods in [#3720](https://github.com/wailsapp/wails/pull/3720) by [leaanthony](https://github.com/leaanthony)
- [windows] Fixed system tray startup panic in [#3693](https://github.com/wailsapp/wails/issues/3693) by [@DeltaLaboratory](https://github.com/DeltaLaboratory)
- Major menu item refactor and event handling. Mainly improves macOS for now. By [leaanthony](https://github.com/leaanthony)
## v3.0.0-alpha.6 - 2024-07-30

View File

@ -28,6 +28,10 @@ func main() {
// Create a custom menu
menu := app.NewMenu()
menu.AddRole(application.AppMenu)
menu.AddRole(application.EditMenu)
menu.AddRole(application.WindowMenu)
menu.AddRole(application.ServicesMenu)
menu.AddRole(application.HelpMenu)
// Let's make a "Demo" menu
infoMenu := menu.AddSubmenu("Info")

View File

@ -27,6 +27,19 @@ func main() {
if runtime.GOOS == "darwin" {
menu.AddRole(application.AppMenu)
}
fileMenu := menu.AddRole(application.FileMenu)
_ = fileMenu
//fileMenu.FindByRole(application.Open).OnClick(func(context *application.Context) {
// selection, err := application.OpenFileDialog().PromptForSingleSelection()
// if err != nil {
// println("Error: " + err.Error())
// return
// }
// println("You selected: " + selection)
//})
menu.AddRole(application.EditMenu)
menu.AddRole(application.WindowMenu)
menu.AddRole(application.HelpMenu)
// Let's make a "Demo" menu
myMenu := menu.AddSubmenu("Demo")

View File

@ -21,7 +21,7 @@ func main() {
systemTray := app.NewSystemTray()
window := app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
_ = app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Width: 500,
Height: 800,
Name: "Systray Demo Window",
@ -92,7 +92,8 @@ func main() {
})
systemTray.SetMenu(myMenu)
systemTray.AttachWindow(window).WindowOffset(5)
//systemTray.AttachWindow(window).WindowOffset(5)
err := app.Run()
if err != nil {

View File

@ -29,7 +29,7 @@ require (
github.com/pterm/pterm v0.12.51
github.com/samber/lo v1.38.1
github.com/tc-hib/winres v0.3.1
github.com/wailsapp/go-webview2 v1.0.11
github.com/wailsapp/go-webview2 v1.0.15
github.com/wailsapp/mimetype v1.4.1
golang.org/x/sys v0.20.0
golang.org/x/term v0.20.0

View File

@ -219,6 +219,8 @@ github.com/tc-hib/winres v0.3.1 h1:CwRjEGrKdbi5CvZ4ID+iyVhgyfatxFoizjPhzez9Io4=
github.com/tc-hib/winres v0.3.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
github.com/wailsapp/go-webview2 v1.0.11 h1:CDbU4UQpaERY6M/FGObPGzUsFOHH3Yz+go12qnJINNY=
github.com/wailsapp/go-webview2 v1.0.11/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
github.com/wailsapp/go-webview2 v1.0.15 h1:IeQFoWmsHp32y64I41J+Zod3SopjHs918KSO4jUqEnY=
github.com/wailsapp/go-webview2 v1.0.15/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=

View File

@ -112,6 +112,23 @@ func (m *Menu) FindByLabel(label string) *MenuItem {
return nil
}
// FindByRole recursively searches for a menu item with the given role
// and returns the first match, or nil if not found.
func (m *Menu) FindByRole(role Role) *MenuItem {
for _, item := range m.items {
if item.role == role {
return item
}
if item.submenu != nil {
found := item.submenu.FindByRole(role)
if found != nil {
return found
}
}
}
return nil
}
func (m *Menu) RemoveMenuItem(target *MenuItem) {
for i, item := range m.items {
if item == target {

View File

@ -116,79 +116,121 @@ func NewSubMenuItem(label string) *MenuItem {
}
func NewRole(role Role) *MenuItem {
var result *MenuItem
switch role {
case AppMenu:
return newAppMenu()
result = NewAppMenu()
case EditMenu:
return newEditMenu()
result = NewEditMenu()
case FileMenu:
return newFileMenu()
result = NewFileMenu()
case ViewMenu:
return newViewMenu()
result = NewViewMenu()
case ServicesMenu:
return NewServicesMenu()
case SpeechMenu:
return newSpeechMenu()
result = NewSpeechMenu()
case WindowMenu:
return newWindowMenu()
result = NewWindowMenu()
case HelpMenu:
return newHelpMenu()
result = NewHelpMenu()
case Hide:
return newHideMenuItem()
result = NewHideMenuItem()
case Front:
result = NewFrontMenuItem()
case HideOthers:
return newHideOthersMenuItem()
result = NewHideOthersMenuItem()
case UnHide:
return newUnhideMenuItem()
result = NewUnhideMenuItem()
case Undo:
return newUndoMenuItem()
result = NewUndoMenuItem()
case Redo:
return newRedoMenuItem()
result = NewRedoMenuItem()
case Cut:
return newCutMenuItem()
result = NewCutMenuItem()
case Copy:
return newCopyMenuItem()
result = NewCopyMenuItem()
case Paste:
return newPasteMenuItem()
result = NewPasteMenuItem()
case PasteAndMatchStyle:
return newPasteAndMatchStyleMenuItem()
result = NewPasteAndMatchStyleMenuItem()
case SelectAll:
return newSelectAllMenuItem()
result = NewSelectAllMenuItem()
case Delete:
return newDeleteMenuItem()
result = NewDeleteMenuItem()
case Quit:
return newQuitMenuItem()
case Close:
return newCloseMenuItem()
result = NewQuitMenuItem()
case CloseWindow:
result = NewCloseMenuItem()
case About:
return newAboutMenuItem()
result = NewAboutMenuItem()
case Reload:
return newReloadMenuItem()
result = NewReloadMenuItem()
case ForceReload:
return newForceReloadMenuItem()
result = NewForceReloadMenuItem()
case ToggleFullscreen:
return newToggleFullscreenMenuItem()
result = NewToggleFullscreenMenuItem()
case OpenDevTools:
return newOpenDevToolsMenuItem()
result = NewOpenDevToolsMenuItem()
case ResetZoom:
return newZoomResetMenuItem()
result = NewZoomResetMenuItem()
case ZoomIn:
return newZoomInMenuItem()
result = NewZoomInMenuItem()
case ZoomOut:
return newZoomOutMenuItem()
result = NewZoomOutMenuItem()
case Minimize:
return newMinimizeMenuItem()
result = NewMinimizeMenuItem()
case Zoom:
return newZoomMenuItem()
result = NewZoomMenuItem()
case FullScreen:
return newFullScreenMenuItem()
result = NewFullScreenMenuItem()
case Print:
result = NewPrintMenuItem()
case PageLayout:
result = NewPageLayoutMenuItem()
case NoRole:
case ShowAll:
result = NewShowAllMenuItem()
case BringAllToFront:
result = NewBringAllToFrontMenuItem()
case NewFile:
result = NewNewFileMenuItem()
case Open:
result = NewOpenMenuItem()
case Save:
result = NewSaveMenuItem()
case SaveAs:
result = NewSaveAsMenuItem()
case StartSpeaking:
result = NewStartSpeakingMenuItem()
case StopSpeaking:
result = NewStopSpeakingMenuItem()
case Revert:
result = NewRevertMenuItem()
case Find:
result = NewFindMenuItem()
case FindAndReplace:
result = NewFindAndReplaceMenuItem()
case FindNext:
result = NewFindNextMenuItem()
case FindPrevious:
result = NewFindPreviousMenuItem()
case Help:
result = NewHelpMenuItem()
default:
globalApplication.error(fmt.Sprintf("No support for role: %v", role))
os.Exit(1)
}
if result == nil {
return nil
}
result.role = role
return result
}
func NewServicesMenu() *MenuItem {
serviceMenu := NewSubMenuItem("Services")
serviceMenu.role = ServicesMenu
@ -256,6 +298,11 @@ func (m *MenuItem) SetTooltip(s string) *MenuItem {
return m
}
func (m *MenuItem) SetRole(role Role) *MenuItem {
m.role = role
return m
}
func (m *MenuItem) SetLabel(s string) *MenuItem {
m.label = s
if m.impl != nil {

View File

@ -13,7 +13,8 @@ package application
#define unicode(input) [NSString stringWithFormat:@"%C", input]
// Create menu item
void* newMenuItem(unsigned int menuItemID, char *label, bool disabled, char* tooltip) {
void* newMenuItem(unsigned int menuItemID, char *label, bool disabled, char* tooltip, char* selector) {
NSLog(@"newMenuItem: %s, %s\n", label, selector);
MenuItem *menuItem = [MenuItem new];
// Label
@ -22,10 +23,16 @@ void* newMenuItem(unsigned int menuItemID, char *label, bool disabled, char* too
if( disabled ) {
[menuItem setTarget:nil];
} else {
[menuItem setTarget:menuItem];
if (selector != NULL) {
menuItem.action = NSSelectorFromString([NSString stringWithUTF8String:selector]);
menuItem.target = nil; // Allow the action to be sent up the responder chain
} else {
menuItem.action = @selector(handleClick);
menuItem.target = menuItem;
}
}
menuItem.menuItemID = menuItemID;
menuItem.action = @selector(handleClick);
menuItem.enabled = !disabled;
// Tooltip
@ -269,21 +276,6 @@ static char *pasteFromPasteboard(void) {
return strdup([text UTF8String]);
}
// Call paste selector to paste text
static void paste(void) {
[NSApp sendAction:@selector(paste:) to:nil from:nil];
}
// Call copy selector to copy text
static void copy(void) {
[NSApp sendAction:@selector(copy:) to:nil from:nil];
}
// Call cut selector to cut text
static void cut(void) {
[NSApp sendAction:@selector(cut:) to:nil from:nil];
}
void performSelectorOnMainThreadForFirstResponder(SEL selector) {
NSWindow *activeWindow = [[NSApplication sharedApplication] keyWindow];
if (activeWindow) {
@ -291,54 +283,6 @@ void performSelectorOnMainThreadForFirstResponder(SEL selector) {
}
}
// Call selectAll selector to select all text
static void selectAll(void) {
performSelectorOnMainThreadForFirstResponder(@selector(selectAll:));
}
// Call delete selector to delete text
static void delete(void) {
[NSApp sendAction:@selector(delete:) to:nil from:nil];
}
// Call undo selector to undo text
static void undo(void) {
[NSApp sendAction:@selector(undo:) to:nil from:nil];
}
// Call redo selector to redo text
static void redo(void) {
[NSApp sendAction:@selector(redo:) to:nil from:nil];
}
// Call startSpeaking selector to start speaking text
static void startSpeaking(void) {
[NSApp sendAction:@selector(startSpeaking:) to:nil from:nil];
}
// Call stopSpeaking selector to stop speaking text
static void stopSpeaking(void) {
[NSApp sendAction:@selector(stopSpeaking:) to:nil from:nil];
}
static void pasteAndMatchStyle(void) {
[NSApp sendAction:@selector(pasteAndMatchStyle:) to:nil from:nil];
}
static void hideApplication(void) {
[[NSApplication sharedApplication] hide:nil];
}
// hideOthers hides all other applications
static void hideOthers(void) {
[[NSApplication sharedApplication] hideOtherApplications:nil];
}
// showAll shows all hidden applications
static void showAll(void) {
[[NSApplication sharedApplication] unhideAllApplications:nil];
}
void setMenuItemBitmap(void* nsMenuItem, unsigned char *bitmap, int length) {
MenuItem *menuItem = (MenuItem *)nsMenuItem;
NSImage *image = [[NSImage alloc] initWithData:[NSData dataWithBytes:bitmap length:length]];
@ -347,7 +291,6 @@ void setMenuItemBitmap(void* nsMenuItem, unsigned char *bitmap, int length) {
*/
import "C"
import (
"runtime"
"unsafe"
)
@ -399,251 +342,25 @@ func newMenuItemImpl(item *MenuItem) *macosMenuItem {
menuItem: item,
}
selector := getSelectorForRole(item.role)
if selector != nil {
defer C.free(unsafe.Pointer(selector))
}
result.nsMenuItem = unsafe.Pointer(C.newMenuItem(
C.uint(item.id),
C.CString(item.label),
C.bool(item.disabled),
C.CString(item.tooltip),
selector,
))
switch item.itemType {
case text, checkbox, submenu, radio:
result.nsMenuItem = unsafe.Pointer(C.newMenuItem(C.uint(item.id), C.CString(item.label), C.bool(item.disabled), C.CString(item.tooltip)))
if item.itemType == checkbox || item.itemType == radio {
case checkbox, radio:
C.setMenuItemChecked(result.nsMenuItem, C.bool(item.checked))
}
if item.accelerator != nil {
result.setAccelerator(item.accelerator)
}
default:
panic("WTF")
}
return result
}
func newSpeechMenu() *MenuItem {
speechMenu := NewMenu()
speechMenu.Add("Start Speaking").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+.").
OnClick(func(ctx *Context) {
C.startSpeaking()
})
speechMenu.Add("Stop Speaking").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+,").
OnClick(func(ctx *Context) {
C.stopSpeaking()
})
subMenu := NewSubMenuItem("Speech")
subMenu.submenu = speechMenu
return subMenu
}
func newHideMenuItem() *MenuItem {
return NewMenuItem("Hide " + globalApplication.options.Name).
SetAccelerator("CmdOrCtrl+h").
OnClick(func(ctx *Context) {
C.hideApplication()
})
}
func newHideOthersMenuItem() *MenuItem {
return NewMenuItem("Hide Others").
SetAccelerator("CmdOrCtrl+OptionOrAlt+h").
OnClick(func(ctx *Context) {
C.hideOthers()
})
}
func newUnhideMenuItem() *MenuItem {
return NewMenuItem("Show All").
OnClick(func(ctx *Context) {
C.showAll()
})
}
func newUndoMenuItem() *MenuItem {
return NewMenuItem("Undo").
SetAccelerator("CmdOrCtrl+z").
OnClick(func(ctx *Context) {
C.undo()
})
}
// newRedoMenuItem creates a new menu item for redoing the last action
func newRedoMenuItem() *MenuItem {
return NewMenuItem("Redo").
SetAccelerator("CmdOrCtrl+Shift+z").
OnClick(func(ctx *Context) {
C.redo()
})
}
func newCutMenuItem() *MenuItem {
return NewMenuItem("Cut").
SetAccelerator("CmdOrCtrl+x").
OnClick(func(ctx *Context) {
C.cut()
})
}
func newCopyMenuItem() *MenuItem {
return NewMenuItem("Copy").
SetAccelerator("CmdOrCtrl+c").
OnClick(func(ctx *Context) {
C.copy()
})
}
func newPasteMenuItem() *MenuItem {
return NewMenuItem("Paste").
SetAccelerator("CmdOrCtrl+v").
OnClick(func(ctx *Context) {
C.paste()
})
}
func newPasteAndMatchStyleMenuItem() *MenuItem {
return NewMenuItem("Paste and Match Style").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+v").
OnClick(func(ctx *Context) {
C.pasteAndMatchStyle()
})
}
func newDeleteMenuItem() *MenuItem {
return NewMenuItem("Delete").
SetAccelerator("backspace").
OnClick(func(ctx *Context) {
C.delete()
})
}
func newQuitMenuItem() *MenuItem {
return NewMenuItem("Quit " + globalApplication.options.Name).
SetAccelerator("CmdOrCtrl+q").
OnClick(func(ctx *Context) {
globalApplication.Quit()
})
}
func newSelectAllMenuItem() *MenuItem {
return NewMenuItem("Select All").
SetAccelerator("CmdOrCtrl+a").
OnClick(func(ctx *Context) {
C.selectAll()
})
}
func newAboutMenuItem() *MenuItem {
return NewMenuItem("About " + globalApplication.options.Name).
OnClick(func(ctx *Context) {
globalApplication.ShowAboutDialog()
})
}
func newCloseMenuItem() *MenuItem {
return NewMenuItem("Close").
SetAccelerator("CmdOrCtrl+w").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Close()
}
})
}
func newReloadMenuItem() *MenuItem {
return NewMenuItem("Reload").
SetAccelerator("CmdOrCtrl+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Reload()
}
})
}
func newForceReloadMenuItem() *MenuItem {
return NewMenuItem("Force Reload").
SetAccelerator("CmdOrCtrl+Shift+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ForceReload()
}
})
}
func newToggleFullscreenMenuItem() *MenuItem {
result := NewMenuItem("Toggle Full Screen").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ToggleFullscreen()
}
})
if runtime.GOOS == "darwin" {
result.SetAccelerator("Ctrl+Command+F")
} else {
result.SetAccelerator("F11")
}
return result
}
func newZoomResetMenuItem() *MenuItem {
// reset zoom menu item
return NewMenuItem("Actual Size").
SetAccelerator("CmdOrCtrl+0").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomReset()
}
})
}
func newZoomInMenuItem() *MenuItem {
return NewMenuItem("Zoom In").
SetAccelerator("CmdOrCtrl+plus").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomIn()
}
})
}
func newZoomOutMenuItem() *MenuItem {
return NewMenuItem("Zoom Out").
SetAccelerator("CmdOrCtrl+-").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomOut()
}
})
}
func newMinimizeMenuItem() *MenuItem {
return NewMenuItem("Minimize").
SetAccelerator("CmdOrCtrl+M").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Minimise()
}
})
}
func newZoomMenuItem() *MenuItem {
return NewMenuItem("Zoom").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Zoom()
}
})
}
func newFullScreenMenuItem() *MenuItem {
return NewMenuItem("Fullscreen").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Fullscreen()
}
})
}

View File

@ -2,7 +2,7 @@
package application
func newOpenDevToolsMenuItem() *MenuItem {
func NewOpenDevToolsMenuItem() *MenuItem {
return NewMenuItem("Open Developer Tools").
SetAccelerator("Alt+Command+I").
OnClick(func(ctx *Context) {

View File

@ -141,6 +141,10 @@ func newSpeechMenu() *MenuItem {
return subMenu
}
func newFrontMenuItem() *MenuItem {
panic("implement me")
}
func newHideMenuItem() *MenuItem {
return NewMenuItem("Hide " + globalApplication.options.Name).
SetAccelerator("CmdOrCtrl+h").
@ -358,3 +362,67 @@ func newFullScreenMenuItem() *MenuItem {
}
})
}
func newPrintMenuItem() *MenuItem {
panic("Implement me")
}
func newPageLayoutMenuItem() *MenuItem {
panic("Implement me")
}
func newShowAllMenuItem() *MenuItem {
panic("Implement me")
}
func newBringAllToFrontMenuItem() *MenuItem {
panic("Implement me")
}
func newNewFileMenuItem() *MenuItem {
panic("Implement me")
}
func newOpenMenuItem() *MenuItem {
panic("Implement me")
}
func newSaveMenuItem() *MenuItem {
panic("Implement me")
}
func newSaveAsMenuItem() *MenuItem {
panic("Implement me")
}
func newStartSpeakingMenuItem() *MenuItem {
panic("Implement me")
}
func newStopSpeakingMenuItem() *MenuItem {
panic("Implement me")
}
func newRevertMenuItem() *MenuItem {
panic("Implement me")
}
func newFindMenuItem() *MenuItem {
panic("Implement me")
}
func newFindAndReplaceMenuItem() *MenuItem {
panic("Implement me")
}
func newFindNextMenuItem() *MenuItem {
panic("Implement me")
}
func newFindPreviousMenuItem() *MenuItem {
panic("Implement me")
}
func newHelpMenuItem() *MenuItem {
panic("Implement me")
}

View File

@ -2,6 +2,6 @@
package application
func newOpenDevToolsMenuItem() *MenuItem {
func NewOpenDevToolsMenuItem() *MenuItem {
return nil
}

View File

@ -0,0 +1,290 @@
package application
import "runtime"
func NewSpeechMenu() *MenuItem {
speechMenu := NewMenu()
speechMenu.AddRole(StartSpeaking)
speechMenu.AddRole(StopSpeaking)
subMenu := NewSubMenuItem("Speech")
subMenu.submenu = speechMenu
return subMenu
}
func NewHideMenuItem() *MenuItem {
return NewMenuItem("Hide " + globalApplication.options.Name).
SetAccelerator("CmdOrCtrl+h").
SetRole(Hide)
}
func NewHideOthersMenuItem() *MenuItem {
return NewMenuItem("Hide Others").
SetAccelerator("CmdOrCtrl+OptionOrAlt+h").
SetRole(HideOthers)
}
func NewFrontMenuItem() *MenuItem {
return NewMenuItem("Bring All to Front")
}
func NewUnhideMenuItem() *MenuItem {
return NewMenuItem("Show All")
}
func NewUndoMenuItem() *MenuItem {
return NewMenuItem("Undo").
SetAccelerator("CmdOrCtrl+z")
}
// newRedoMenuItem creates a new menu item for redoing the last action
func NewRedoMenuItem() *MenuItem {
return NewMenuItem("Redo").
SetAccelerator("CmdOrCtrl+Shift+z")
}
func NewCutMenuItem() *MenuItem {
return NewMenuItem("Cut").
SetAccelerator("CmdOrCtrl+x")
}
func NewCopyMenuItem() *MenuItem {
return NewMenuItem("Copy").
SetAccelerator("CmdOrCtrl+c")
}
func NewPasteMenuItem() *MenuItem {
return NewMenuItem("Paste").
SetAccelerator("CmdOrCtrl+v")
}
func NewPasteAndMatchStyleMenuItem() *MenuItem {
return NewMenuItem("Paste and Match Style").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+v")
}
func NewDeleteMenuItem() *MenuItem {
return NewMenuItem("Delete").
SetAccelerator("backspace")
}
func NewQuitMenuItem() *MenuItem {
label := "Quit"
if runtime.GOOS == "darwin" {
if globalApplication.options.Name != "" {
label += " " + globalApplication.options.Name
}
}
return NewMenuItem(label).
SetAccelerator("CmdOrCtrl+q").
OnClick(func(ctx *Context) {
globalApplication.Quit()
})
}
func NewSelectAllMenuItem() *MenuItem {
return NewMenuItem("Select All").
SetAccelerator("CmdOrCtrl+a")
}
func NewAboutMenuItem() *MenuItem {
label := "About"
if globalApplication.options.Name != "" {
label += " " + globalApplication.options.Name
}
return NewMenuItem(label).
OnClick(func(ctx *Context) {
globalApplication.ShowAboutDialog()
})
}
func NewCloseMenuItem() *MenuItem {
return NewMenuItem("Close").
SetAccelerator("CmdOrCtrl+w").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Close()
}
})
}
func NewReloadMenuItem() *MenuItem {
return NewMenuItem("Reload").
SetAccelerator("CmdOrCtrl+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Reload()
}
})
}
func NewForceReloadMenuItem() *MenuItem {
return NewMenuItem("Force Reload").
SetAccelerator("CmdOrCtrl+Shift+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ForceReload()
}
})
}
func NewToggleFullscreenMenuItem() *MenuItem {
result := NewMenuItem("Toggle Full Screen").
SetAccelerator("Ctrl+Command+F").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ToggleFullscreen()
}
})
if runtime.GOOS != "darwin" {
result.SetAccelerator("F11")
}
return result
}
func NewZoomResetMenuItem() *MenuItem {
// reset zoom menu item
return NewMenuItem("Actual Size").
SetAccelerator("CmdOrCtrl+0").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomReset()
}
})
}
func NewZoomInMenuItem() *MenuItem {
return NewMenuItem("Zoom In").
SetAccelerator("CmdOrCtrl+plus").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomIn()
}
})
}
func NewZoomOutMenuItem() *MenuItem {
return NewMenuItem("Zoom Out").
SetAccelerator("CmdOrCtrl+-").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomOut()
}
})
}
func NewMinimizeMenuItem() *MenuItem {
return NewMenuItem("Minimize").
SetAccelerator("CmdOrCtrl+M").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Minimise()
}
})
}
func NewZoomMenuItem() *MenuItem {
return NewMenuItem("Zoom").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Zoom()
}
})
}
func NewFullScreenMenuItem() *MenuItem {
return NewMenuItem("Fullscreen").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Fullscreen()
}
})
}
func NewPrintMenuItem() *MenuItem {
return NewMenuItem("Print").
SetAccelerator("CmdOrCtrl+p")
}
func NewPageLayoutMenuItem() *MenuItem {
return NewMenuItem("Page Setup...").
SetAccelerator("CmdOrCtrl+Shift+p")
}
func NewShowAllMenuItem() *MenuItem {
return NewMenuItem("Show All")
}
func NewBringAllToFrontMenuItem() *MenuItem {
return NewMenuItem("Bring All to Front")
}
func NewNewFileMenuItem() *MenuItem {
return NewMenuItem("New File").
SetAccelerator("CmdOrCtrl+n")
}
func NewOpenMenuItem() *MenuItem {
return NewMenuItem("Open...").
SetAccelerator("CmdOrCtrl+o").
SetRole(Open)
}
func NewSaveMenuItem() *MenuItem {
return NewMenuItem("Save").
SetAccelerator("CmdOrCtrl+s")
}
func NewSaveAsMenuItem() *MenuItem {
return NewMenuItem("Save As...").
SetAccelerator("CmdOrCtrl+Shift+s")
}
func NewStartSpeakingMenuItem() *MenuItem {
return NewMenuItem("Start Speaking").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+.")
}
func NewStopSpeakingMenuItem() *MenuItem {
return NewMenuItem("Stop Speaking").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+,")
}
func NewRevertMenuItem() *MenuItem {
return NewMenuItem("Revert").
SetAccelerator("CmdOrCtrl+r")
}
func NewFindMenuItem() *MenuItem {
return NewMenuItem("Find...").
SetAccelerator("CmdOrCtrl+f")
}
func NewFindAndReplaceMenuItem() *MenuItem {
return NewMenuItem("Find and Replace...").
SetAccelerator("CmdOrCtrl+Shift+f")
}
func NewFindNextMenuItem() *MenuItem {
return NewMenuItem("Find Next").
SetAccelerator("CmdOrCtrl+g")
}
func NewFindPreviousMenuItem() *MenuItem {
return NewMenuItem("Find Previous").
SetAccelerator("CmdOrCtrl+Shift+g")
}
func NewHelpMenuItem() *MenuItem {
return NewMenuItem("Help").
SetAccelerator("CmdOrCtrl+?")
}

View File

@ -0,0 +1,58 @@
// File: v3/pkg/application/menuitem_selectors_darwin.go
//go:build darwin
package application
import "C"
var roleToSelector = map[Role]string{
//AppMenu: "", // This is a special case, handled separately
About: "orderFrontStandardAboutPanel:",
//ServicesMenu: "", // This is a submenu, no direct selector
Hide: "hide:",
HideOthers: "hideOtherApplications:",
ShowAll: "unhideAllApplications:",
Quit: "terminate:",
//WindowMenu: "", // This is a submenu, no direct selector
Minimize: "performMiniaturize:",
Zoom: "performZoom:",
BringAllToFront: "arrangeInFront:",
CloseWindow: "performClose:",
//EditMenu: "", // This is a submenu, no direct selector
Undo: "undo:",
Redo: "redo:",
Cut: "cut:",
Copy: "copy:",
Paste: "paste:",
Delete: "delete:",
SelectAll: "selectAll:",
//FindMenu: "", // This is a submenu, no direct selector
Find: "performTextFinderAction:",
FindAndReplace: "performTextFinderAction:",
FindNext: "performTextFinderAction:",
FindPrevious: "performTextFinderAction:",
UseSelectionForFind: "performTextFinderAction:",
//ViewMenu: "", // This is a submenu, no direct selector
ToggleFullscreen: "toggleFullScreen:",
//FileMenu: "", // This is a submenu, no direct selector
NewFile: "newDocument:",
Open: "openDocument:",
Save: "saveDocument:",
SaveAs: "saveDocumentAs:",
StartSpeaking: "startSpeaking:",
StopSpeaking: "stopSpeaking:",
Revert: "revertDocumentToSaved:",
Print: "printDocument:",
PageLayout: "runPageLayout:",
//HelpMenu: "", // This is a submenu, no direct selector
Help: "showHelp:",
//No: "", // No specific selector for this role
}
func getSelectorForRole(role Role) *C.char {
if selector, ok := roleToSelector[role]; ok && selector != "" {
return C.CString(selector)
}
return nil
}

View File

@ -4,7 +4,6 @@ package application
import (
"github.com/wailsapp/wails/v3/pkg/w32"
"runtime"
"unsafe"
)
@ -135,192 +134,125 @@ func newMenuItemImpl(item *MenuItem, parentMenu w32.HMENU, ID int) *windowsMenuI
return result
}
func newSpeechMenu() *MenuItem {
panic("implement me")
}
func newHideMenuItem() *MenuItem {
panic("implement me")
}
func newHideOthersMenuItem() *MenuItem {
panic("implement me")
}
func newUnhideMenuItem() *MenuItem {
panic("implement me")
}
func newUndoMenuItem() *MenuItem {
panic("implement me")
}
// newRedoMenuItem creates a new menu item for redoing the last action
func newRedoMenuItem() *MenuItem {
panic("implement me")
}
func newCutMenuItem() *MenuItem {
panic("implement me")
}
func newCopyMenuItem() *MenuItem {
panic("implement me")
}
func newPasteMenuItem() *MenuItem {
panic("implement me")
}
func newPasteAndMatchStyleMenuItem() *MenuItem {
panic("implement me")
}
func newDeleteMenuItem() *MenuItem {
panic("implement me")
}
func newQuitMenuItem() *MenuItem {
return NewMenuItem("Quit").
OnClick(func(ctx *Context) {
globalApplication.Quit()
})
}
func newSelectAllMenuItem() *MenuItem {
panic("implement me")
}
func newAboutMenuItem() *MenuItem {
return NewMenuItem("About " + globalApplication.options.Name).
OnClick(func(ctx *Context) {
globalApplication.ShowAboutDialog()
})
}
func newCloseMenuItem() *MenuItem {
return NewMenuItem("Close").
SetAccelerator("CmdOrCtrl+w").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Close()
}
})
}
func newReloadMenuItem() *MenuItem {
return NewMenuItem("Reload").
SetAccelerator("CmdOrCtrl+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Reload()
}
})
}
func newForceReloadMenuItem() *MenuItem {
return NewMenuItem("Force Reload").
SetAccelerator("CmdOrCtrl+Shift+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ForceReload()
}
})
}
func newToggleFullscreenMenuItem() *MenuItem {
result := NewMenuItem("Toggle Full Screen").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ToggleFullscreen()
}
})
if runtime.GOOS == "darwin" {
result.SetAccelerator("Ctrl+Command+F")
} else {
result.SetAccelerator("F11")
}
return result
}
func newZoomResetMenuItem() *MenuItem {
// reset zoom menu item
return NewMenuItem("Actual Size").
SetAccelerator("CmdOrCtrl+0").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomReset()
}
})
}
func newZoomInMenuItem() *MenuItem {
return NewMenuItem("Zoom In").
SetAccelerator("CmdOrCtrl+plus").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomIn()
}
})
}
func newZoomOutMenuItem() *MenuItem {
return NewMenuItem("Zoom Out").
SetAccelerator("CmdOrCtrl+-").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ZoomOut()
}
})
}
func newFullScreenMenuItem() *MenuItem {
return NewMenuItem("Fullscreen").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Fullscreen()
}
})
}
func newMinimizeMenuItem() *MenuItem {
return NewMenuItem("Minimize").
SetAccelerator("CmdOrCtrl+M").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Minimise()
}
})
}
func newZoomMenuItem() *MenuItem {
return NewMenuItem("Zoom").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.Zoom()
}
})
}
//func newAboutMenuItem() *MenuItem {
// return NewMenuItem("About " + globalApplication.options.Name).
// OnClick(func(ctx *Context) {
// globalApplication.ShowAboutDialog()
// })
//}
//
//func newCloseMenuItem() *MenuItem {
// return NewMenuItem("Close").
// SetAccelerator("CmdOrCtrl+w").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.Close()
// }
// })
//}
//func newReloadMenuItem() *MenuItem {
// return NewMenuItem("Reload").
// SetAccelerator("CmdOrCtrl+r").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.Reload()
// }
// })
//}
//
//func newForceReloadMenuItem() *MenuItem {
// return NewMenuItem("Force Reload").
// SetAccelerator("CmdOrCtrl+Shift+r").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.ForceReload()
// }
// })
//}
//
//func newToggleFullscreenMenuItem() *MenuItem {
// result := NewMenuItem("Toggle Full Screen").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.ToggleFullscreen()
// }
// })
// if runtime.GOOS == "darwin" {
// result.SetAccelerator("Ctrl+Command+F")
// } else {
// result.SetAccelerator("F11")
// }
// return result
//}
//
//func newZoomResetMenuItem() *MenuItem {
// // reset zoom menu item
// return NewMenuItem("Actual Size").
// SetAccelerator("CmdOrCtrl+0").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.ZoomReset()
// }
// })
//}
//
//func newZoomInMenuItem() *MenuItem {
// return NewMenuItem("Zoom In").
// SetAccelerator("CmdOrCtrl+plus").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.ZoomIn()
// }
// })
//}
//
//func newZoomOutMenuItem() *MenuItem {
// return NewMenuItem("Zoom Out").
// SetAccelerator("CmdOrCtrl+-").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.ZoomOut()
// }
// })
//}
//
//func newFullScreenMenuItem() *MenuItem {
// return NewMenuItem("Fullscreen").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.Fullscreen()
// }
// })
//}
//
//func newMinimizeMenuItem() *MenuItem {
// return NewMenuItem("Minimize").
// SetAccelerator("CmdOrCtrl+M").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.Minimise()
// }
// })
//}
//
//func newZoomMenuItem() *MenuItem {
// return NewMenuItem("Zoom").
// OnClick(func(ctx *Context) {
// currentWindow := globalApplication.CurrentWindow()
// if currentWindow != nil {
// currentWindow.Zoom()
// }
// })
//}
// ---------- unsupported on windows ----------

View File

@ -20,6 +20,8 @@ const (
Hide Role = iota
HideOthers Role = iota
ShowAll Role = iota
BringAllToFront Role = iota
UnHide Role = iota
About Role = iota
Undo Role = iota
@ -33,7 +35,7 @@ const (
SpeechMenu Role = iota
Quit Role = iota
FileMenu Role = iota
Close Role = iota
CloseWindow Role = iota
Reload Role = iota
ForceReload Role = iota
OpenDevTools Role = iota
@ -45,25 +47,28 @@ const (
Minimize Role = iota
Zoom Role = iota
FullScreen Role = iota
//Front Role = iota
//WindowRole Role = iota
//QuitRole Role =
//TogglefullscreenRole Role = "togglefullscreen"
//ViewMenuRole Role = "viewMenu"
//WindowMenuRole Role = "windowMenu"
//FrontRole Role = "front"
//ZoomRole Role = "zoom"
//WindowSubMenuRole Role = "windowSubMenu"
//HelpSubMenuRole Role = "helpSubMenu"
//SeparatorItemRole Role = "separatorItem"
NewFile Role = iota
Open Role = iota
Save Role = iota
SaveAs Role = iota
StartSpeaking Role = iota
StopSpeaking Role = iota
Revert Role = iota
Print Role = iota
PageLayout Role = iota
Find Role = iota
FindAndReplace Role = iota
FindNext Role = iota
FindPrevious Role = iota
Front Role = iota
Help Role = iota
)
func newFileMenu() *MenuItem {
func NewFileMenu() *MenuItem {
fileMenu := NewMenu()
if runtime.GOOS == "darwin" {
fileMenu.AddRole(Close)
fileMenu.AddRole(CloseWindow)
} else {
fileMenu.AddRole(Quit)
}
@ -72,7 +77,7 @@ func newFileMenu() *MenuItem {
return subMenu
}
func newViewMenu() *MenuItem {
func NewViewMenu() *MenuItem {
viewMenu := NewMenu()
viewMenu.AddRole(Reload)
viewMenu.AddRole(ForceReload)
@ -88,7 +93,7 @@ func newViewMenu() *MenuItem {
return subMenu
}
func newAppMenu() *MenuItem {
func NewAppMenu() *MenuItem {
if runtime.GOOS != "darwin" {
return nil
}
@ -107,7 +112,7 @@ func newAppMenu() *MenuItem {
return subMenu
}
func newEditMenu() *MenuItem {
func NewEditMenu() *MenuItem {
editMenu := NewMenu()
editMenu.AddRole(Undo)
editMenu.AddRole(Redo)
@ -132,22 +137,24 @@ func newEditMenu() *MenuItem {
return subMenu
}
func newWindowMenu() *MenuItem {
func NewWindowMenu() *MenuItem {
menu := NewMenu()
menu.AddRole(Minimize)
menu.AddRole(Zoom)
if runtime.GOOS == "darwin" {
menu.AddSeparator()
menu.AddRole(FullScreen)
menu.AddRole(Front)
//menu.AddSeparator()
//menu.AddRole(Window)
} else {
menu.AddRole(Close)
menu.AddRole(CloseWindow)
}
subMenu := NewSubMenuItem("Window")
subMenu.submenu = menu
return subMenu
}
func newHelpMenu() *MenuItem {
func NewHelpMenu() *MenuItem {
menu := NewMenu()
menu.Add("Learn More").OnClick(func(ctx *Context) {
globalApplication.CurrentWindow().SetURL("https://wails.io")

25
v3/pkg/w32/actions.go Normal file
View File

@ -0,0 +1,25 @@
package w32
func Undo(hwnd HWND) {
SendMessage(hwnd, WM_UNDO, 0, 0)
}
func Cut(hwnd HWND) {
SendMessage(hwnd, WM_CUT, 0, 0)
}
func Copy(hwnd HWND) {
SendMessage(hwnd, WM_COPY, 0, 0)
}
func Paste(hwnd HWND) {
SendMessage(hwnd, WM_PASTE, 0, 0)
}
func Delete(hwnd HWND) {
SendMessage(hwnd, WM_CLEAR, 0, 0)
}
func SelectAll(hwnd HWND) {
SendMessage(hwnd, WM_SELECTALL, 0, 0)
}

View File

@ -538,6 +538,7 @@ const (
WM_VSCROLLCLIPBOARD = 778
WM_WINDOWPOSCHANGED = 71
WM_WINDOWPOSCHANGING = 70
WM_SELECTALL = 0x00B1
WM_WININICHANGE = 26
WM_KEYFIRST = 256
WM_KEYLAST = 264