diff --git a/v2/internal/appng/app.go b/v2/internal/appng/app.go index d47fec907..1ee0b4635 100644 --- a/v2/internal/appng/app.go +++ b/v2/internal/appng/app.go @@ -131,7 +131,7 @@ func CreateApp(appoptions *options.App) (*App, error) { bindingExemptions := []interface{}{appoptions.Startup, appoptions.Shutdown} appBindings := binding.NewBindings(myLogger, appoptions.Bind, bindingExemptions) - appFrontend := frontend.NewFrontend(appoptions, myLogger, appBindings) + appFrontend := NewFrontend(appoptions, myLogger, appBindings) result := &App{ frontend: appFrontend, diff --git a/v2/internal/frontend/frontend_windows.go b/v2/internal/appng/app_windows.go similarity index 61% rename from v2/internal/frontend/frontend_windows.go rename to v2/internal/appng/app_windows.go index a83647dcf..61ff25873 100644 --- a/v2/internal/frontend/frontend_windows.go +++ b/v2/internal/appng/app_windows.go @@ -1,12 +1,13 @@ -package frontend +package appng import ( "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/logger" "github.com/wailsapp/wails/v2/pkg/options" ) -func NewFrontend(appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings) *windows.Frontend { - return windows.NewFrontend(appoptions, myLogger, appBindings) +func NewFrontend(appoptions *options.App, myLogger *logger.Logger, bindings *binding.Bindings) frontend.Frontend { + return windows.NewFrontend(appoptions, myLogger, bindings) } diff --git a/v2/internal/frontend/frontend.go b/v2/internal/frontend/frontend.go index f714ac97c..3c2bb0b62 100644 --- a/v2/internal/frontend/frontend.go +++ b/v2/internal/frontend/frontend.go @@ -1,5 +1,58 @@ 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 { // Main methods @@ -10,12 +63,12 @@ type Frontend interface { //NotifyEvent(message string) //CallResult(message string) // - //// Dialog - //OpenFileDialog(dialogOptions dialog.OpenDialogOptions, callbackID string) - //OpenMultipleFilesDialog(dialogOptions dialog.OpenDialogOptions, callbackID string) - //OpenDirectoryDialog(dialogOptions dialog.OpenDialogOptions, callbackID string) - //SaveDialog(dialogOptions dialog.SaveDialogOptions, callbackID string) - //MessageDialog(dialogOptions dialog.MessageDialogOptions, callbackID string) + // Dialog + OpenFileDialog(dialogOptions OpenDialogOptions) (string, error) + OpenMultipleFilesDialog(dialogOptions OpenDialogOptions) ([]string, error) + OpenDirectoryDialog(dialogOptions OpenDialogOptions) (string, error) + SaveFileDialog(dialogOptions SaveDialogOptions) (string, error) + MessageDialog(dialogOptions MessageDialogOptions) (string, error) // Window WindowSetTitle(title string) @@ -35,9 +88,10 @@ type Frontend interface { WindowFullscreen() WindowUnFullscreen() WindowSetColour(colour int) - // - //// Menus - //SetApplicationMenu(menu *menu.Menu) + + // Menus + SetApplicationMenu(menu *menu.Menu) + UpdateApplicationMenu() //SetTrayMenu(menu *menu.TrayMenu) //UpdateTrayMenuLabel(menu *menu.TrayMenu) //UpdateContextMenu(contextMenu *menu.ContextMenu) diff --git a/v2/internal/frontend/windows/dialog.go b/v2/internal/frontend/windows/dialog.go new file mode 100644 index 000000000..cdc931e13 --- /dev/null +++ b/v2/internal/frontend/windows/dialog.go @@ -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 +} diff --git a/v2/internal/frontend/windows/frontend.go b/v2/internal/frontend/windows/frontend.go index b764776ef..0790e9137 100644 --- a/v2/internal/frontend/windows/frontend.go +++ b/v2/internal/frontend/windows/frontend.go @@ -1,6 +1,7 @@ package windows import ( + "context" "github.com/tadvi/winc" "github.com/wailsapp/wails/v2/internal/binding" "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() return nil } diff --git a/v2/internal/frontend/windows/keys.go b/v2/internal/frontend/windows/keys.go new file mode 100644 index 000000000..072f2eab0 --- /dev/null +++ b/v2/internal/frontend/windows/keys.go @@ -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, +} diff --git a/v2/internal/frontend/windows/menu.go b/v2/internal/frontend/windows/menu.go index 3acd1251c..3aa0ba068 100644 --- a/v2/internal/frontend/windows/menu.go +++ b/v2/internal/frontend/windows/menu.go @@ -36,9 +36,14 @@ func addRadioItemToMap(menuItem *menu.MenuItem, wincMenuItem *winc.MenuItem) { 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() - for _, menuItem := range menuToProcess.Items { + for _, menuItem := range menu.Items { submenu := mainMenu.AddSubMenu(menuItem.Label) for _, menuItem := range menuItem.SubMenu.Items { processMenuItem(submenu, menuItem) @@ -55,7 +60,8 @@ func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) { case menu.SeparatorType: parent.AddSeparator() case menu.TextType: - newItem := parent.AddItem(menuItem.Label, winc.NoShortcut) + shortcut := acceleratorToWincShortcut(menuItem.Accelerator) + newItem := parent.AddItem(menuItem.Label, shortcut) if menuItem.Tooltip != "" { newItem.SetToolTip(menuItem.Tooltip) } @@ -69,7 +75,8 @@ func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) { newItem.SetEnabled(!menuItem.Disabled) case menu.CheckboxType: - newItem := parent.AddItem(menuItem.Label, winc.NoShortcut) + shortcut := acceleratorToWincShortcut(menuItem.Accelerator) + newItem := parent.AddItem(menuItem.Label, shortcut) newItem.SetCheckable(true) newItem.SetChecked(menuItem.Checked) if menuItem.Tooltip != "" { @@ -86,7 +93,8 @@ func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) { newItem.SetEnabled(!menuItem.Disabled) addCheckBoxToMap(menuItem, newItem) case menu.RadioType: - newItem := parent.AddItemRadio(menuItem.Label, winc.NoShortcut) + shortcut := acceleratorToWincShortcut(menuItem.Accelerator) + newItem := parent.AddItemRadio(menuItem.Label, shortcut) newItem.SetCheckable(true) newItem.SetChecked(menuItem.Checked) 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) +} diff --git a/v2/internal/frontend/windows/window.go b/v2/internal/frontend/windows/window.go index c1b63a41f..7f5669f99 100644 --- a/v2/internal/frontend/windows/window.go +++ b/v2/internal/frontend/windows/window.go @@ -3,12 +3,14 @@ package windows import ( "github.com/tadvi/winc" "github.com/tadvi/winc/w32" + "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/options" ) type Window struct { winc.Form frontendOptions *options.App + applicationMenu *menu.Menu } 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 { - processApplicationMenu(result, options.Windows.Menu) + result.SetApplicationMenu(options.Windows.Menu) } return result diff --git a/v2/pkg/commands/build/base.go b/v2/pkg/commands/build/base.go index 3dfd7a30e..7f0e9a2ca 100644 --- a/v2/pkg/commands/build/base.go +++ b/v2/pkg/commands/build/base.go @@ -187,10 +187,10 @@ func (b *BaseBuilder) CompileProject(options *Options) error { verbose := options.Verbosity == VERBOSE // Run go mod tidy first cmd := exec.Command(options.Compiler, "mod", "tidy") + cmd.Stderr = os.Stderr if verbose { println("") cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr } err := cmd.Run() if err != nil { @@ -271,10 +271,10 @@ func (b *BaseBuilder) CompileProject(options *Options) error { // Create the command cmd = exec.Command(options.Compiler, commands.AsSlice()...) + cmd.Stderr = os.Stderr if verbose { println(" Build command:", commands.Join(" ")) cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr } // Set the directory cmd.Dir = b.projectData.Path @@ -321,17 +321,13 @@ func (b *BaseBuilder) CompileProject(options *Options) error { println(" Environment:", strings.Join(cmd.Env, " ")) } - // Setup buffers - var stdo, stde bytes.Buffer - cmd.Stdout = &stdo - cmd.Stderr = &stde - // Run command err = cmd.Run() + cmd.Stderr = os.Stderr // Format error if we have one if err != nil { - return fmt.Errorf("%s\n%s", err, string(stde.Bytes())) + return err } println("Done.") diff --git a/v2/pkg/runtime/dialog-x.go b/v2/pkg/runtime/dialog-x.go new file mode 100644 index 000000000..6f26b664e --- /dev/null +++ b/v2/pkg/runtime/dialog-x.go @@ -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) +} diff --git a/v2/pkg/runtime/dialog.go b/v2/pkg/runtime/dialog.go index d23bc50d8..ba2f560b5 100644 --- a/v2/pkg/runtime/dialog.go +++ b/v2/pkg/runtime/dialog.go @@ -60,23 +60,6 @@ type MessageDialogOptions struct { 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 func OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error) { diff --git a/v2/pkg/runtime/menu-x.go b/v2/pkg/runtime/menu-x.go new file mode 100644 index 000000000..96aa0b378 --- /dev/null +++ b/v2/pkg/runtime/menu-x.go @@ -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) +} +*/ diff --git a/v2/pkg/runtime/runtime-x.go b/v2/pkg/runtime/runtime-x.go new file mode 100644 index 000000000..a65deea7b --- /dev/null +++ b/v2/pkg/runtime/runtime-x.go @@ -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() +}