From 4d58b56d54844771da5fc3268d20716173586fa5 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Wed, 21 Dec 2022 21:30:26 +1100 Subject: [PATCH] Improve dialogs --- exp/examples/dialogs/main.go | 76 ++++++++++++++ exp/pkg/application/dialogs.go | 137 +++++++++++++++++++++++--- exp/pkg/application/dialogs_darwin.go | 111 +++++++++++++++++---- 3 files changed, 290 insertions(+), 34 deletions(-) diff --git a/exp/examples/dialogs/main.go b/exp/examples/dialogs/main.go index 97b436575..96e5de440 100644 --- a/exp/examples/dialogs/main.go +++ b/exp/examples/dialogs/main.go @@ -3,6 +3,8 @@ package main import ( _ "embed" "log" + "os" + "runtime" "strings" "github.com/wailsapp/wails/exp/pkg/application" @@ -205,6 +207,63 @@ func main() { app.NewInfoDialog().SetMessage("No directory selected").Show() } }) + openMenu.Add("Open Directory (Resolves Aliases)").OnClick(func(ctx *application.Context) { + result, _ := app.NewOpenFileDialog(). + CanChooseDirectories(true). + CanCreateDirectories(true). + ResolvesAliases(true). + PromptForSingleSelection() + if result != "" { + app.NewInfoDialog().SetMessage(result).Show() + } else { + app.NewInfoDialog().SetMessage("No directory selected").Show() + } + }) + openMenu.Add("Open File/Directory (Set Title)").OnClick(func(ctx *application.Context) { + dialog := app.NewOpenFileDialog(). + CanChooseDirectories(true). + CanCreateDirectories(true). + ResolvesAliases(true) + if runtime.GOOS == "darwin" { + dialog.SetMessage("Select a file/directory") + } else { + dialog.SetTitle("Select a file/directory") + } + + result, _ := dialog.PromptForSingleSelection() + if result != "" { + app.NewInfoDialog().SetMessage(result).Show() + } else { + app.NewInfoDialog().SetMessage("No file/directory selected").Show() + } + }) + openMenu.Add("Open (Full Example)").OnClick(func(ctx *application.Context) { + cwd, _ := os.Getwd() + dialog := app.NewOpenFileDialog(). + SetTitle("Select a file"). + SetMessage("Select a file to open"). + SetButtonText("Let's do this!"). + SetDirectory(cwd). + CanCreateDirectories(true). + ResolvesAliases(true). + AllowsOtherFileTypes(true). + TreatsFilePackagesAsDirectories(true). + ShowHiddenFiles(true). + CanSelectHiddenExtension(true) + + if runtime.GOOS == "darwin" { + dialog.SetMessage("Select a file") + } else { + dialog.SetTitle("Select a file") + } + + result, _ := dialog.PromptForSingleSelection() + if result != "" { + app.NewInfoDialog().SetMessage(result).Show() + } else { + app.NewInfoDialog().SetMessage("No file selected").Show() + } + }) saveMenu := menu.AddSubmenu("Save") saveMenu.Add("Select File (Defaults)").OnClick(func(ctx *application.Context) { @@ -238,6 +297,23 @@ func main() { app.NewInfoDialog().SetMessage(result).Show() } }) + saveMenu.Add("Select File (Full Example)").OnClick(func(ctx *application.Context) { + result, _ := app.NewSaveFileDialog(). + CanCreateDirectories(false). + ShowHiddenFiles(true). + SetMessage("Select a file"). + SetDirectory("/Applications"). + SetButtonText("Let's do this!"). + SetFilename("README.md"). + HideExtension(true). + AllowsOtherFileTypes(true). + TreatsFilePackagesAsDirectories(true). + ShowHiddenFiles(true). + PromptForSingleSelection() + if result != "" { + app.NewInfoDialog().SetMessage(result).Show() + } + }) app.SetMenu(menu) diff --git a/exp/pkg/application/dialogs.go b/exp/pkg/application/dialogs.go index 7ba5b7628..f59123742 100644 --- a/exp/pkg/application/dialogs.go +++ b/exp/pkg/application/dialogs.go @@ -74,11 +74,6 @@ func (d *MessageDialog) SetTitle(title string) *MessageDialog { return d } -func (d *MessageDialog) SetMessage(message string) *MessageDialog { - d.message = message - return d -} - func (d *MessageDialog) Show() { if d.impl == nil { d.impl = newDialogImpl(d) @@ -115,18 +110,33 @@ func (d *MessageDialog) SetCancelButton(button *Button) *MessageDialog { return d } +func (d *MessageDialog) SetMessage(title string) *MessageDialog { + d.title = title + return d +} + type openFileDialogImpl interface { show() ([]string, error) } type OpenFileDialog struct { - id uint - canChooseDirectories bool - canChooseFiles bool - canCreateDirectories bool - showHiddenFiles bool - allowsMultipleSelection bool - window *Window + id uint + canChooseDirectories bool + canChooseFiles bool + canCreateDirectories bool + showHiddenFiles bool + resolvesAliases bool + allowsMultipleSelection bool + hideExtension bool + canSelectHiddenExtension bool + treatsFilePackagesAsDirectories bool + allowsOtherFileTypes bool + + title string + message string + buttonText string + directory string + window *Window impl openFileDialogImpl } @@ -146,16 +156,41 @@ func (d *OpenFileDialog) CanCreateDirectories(canCreateDirectories bool) *OpenFi return d } +func (d *OpenFileDialog) AllowsOtherFileTypes(allowsOtherFileTypes bool) *OpenFileDialog { + d.allowsOtherFileTypes = allowsOtherFileTypes + return d +} + func (d *OpenFileDialog) ShowHiddenFiles(showHiddenFiles bool) *OpenFileDialog { d.showHiddenFiles = showHiddenFiles return d } +func (d *OpenFileDialog) HideExtension(hideExtension bool) *OpenFileDialog { + d.hideExtension = hideExtension + return d +} + +func (d *OpenFileDialog) TreatsFilePackagesAsDirectories(treatsFilePackagesAsDirectories bool) *OpenFileDialog { + d.treatsFilePackagesAsDirectories = treatsFilePackagesAsDirectories + return d +} + func (d *OpenFileDialog) AttachToWindow(window *Window) *OpenFileDialog { d.window = window return d } +func (d *OpenFileDialog) ResolvesAliases(resolvesAliases bool) *OpenFileDialog { + d.resolvesAliases = resolvesAliases + return d +} + +func (d *OpenFileDialog) SetTitle(title string) *OpenFileDialog { + d.title = title + return d +} + func (d *OpenFileDialog) PromptForSingleSelection() (string, error) { d.allowsMultipleSelection = false if d.impl == nil { @@ -178,12 +213,33 @@ func (d *OpenFileDialog) PromptForMultipleSelection() ([]string, error) { return d.impl.show() } +func (d *OpenFileDialog) SetMessage(message string) *OpenFileDialog { + d.message = message + return d +} + +func (d *OpenFileDialog) SetButtonText(text string) *OpenFileDialog { + d.buttonText = text + return d +} + +func (d *OpenFileDialog) SetDirectory(directory string) *OpenFileDialog { + d.directory = directory + return d +} + +func (d *OpenFileDialog) CanSelectHiddenExtension(canSelectHiddenExtension bool) *OpenFileDialog { + d.canSelectHiddenExtension = canSelectHiddenExtension + return d +} + func newOpenFileDialog() *OpenFileDialog { return &OpenFileDialog{ id: getDialogID(), canChooseDirectories: false, canChooseFiles: true, canCreateDirectories: true, + resolvesAliases: false, } } @@ -195,10 +251,19 @@ func newSaveFileDialog() *SaveFileDialog { } type SaveFileDialog struct { - id uint - canCreateDirectories bool - showHiddenFiles bool - window *Window + id uint + canCreateDirectories bool + showHiddenFiles bool + canSelectHiddenExtension bool + allowOtherFileTypes bool + hideExtension bool + treatsFilePackagesAsDirectories bool + message string + directory string + filename string + buttonText string + + window *Window impl saveFileDialogImpl } @@ -212,11 +277,26 @@ func (d *SaveFileDialog) CanCreateDirectories(canCreateDirectories bool) *SaveFi return d } +func (d *SaveFileDialog) CanSelectHiddenExtension(canSelectHiddenExtension bool) *SaveFileDialog { + d.canSelectHiddenExtension = canSelectHiddenExtension + return d +} + func (d *SaveFileDialog) ShowHiddenFiles(showHiddenFiles bool) *SaveFileDialog { d.showHiddenFiles = showHiddenFiles return d } +func (d *SaveFileDialog) SetMessage(message string) *SaveFileDialog { + d.message = message + return d +} + +func (d *SaveFileDialog) SetDirectory(directory string) *SaveFileDialog { + d.directory = directory + return d +} + func (d *SaveFileDialog) AttachToWindow(window *Window) *SaveFileDialog { d.window = window return d @@ -228,3 +308,28 @@ func (d *SaveFileDialog) PromptForSingleSelection() (string, error) { } return d.impl.show() } + +func (d *SaveFileDialog) SetButtonText(text string) *SaveFileDialog { + d.buttonText = text + return d +} + +func (d *SaveFileDialog) SetFilename(filename string) *SaveFileDialog { + d.filename = filename + return d +} + +func (d *SaveFileDialog) AllowsOtherFileTypes(allowOtherFileTypes bool) *SaveFileDialog { + d.allowOtherFileTypes = allowOtherFileTypes + return d +} + +func (d *SaveFileDialog) HideExtension(hideExtension bool) *SaveFileDialog { + d.hideExtension = hideExtension + return d +} + +func (d *SaveFileDialog) TreatsFilePackagesAsDirectories(treatsFilePackagesAsDirectories bool) *SaveFileDialog { + d.treatsFilePackagesAsDirectories = treatsFilePackagesAsDirectories + return d +} diff --git a/exp/pkg/application/dialogs_darwin.go b/exp/pkg/application/dialogs_darwin.go index 3bb004dca..1aa47966d 100644 --- a/exp/pkg/application/dialogs_darwin.go +++ b/exp/pkg/application/dialogs_darwin.go @@ -123,17 +123,49 @@ static void processOpenFileDialogResults(NSOpenPanel *panel, NSInteger result, b } -static void showOpenFileDialog(unsigned int dialogID, bool canChooseFiles, bool canChooseDirectories, bool canCreateDirectories, bool showHiddenFiles, bool allowsMultipleSelection, void *window) { +static void showOpenFileDialog(unsigned int dialogID, + bool canChooseFiles, + bool canChooseDirectories, + bool canCreateDirectories, + bool showHiddenFiles, + bool allowsMultipleSelection, + bool resolvesAliases, + bool hideExtension, + bool treatsFilePackagesAsDirectories, + bool allowsOtherFileTypes, + char* message, + char* directory, + char* buttonText, + void *window) { // run on main thread dispatch_async(dispatch_get_main_queue(), ^{ NSOpenPanel *panel = [NSOpenPanel openPanel]; + if (message != NULL) { + [panel setMessage:[NSString stringWithUTF8String:message]]; + free(message); + } + + if (directory != NULL) { + [panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:directory]]]; + free(directory); + } + + if (buttonText != NULL) { + [panel setPrompt:[NSString stringWithUTF8String:buttonText]]; + free(buttonText); + } + [panel setCanChooseFiles:canChooseFiles]; [panel setCanChooseDirectories:canChooseDirectories]; [panel setCanCreateDirectories:canCreateDirectories]; [panel setShowsHiddenFiles:showHiddenFiles]; [panel setAllowsMultipleSelection:allowsMultipleSelection]; + [panel setResolvesAliases:resolvesAliases]; + [panel setExtensionHidden:hideExtension]; + [panel setTreatsFilePackagesAsDirectories:treatsFilePackagesAsDirectories]; + [panel setAllowsOtherFileTypes:allowsOtherFileTypes]; if (window != NULL) { [panel beginSheetModalForWindow:(__bridge NSWindow *)window completionHandler:^(NSInteger result) { @@ -147,28 +179,49 @@ static void showOpenFileDialog(unsigned int dialogID, bool canChooseFiles, bool }); } -static void showSaveFileDialog(unsigned int dialogID, bool canCreateDirectories, bool showHiddenFiles, void *window) { - // run on main thread +static void showSaveFileDialog(unsigned int dialogID, + bool canCreateDirectories, + bool showHiddenFiles, + bool canSelectHiddenExtension, + bool hideExtension, + bool treatsFilePackagesAsDirectories, + bool allowOtherFileTypes, + char* message, + char* directory, + char* buttonText, + char* filename, + void *window) { + +// run on main thread dispatch_async(dispatch_get_main_queue(), ^{ NSSavePanel *panel = [NSSavePanel savePanel]; + if (message != NULL) { + [panel setMessage:[NSString stringWithUTF8String:message]]; + free(message); + } + + if (directory != NULL) { + [panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:directory]]]; + free(directory); + } + + if (filename != NULL) { + [panel setNameFieldStringValue:[NSString stringWithUTF8String:filename]]; + free(filename); + } + + if (buttonText != NULL) { + [panel setPrompt:[NSString stringWithUTF8String:buttonText]]; + free(buttonText); + } + [panel setCanCreateDirectories:canCreateDirectories]; [panel setShowsHiddenFiles:showHiddenFiles]; - - //if (title != NULL) { - // [panel setTitle:[NSString stringWithUTF8String:title]]; - // free(title); - //} - - //if (defaultFilename != NULL) { - // [panel setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]]; - // free(defaultFilename); - //} - // - //if (defaultDirectory != NULL) { - // [panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]]]; - // free(defaultDirectory); - //} + [panel setCanSelectHiddenExtension:canSelectHiddenExtension]; + [panel setExtensionHidden:hideExtension]; + [panel setTreatsFilePackagesAsDirectories:treatsFilePackagesAsDirectories]; + [panel setAllowsOtherFileTypes:allowOtherFileTypes]; if (window != NULL) { [panel beginSheetModalForWindow:(__bridge NSWindow *)window completionHandler:^(NSInteger result) { @@ -300,6 +353,13 @@ func newOpenFileDialogImpl(d *OpenFileDialog) *macosOpenFileDialog { } } +func toCString(s string) *C.char { + if s == "" { + return nil + } + return C.CString(s) +} + func (m *macosOpenFileDialog) show() ([]string, error) { openFileResponses[dialogID] = make(chan string) nsWindow := unsafe.Pointer(nil) @@ -313,6 +373,13 @@ func (m *macosOpenFileDialog) show() ([]string, error) { C.bool(m.dialog.canCreateDirectories), C.bool(m.dialog.showHiddenFiles), C.bool(m.dialog.allowsMultipleSelection), + C.bool(m.dialog.resolvesAliases), + C.bool(m.dialog.hideExtension), + C.bool(m.dialog.treatsFilePackagesAsDirectories), + C.bool(m.dialog.allowsOtherFileTypes), + toCString(m.dialog.message), + toCString(m.dialog.directory), + toCString(m.dialog.buttonText), nsWindow) var result []string for filename := range openFileResponses[m.dialog.id] { @@ -364,6 +431,14 @@ func (m *macosSaveFileDialog) show() (string, error) { C.showSaveFileDialog(C.uint(m.dialog.id), C.bool(m.dialog.canCreateDirectories), C.bool(m.dialog.showHiddenFiles), + C.bool(m.dialog.canSelectHiddenExtension), + C.bool(m.dialog.hideExtension), + C.bool(m.dialog.treatsFilePackagesAsDirectories), + C.bool(m.dialog.allowOtherFileTypes), + toCString(m.dialog.message), + toCString(m.dialog.directory), + toCString(m.dialog.buttonText), + toCString(m.dialog.filename), nsWindow) return <-saveFileResponses[m.dialog.id], nil }