mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 06:20:48 +08:00
[windows-x] Runtime ported. Menu shortcuts.
This commit is contained in:
parent
72b1e58218
commit
5b10ee4b40
@ -131,7 +131,7 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
|||||||
bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown}
|
bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown}
|
||||||
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions)
|
appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions)
|
||||||
|
|
||||||
appFrontend := frontend.NewFrontend(appoptions, myLogger, appBindings)
|
appFrontend := NewFrontend(appoptions, myLogger, appBindings)
|
||||||
|
|
||||||
result := &App{
|
result := &App{
|
||||||
frontend: appFrontend,
|
frontend: appFrontend,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package frontend
|
package appng
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend/windows"
|
"github.com/wailsapp/wails/v2/internal/frontend/windows"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewFrontend(appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings) *windows.Frontend {
|
func NewFrontend(appoptions *options.App, myLogger *logger.Logger, bindings *binding.Bindings) frontend.Frontend {
|
||||||
return windows.NewFrontend(appoptions, myLogger, appBindings)
|
return windows.NewFrontend(appoptions, myLogger, bindings)
|
||||||
}
|
}
|
@ -1,5 +1,58 @@
|
|||||||
package frontend
|
package frontend
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
|
|
||||||
|
// FileFilter defines a filter for dialog boxes
|
||||||
|
type FileFilter struct {
|
||||||
|
DisplayName string // Filter information EG: "Image Files (*.jpg, *.png)"
|
||||||
|
Pattern string // semi-colon separated list of extensions, EG: "*.jpg;*.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenDialogOptions contains the options for the OpenDialogOptions runtime method
|
||||||
|
type OpenDialogOptions struct {
|
||||||
|
DefaultDirectory string
|
||||||
|
DefaultFilename string
|
||||||
|
Title string
|
||||||
|
Filters []FileFilter
|
||||||
|
AllowFiles bool
|
||||||
|
AllowDirectories bool
|
||||||
|
ShowHiddenFiles bool
|
||||||
|
CanCreateDirectories bool
|
||||||
|
ResolvesAliases bool
|
||||||
|
TreatPackagesAsDirectories bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveDialogOptions contains the options for the SaveDialog runtime method
|
||||||
|
type SaveDialogOptions struct {
|
||||||
|
DefaultDirectory string
|
||||||
|
DefaultFilename string
|
||||||
|
Title string
|
||||||
|
Filters []FileFilter
|
||||||
|
ShowHiddenFiles bool
|
||||||
|
CanCreateDirectories bool
|
||||||
|
TreatPackagesAsDirectories bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type DialogType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
InfoDialog DialogType = "info"
|
||||||
|
WarningDialog DialogType = "warning"
|
||||||
|
ErrorDialog DialogType = "error"
|
||||||
|
QuestionDialog DialogType = "question"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MessageDialogOptions contains the options for the Message dialogs, EG Info, Warning, etc runtime methods
|
||||||
|
type MessageDialogOptions struct {
|
||||||
|
Type DialogType
|
||||||
|
Title string
|
||||||
|
Message string
|
||||||
|
Buttons []string
|
||||||
|
DefaultButton string
|
||||||
|
CancelButton string
|
||||||
|
Icon string
|
||||||
|
}
|
||||||
|
|
||||||
type Frontend interface {
|
type Frontend interface {
|
||||||
|
|
||||||
// Main methods
|
// Main methods
|
||||||
@ -10,12 +63,12 @@ type Frontend interface {
|
|||||||
//NotifyEvent(message string)
|
//NotifyEvent(message string)
|
||||||
//CallResult(message string)
|
//CallResult(message string)
|
||||||
//
|
//
|
||||||
//// Dialog
|
// Dialog
|
||||||
//OpenFileDialog(dialogOptions dialog.OpenDialogOptions, callbackID string)
|
OpenFileDialog(dialogOptions OpenDialogOptions) (string, error)
|
||||||
//OpenMultipleFilesDialog(dialogOptions dialog.OpenDialogOptions, callbackID string)
|
OpenMultipleFilesDialog(dialogOptions OpenDialogOptions) ([]string, error)
|
||||||
//OpenDirectoryDialog(dialogOptions dialog.OpenDialogOptions, callbackID string)
|
OpenDirectoryDialog(dialogOptions OpenDialogOptions) (string, error)
|
||||||
//SaveDialog(dialogOptions dialog.SaveDialogOptions, callbackID string)
|
SaveFileDialog(dialogOptions SaveDialogOptions) (string, error)
|
||||||
//MessageDialog(dialogOptions dialog.MessageDialogOptions, callbackID string)
|
MessageDialog(dialogOptions MessageDialogOptions) (string, error)
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
WindowSetTitle(title string)
|
WindowSetTitle(title string)
|
||||||
@ -35,9 +88,10 @@ type Frontend interface {
|
|||||||
WindowFullscreen()
|
WindowFullscreen()
|
||||||
WindowUnFullscreen()
|
WindowUnFullscreen()
|
||||||
WindowSetColour(colour int)
|
WindowSetColour(colour int)
|
||||||
//
|
|
||||||
//// Menus
|
// Menus
|
||||||
//SetApplicationMenu(menu *menu.Menu)
|
SetApplicationMenu(menu *menu.Menu)
|
||||||
|
UpdateApplicationMenu()
|
||||||
//SetTrayMenu(menu *menu.TrayMenu)
|
//SetTrayMenu(menu *menu.TrayMenu)
|
||||||
//UpdateTrayMenuLabel(menu *menu.TrayMenu)
|
//UpdateTrayMenuLabel(menu *menu.TrayMenu)
|
||||||
//UpdateContextMenu(contextMenu *menu.ContextMenu)
|
//UpdateContextMenu(contextMenu *menu.ContextMenu)
|
||||||
|
151
v2/internal/frontend/windows/dialog.go
Normal file
151
v2/internal/frontend/windows/dialog.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package windows
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/leaanthony/go-common-file-dialog/cfd"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OpenDirectoryDialog prompts the user to select a directory
|
||||||
|
func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (string, error) {
|
||||||
|
config := cfd.DialogConfig{
|
||||||
|
Title: options.Title,
|
||||||
|
Role: "PickFolder",
|
||||||
|
Folder: options.DefaultDirectory,
|
||||||
|
}
|
||||||
|
thisDialog, err := cfd.NewSelectFolderDialog(config)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
thisDialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||||
|
defer func(thisDialog cfd.SelectFolderDialog) {
|
||||||
|
err := thisDialog.Release()
|
||||||
|
if err != nil {
|
||||||
|
println("ERROR: Unable to release dialog:", err.Error())
|
||||||
|
}
|
||||||
|
}(thisDialog)
|
||||||
|
result, err := thisDialog.ShowAndGetResult()
|
||||||
|
if err != nil && err != cfd.ErrorCancelled {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFileDialog prompts the user to select a file
|
||||||
|
func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) {
|
||||||
|
config := cfd.DialogConfig{
|
||||||
|
Folder: options.DefaultDirectory,
|
||||||
|
FileFilters: convertFilters(options.Filters),
|
||||||
|
FileName: options.DefaultFilename,
|
||||||
|
}
|
||||||
|
thisdialog, err := cfd.NewOpenFileDialog(config)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
thisdialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||||
|
defer func(thisdialog cfd.OpenFileDialog) {
|
||||||
|
err := thisdialog.Release()
|
||||||
|
if err != nil {
|
||||||
|
println("ERROR: Unable to release dialog:", err.Error())
|
||||||
|
}
|
||||||
|
}(thisdialog)
|
||||||
|
result, err := thisdialog.ShowAndGetResult()
|
||||||
|
if err != nil && err != cfd.ErrorCancelled {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenMultipleFilesDialog prompts the user to select a file
|
||||||
|
func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) {
|
||||||
|
config := cfd.DialogConfig{
|
||||||
|
Title: dialogOptions.Title,
|
||||||
|
Role: "OpenMultipleFiles",
|
||||||
|
FileFilters: convertFilters(dialogOptions.Filters),
|
||||||
|
FileName: dialogOptions.DefaultFilename,
|
||||||
|
Folder: dialogOptions.DefaultDirectory,
|
||||||
|
}
|
||||||
|
thisdialog, err := cfd.NewOpenMultipleFilesDialog(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
thisdialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||||
|
defer func(thisdialog cfd.OpenMultipleFilesDialog) {
|
||||||
|
err := thisdialog.Release()
|
||||||
|
if err != nil {
|
||||||
|
println("ERROR: Unable to release dialog:", err.Error())
|
||||||
|
}
|
||||||
|
}(thisdialog)
|
||||||
|
result, err := thisdialog.ShowAndGetResults()
|
||||||
|
if err != nil && err != cfd.ErrorCancelled {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveFileDialog prompts the user to select a file
|
||||||
|
func (f *Frontend) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) {
|
||||||
|
saveDialog, err := cfd.NewSaveFileDialog(cfd.DialogConfig{
|
||||||
|
Title: dialogOptions.Title,
|
||||||
|
Role: "SaveFile",
|
||||||
|
FileFilters: convertFilters(dialogOptions.Filters),
|
||||||
|
FileName: dialogOptions.DefaultFilename,
|
||||||
|
Folder: dialogOptions.DefaultDirectory,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
saveDialog.SetParentWindowHandle(f.mainWindow.Handle())
|
||||||
|
err = saveDialog.Show()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
result, err := saveDialog.GetResult()
|
||||||
|
if err != nil && err != cfd.ErrorCancelled {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageDialog show a message dialog to the user
|
||||||
|
func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string, error) {
|
||||||
|
|
||||||
|
title, err := syscall.UTF16PtrFromString(options.Title)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
message, err := syscall.UTF16PtrFromString(options.Message)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
var flags uint32
|
||||||
|
switch options.Type {
|
||||||
|
case frontend.InfoDialog:
|
||||||
|
flags = windows.MB_OK | windows.MB_ICONINFORMATION
|
||||||
|
case frontend.ErrorDialog:
|
||||||
|
flags = windows.MB_ICONERROR | windows.MB_OK
|
||||||
|
case frontend.QuestionDialog:
|
||||||
|
flags = windows.MB_YESNO
|
||||||
|
case frontend.WarningDialog:
|
||||||
|
flags = windows.MB_OK | windows.MB_ICONWARNING
|
||||||
|
}
|
||||||
|
|
||||||
|
button, _ := windows.MessageBox(windows.HWND(f.mainWindow.Handle()), message, title, flags|windows.MB_SYSTEMMODAL)
|
||||||
|
// This maps MessageBox return values to strings
|
||||||
|
responses := []string{"", "Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "", "", "Try Again", "Continue"}
|
||||||
|
result := "Error"
|
||||||
|
if int(button) < len(responses) {
|
||||||
|
result = responses[button]
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertFilters(filters []frontend.FileFilter) []cfd.FileFilter {
|
||||||
|
var result []cfd.FileFilter
|
||||||
|
for _, filter := range filters {
|
||||||
|
result = append(result, cfd.FileFilter(filter))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package windows
|
package windows
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"github.com/tadvi/winc"
|
"github.com/tadvi/winc"
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
"github.com/wailsapp/wails/v2/internal/logger"
|
"github.com/wailsapp/wails/v2/internal/logger"
|
||||||
@ -37,6 +38,12 @@ func (f *Frontend) Run() error {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO: Move this into a callback from frontend
|
||||||
|
go func() {
|
||||||
|
ctx := context.WithValue(context.Background(), "frontend", f)
|
||||||
|
f.frontendOptions.Startup(ctx)
|
||||||
|
}()
|
||||||
|
|
||||||
winc.RunMainLoop()
|
winc.RunMainLoop()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
200
v2/internal/frontend/windows/keys.go
Normal file
200
v2/internal/frontend/windows/keys.go
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tadvi/winc"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ModifierMap = map[keys.Modifier]winc.Modifiers{
|
||||||
|
keys.ShiftKey: winc.ModShift,
|
||||||
|
keys.ControlKey: winc.ModControl,
|
||||||
|
keys.OptionOrAltKey: winc.ModAlt,
|
||||||
|
keys.CmdOrCtrlKey: winc.ModControl,
|
||||||
|
}
|
||||||
|
|
||||||
|
func acceleratorToWincShortcut(accelerator *keys.Accelerator) winc.Shortcut {
|
||||||
|
|
||||||
|
if accelerator == nil {
|
||||||
|
return winc.NoShortcut
|
||||||
|
}
|
||||||
|
inKey := strings.ToUpper(accelerator.Key)
|
||||||
|
key, exists := keyMap[inKey]
|
||||||
|
if !exists {
|
||||||
|
return winc.NoShortcut
|
||||||
|
}
|
||||||
|
var modifiers winc.Modifiers
|
||||||
|
if _, exists := shiftMap[inKey]; exists {
|
||||||
|
modifiers = winc.ModShift
|
||||||
|
}
|
||||||
|
for _, mod := range accelerator.Modifiers {
|
||||||
|
modifiers |= ModifierMap[mod]
|
||||||
|
}
|
||||||
|
return winc.Shortcut{
|
||||||
|
Modifiers: modifiers,
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var shiftMap = map[string]struct{}{
|
||||||
|
"~": {},
|
||||||
|
")": {},
|
||||||
|
"!": {},
|
||||||
|
"@": {},
|
||||||
|
"#": {},
|
||||||
|
"$": {},
|
||||||
|
"%": {},
|
||||||
|
"^": {},
|
||||||
|
"&": {},
|
||||||
|
"*": {},
|
||||||
|
"(": {},
|
||||||
|
"_": {},
|
||||||
|
"PLUS": {},
|
||||||
|
"<": {},
|
||||||
|
">": {},
|
||||||
|
"?": {},
|
||||||
|
":": {},
|
||||||
|
`"`: {},
|
||||||
|
"{": {},
|
||||||
|
"}": {},
|
||||||
|
"|": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
var keyMap = map[string]winc.Key{
|
||||||
|
"0": winc.Key0,
|
||||||
|
"1": winc.Key1,
|
||||||
|
"2": winc.Key2,
|
||||||
|
"3": winc.Key3,
|
||||||
|
"4": winc.Key4,
|
||||||
|
"5": winc.Key5,
|
||||||
|
"6": winc.Key6,
|
||||||
|
"7": winc.Key7,
|
||||||
|
"8": winc.Key8,
|
||||||
|
"9": winc.Key9,
|
||||||
|
"A": winc.KeyA,
|
||||||
|
"B": winc.KeyB,
|
||||||
|
"C": winc.KeyC,
|
||||||
|
"D": winc.KeyD,
|
||||||
|
"E": winc.KeyE,
|
||||||
|
"F": winc.KeyF,
|
||||||
|
"G": winc.KeyG,
|
||||||
|
"H": winc.KeyH,
|
||||||
|
"I": winc.KeyI,
|
||||||
|
"J": winc.KeyJ,
|
||||||
|
"K": winc.KeyK,
|
||||||
|
"L": winc.KeyL,
|
||||||
|
"M": winc.KeyM,
|
||||||
|
"N": winc.KeyN,
|
||||||
|
"O": winc.KeyO,
|
||||||
|
"P": winc.KeyP,
|
||||||
|
"Q": winc.KeyQ,
|
||||||
|
"R": winc.KeyR,
|
||||||
|
"S": winc.KeyS,
|
||||||
|
"T": winc.KeyT,
|
||||||
|
"U": winc.KeyU,
|
||||||
|
"V": winc.KeyV,
|
||||||
|
"W": winc.KeyW,
|
||||||
|
"X": winc.KeyX,
|
||||||
|
"Y": winc.KeyY,
|
||||||
|
"Z": winc.KeyZ,
|
||||||
|
"F1": winc.KeyF1,
|
||||||
|
"F2": winc.KeyF2,
|
||||||
|
"F3": winc.KeyF3,
|
||||||
|
"F4": winc.KeyF4,
|
||||||
|
"F5": winc.KeyF5,
|
||||||
|
"F6": winc.KeyF6,
|
||||||
|
"F7": winc.KeyF7,
|
||||||
|
"F8": winc.KeyF8,
|
||||||
|
"F9": winc.KeyF9,
|
||||||
|
"F10": winc.KeyF10,
|
||||||
|
"F11": winc.KeyF11,
|
||||||
|
"F12": winc.KeyF12,
|
||||||
|
"F13": winc.KeyF13,
|
||||||
|
"F14": winc.KeyF14,
|
||||||
|
"F15": winc.KeyF15,
|
||||||
|
"F16": winc.KeyF16,
|
||||||
|
"F17": winc.KeyF17,
|
||||||
|
"F18": winc.KeyF18,
|
||||||
|
"F19": winc.KeyF19,
|
||||||
|
"F20": winc.KeyF20,
|
||||||
|
"F21": winc.KeyF21,
|
||||||
|
"F22": winc.KeyF22,
|
||||||
|
"F23": winc.KeyF23,
|
||||||
|
"F24": winc.KeyF24,
|
||||||
|
|
||||||
|
"`": winc.KeyOEM3,
|
||||||
|
",": winc.KeyOEMComma,
|
||||||
|
".": winc.KeyOEMPeriod,
|
||||||
|
"/": winc.KeyOEM2,
|
||||||
|
";": winc.KeyOEM1,
|
||||||
|
"'": winc.KeyOEM7,
|
||||||
|
"[": winc.KeyOEM4,
|
||||||
|
"]": winc.KeyOEM6,
|
||||||
|
`\`: winc.KeyOEM5,
|
||||||
|
|
||||||
|
"~": winc.KeyOEM3, //
|
||||||
|
")": winc.Key0,
|
||||||
|
"!": winc.Key1,
|
||||||
|
"@": winc.Key2,
|
||||||
|
"#": winc.Key3,
|
||||||
|
"$": winc.Key4,
|
||||||
|
"%": winc.Key5,
|
||||||
|
"^": winc.Key6,
|
||||||
|
"&": winc.Key7,
|
||||||
|
"*": winc.Key8,
|
||||||
|
"(": winc.Key9,
|
||||||
|
"_": winc.KeyOEMMinus,
|
||||||
|
"PLUS": winc.KeyOEMPlus,
|
||||||
|
"<": winc.KeyOEMComma,
|
||||||
|
">": winc.KeyOEMPeriod,
|
||||||
|
"?": winc.KeyOEM2,
|
||||||
|
":": winc.KeyOEM1,
|
||||||
|
`"`: winc.KeyOEM7,
|
||||||
|
"{": winc.KeyOEM4,
|
||||||
|
"}": winc.KeyOEM6,
|
||||||
|
"|": winc.KeyOEM5,
|
||||||
|
|
||||||
|
"SPACE": winc.KeySpace,
|
||||||
|
"TAB": winc.KeyTab,
|
||||||
|
"CAPSLOCK": winc.KeyCapital,
|
||||||
|
"NUMLOCK": winc.KeyNumlock,
|
||||||
|
"SCROLLLOCK": winc.KeyScroll,
|
||||||
|
"BACKSPACE": winc.KeyBack,
|
||||||
|
"DELETE": winc.KeyDelete,
|
||||||
|
"INSERT": winc.KeyInsert,
|
||||||
|
"RETURN": winc.KeyReturn,
|
||||||
|
"ENTER": winc.KeyReturn,
|
||||||
|
"UP": winc.KeyUp,
|
||||||
|
"DOWN": winc.KeyDown,
|
||||||
|
"LEFT": winc.KeyLeft,
|
||||||
|
"RIGHT": winc.KeyRight,
|
||||||
|
"HOME": winc.KeyHome,
|
||||||
|
"END": winc.KeyEnd,
|
||||||
|
"PAGEUP": winc.KeyPrior,
|
||||||
|
"PAGEDOWN": winc.KeyNext,
|
||||||
|
"ESCAPE": winc.KeyEscape,
|
||||||
|
"ESC": winc.KeyEscape,
|
||||||
|
"VOLUMEUP": winc.KeyVolumeUp,
|
||||||
|
"VOLUMEDOWN": winc.KeyVolumeDown,
|
||||||
|
"VOLUMEMUTE": winc.KeyVolumeMute,
|
||||||
|
"MEDIANEXTTRACK": winc.KeyMediaNextTrack,
|
||||||
|
"MEDIAPREVIOUSTRACK": winc.KeyMediaPrevTrack,
|
||||||
|
"MEDIASTOP": winc.KeyMediaStop,
|
||||||
|
"MEDIAPLAYPAUSE": winc.KeyMediaPlayPause,
|
||||||
|
"PRINTSCREEN": winc.KeyPrint,
|
||||||
|
"NUM0": winc.KeyNumpad0,
|
||||||
|
"NUM1": winc.KeyNumpad1,
|
||||||
|
"NUM2": winc.KeyNumpad2,
|
||||||
|
"NUM3": winc.KeyNumpad3,
|
||||||
|
"NUM4": winc.KeyNumpad4,
|
||||||
|
"NUM5": winc.KeyNumpad5,
|
||||||
|
"NUM6": winc.KeyNumpad6,
|
||||||
|
"NUM7": winc.KeyNumpad7,
|
||||||
|
"NUM8": winc.KeyNumpad8,
|
||||||
|
"NUM9": winc.KeyNumpad9,
|
||||||
|
"nummult": winc.KeyMultiply,
|
||||||
|
"numadd": winc.KeyAdd,
|
||||||
|
"numsub": winc.KeySubtract,
|
||||||
|
"numdec": winc.KeyDecimal,
|
||||||
|
"numdiv": winc.KeyDivide,
|
||||||
|
}
|
@ -36,9 +36,14 @@ func addRadioItemToMap(menuItem *menu.MenuItem, wincMenuItem *winc.MenuItem) {
|
|||||||
radioGroupMap[menuItem] = append(radioGroupMap[menuItem], wincMenuItem)
|
radioGroupMap[menuItem] = append(radioGroupMap[menuItem], wincMenuItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processApplicationMenu(window *Window, menuToProcess *menu.Menu) {
|
func (w *Window) SetApplicationMenu(menu *menu.Menu) {
|
||||||
|
w.applicationMenu = menu
|
||||||
|
processMenu(w, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processMenu(window *Window, menu *menu.Menu) {
|
||||||
mainMenu := window.NewMenu()
|
mainMenu := window.NewMenu()
|
||||||
for _, menuItem := range menuToProcess.Items {
|
for _, menuItem := range menu.Items {
|
||||||
submenu := mainMenu.AddSubMenu(menuItem.Label)
|
submenu := mainMenu.AddSubMenu(menuItem.Label)
|
||||||
for _, menuItem := range menuItem.SubMenu.Items {
|
for _, menuItem := range menuItem.SubMenu.Items {
|
||||||
processMenuItem(submenu, menuItem)
|
processMenuItem(submenu, menuItem)
|
||||||
@ -55,7 +60,8 @@ func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) {
|
|||||||
case menu.SeparatorType:
|
case menu.SeparatorType:
|
||||||
parent.AddSeparator()
|
parent.AddSeparator()
|
||||||
case menu.TextType:
|
case menu.TextType:
|
||||||
newItem := parent.AddItem(menuItem.Label, winc.NoShortcut)
|
shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||||
|
newItem := parent.AddItem(menuItem.Label, shortcut)
|
||||||
if menuItem.Tooltip != "" {
|
if menuItem.Tooltip != "" {
|
||||||
newItem.SetToolTip(menuItem.Tooltip)
|
newItem.SetToolTip(menuItem.Tooltip)
|
||||||
}
|
}
|
||||||
@ -69,7 +75,8 @@ func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) {
|
|||||||
newItem.SetEnabled(!menuItem.Disabled)
|
newItem.SetEnabled(!menuItem.Disabled)
|
||||||
|
|
||||||
case menu.CheckboxType:
|
case menu.CheckboxType:
|
||||||
newItem := parent.AddItem(menuItem.Label, winc.NoShortcut)
|
shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||||
|
newItem := parent.AddItem(menuItem.Label, shortcut)
|
||||||
newItem.SetCheckable(true)
|
newItem.SetCheckable(true)
|
||||||
newItem.SetChecked(menuItem.Checked)
|
newItem.SetChecked(menuItem.Checked)
|
||||||
if menuItem.Tooltip != "" {
|
if menuItem.Tooltip != "" {
|
||||||
@ -86,7 +93,8 @@ func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) {
|
|||||||
newItem.SetEnabled(!menuItem.Disabled)
|
newItem.SetEnabled(!menuItem.Disabled)
|
||||||
addCheckBoxToMap(menuItem, newItem)
|
addCheckBoxToMap(menuItem, newItem)
|
||||||
case menu.RadioType:
|
case menu.RadioType:
|
||||||
newItem := parent.AddItemRadio(menuItem.Label, winc.NoShortcut)
|
shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||||
|
newItem := parent.AddItemRadio(menuItem.Label, shortcut)
|
||||||
newItem.SetCheckable(true)
|
newItem.SetCheckable(true)
|
||||||
newItem.SetChecked(menuItem.Checked)
|
newItem.SetChecked(menuItem.Checked)
|
||||||
if menuItem.Tooltip != "" {
|
if menuItem.Tooltip != "" {
|
||||||
@ -109,3 +117,11 @@ func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Frontend) SetApplicationMenu(menu *menu.Menu) {
|
||||||
|
f.mainWindow.SetApplicationMenu(menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Frontend) UpdateApplicationMenu() {
|
||||||
|
processMenu(f.mainWindow, f.mainWindow.applicationMenu)
|
||||||
|
}
|
||||||
|
@ -3,12 +3,14 @@ package windows
|
|||||||
import (
|
import (
|
||||||
"github.com/tadvi/winc"
|
"github.com/tadvi/winc"
|
||||||
"github.com/tadvi/winc/w32"
|
"github.com/tadvi/winc/w32"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Window struct {
|
type Window struct {
|
||||||
winc.Form
|
winc.Form
|
||||||
frontendOptions *options.App
|
frontendOptions *options.App
|
||||||
|
applicationMenu *menu.Menu
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWindow(parent winc.Controller, options *options.App) *Window {
|
func NewWindow(parent winc.Controller, options *options.App) *Window {
|
||||||
@ -61,7 +63,7 @@ func NewWindow(parent winc.Controller, options *options.App) *Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if options.Windows.Menu != nil {
|
if options.Windows.Menu != nil {
|
||||||
processApplicationMenu(result, options.Windows.Menu)
|
result.SetApplicationMenu(options.Windows.Menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -187,10 +187,10 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
verbose := options.Verbosity == VERBOSE
|
verbose := options.Verbosity == VERBOSE
|
||||||
// Run go mod tidy first
|
// Run go mod tidy first
|
||||||
cmd := exec.Command(options.Compiler, "mod", "tidy")
|
cmd := exec.Command(options.Compiler, "mod", "tidy")
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
if verbose {
|
if verbose {
|
||||||
println("")
|
println("")
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
}
|
}
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -271,10 +271,10 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
|
|
||||||
// Create the command
|
// Create the command
|
||||||
cmd = exec.Command(options.Compiler, commands.AsSlice()...)
|
cmd = exec.Command(options.Compiler, commands.AsSlice()...)
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
if verbose {
|
if verbose {
|
||||||
println(" Build command:", commands.Join(" "))
|
println(" Build command:", commands.Join(" "))
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
}
|
}
|
||||||
// Set the directory
|
// Set the directory
|
||||||
cmd.Dir = b.projectData.Path
|
cmd.Dir = b.projectData.Path
|
||||||
@ -321,17 +321,13 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
|
|||||||
println(" Environment:", strings.Join(cmd.Env, " "))
|
println(" Environment:", strings.Join(cmd.Env, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup buffers
|
|
||||||
var stdo, stde bytes.Buffer
|
|
||||||
cmd.Stdout = &stdo
|
|
||||||
cmd.Stderr = &stde
|
|
||||||
|
|
||||||
// Run command
|
// Run command
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
|
||||||
// Format error if we have one
|
// Format error if we have one
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s\n%s", err, string(stde.Bytes()))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Done.")
|
println("Done.")
|
||||||
|
59
v2/pkg/runtime/dialog-x.go
Normal file
59
v2/pkg/runtime/dialog-x.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//+build experimental
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileFilter defines a filter for dialog boxes
|
||||||
|
type FileFilter = frontend.FileFilter
|
||||||
|
|
||||||
|
// OpenDialogOptions contains the options for the OpenDialogOptions runtime method
|
||||||
|
type OpenDialogOptions = frontend.OpenDialogOptions
|
||||||
|
|
||||||
|
// SaveDialogOptions contains the options for the SaveDialog runtime method
|
||||||
|
type SaveDialogOptions = frontend.SaveDialogOptions
|
||||||
|
|
||||||
|
type DialogType = frontend.DialogType
|
||||||
|
|
||||||
|
const (
|
||||||
|
InfoDialog = frontend.InfoDialog
|
||||||
|
WarningDialog = frontend.WarningDialog
|
||||||
|
ErrorDialog = frontend.ErrorDialog
|
||||||
|
QuestionDialog = frontend.QuestionDialog
|
||||||
|
)
|
||||||
|
|
||||||
|
// MessageDialogOptions contains the options for the Message dialogs, EG Info, Warning, etc runtime methods
|
||||||
|
type MessageDialogOptions = frontend.MessageDialogOptions
|
||||||
|
|
||||||
|
// OpenDirectoryDialog prompts the user to select a directory
|
||||||
|
func OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
return frontend.OpenDirectoryDialog(dialogOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFileDialog prompts the user to select a file
|
||||||
|
func OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
return frontend.OpenFileDialog(dialogOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenMultipleFilesDialog prompts the user to select a file
|
||||||
|
func OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
return frontend.OpenMultipleFilesDialog(dialogOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveFileDialog prompts the user to select a file
|
||||||
|
func SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
return frontend.SaveFileDialog(dialogOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageDialog show a message dialog to the user
|
||||||
|
func MessageDialog(ctx context.Context, dialogOptions MessageDialogOptions) (string, error) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
return frontend.MessageDialog(dialogOptions)
|
||||||
|
}
|
@ -60,23 +60,6 @@ type MessageDialogOptions struct {
|
|||||||
Icon string
|
Icon string
|
||||||
}
|
}
|
||||||
|
|
||||||
// processTitleAndFilter return the title and filter from the given params.
|
|
||||||
// title is the first string, filter is the second
|
|
||||||
func processTitleAndFilter(params ...string) (string, string) {
|
|
||||||
|
|
||||||
var title, filter string
|
|
||||||
|
|
||||||
if len(params) > 0 {
|
|
||||||
title = params[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(params) > 1 {
|
|
||||||
filter = params[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return title, filter
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenDirectoryDialog prompts the user to select a directory
|
// OpenDirectoryDialog prompts the user to select a directory
|
||||||
func OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
func OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) {
|
||||||
|
|
||||||
|
34
v2/pkg/runtime/menu-x.go
Normal file
34
v2/pkg/runtime/menu-x.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//+build experimental
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateApplicationMenu(ctx context.Context) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
frontend.UpdateApplicationMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func UpdateContextMenu(ctx context.Context, contextMenu *menu.ContextMenu) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
bus.Publish("menu:updatecontextmenu", contextMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTrayMenu(ctx context.Context, trayMenu *menu.TrayMenu) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
bus.Publish("menu:settraymenu", trayMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateTrayMenuLabel(ctx context.Context, trayMenu *menu.TrayMenu) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
bus.Publish("menu:updatetraymenulabel", trayMenu)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTrayMenu(ctx context.Context, trayMenu *menu.TrayMenu) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
bus.Publish("menu:deletetraymenu", trayMenu)
|
||||||
|
}
|
||||||
|
*/
|
27
v2/pkg/runtime/runtime-x.go
Normal file
27
v2/pkg/runtime/runtime-x.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//+build experimental
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
|
"log"
|
||||||
|
goruntime "runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getFrontend(ctx context.Context) frontend.Frontend {
|
||||||
|
result := ctx.Value("frontend")
|
||||||
|
if result != nil {
|
||||||
|
return result.(frontend.Frontend)
|
||||||
|
}
|
||||||
|
pc, _, _, _ := goruntime.Caller(1)
|
||||||
|
funcName := goruntime.FuncForPC(pc).Name()
|
||||||
|
log.Fatalf("cannot call '%s': Application not initialised", funcName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit the application
|
||||||
|
func Quit(ctx context.Context) {
|
||||||
|
frontend := getFrontend(ctx)
|
||||||
|
frontend.Quit()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user