5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-08 12:00:43 +08:00
wails/v3/pkg/application/dialogs_windows.go
Lea Anthony dff47263d5 Set default extension for save dialog file filter
The code update sets the default extension to the first pattern in the save dialog file filter when options.Filters is populated. This improvement applies to Windows platform interface function for 'Save File Dialog' and provides a more intuitive user experience.
2024-01-17 22:35:58 +11:00

234 lines
5.4 KiB
Go

//go:build windows
package application
import (
"github.com/wailsapp/wails/v3/internal/go-common-file-dialog/cfd"
"github.com/wailsapp/wails/v3/pkg/w32"
"golang.org/x/sys/windows"
"path/filepath"
"strings"
)
func (m *windowsApp) showAboutDialog(title string, message string, _ []byte) {
about := newDialogImpl(&MessageDialog{
MessageDialogOptions: MessageDialogOptions{
DialogType: InfoDialogType,
Title: title,
Message: message,
},
})
about.UseAppIcon = true
about.show()
}
type windowsDialog struct {
dialog *MessageDialog
//dialogImpl unsafe.Pointer
UseAppIcon bool
}
func (m *windowsDialog) show() {
title := w32.MustStringToUTF16Ptr(m.dialog.Title)
message := w32.MustStringToUTF16Ptr(m.dialog.Message)
flags := calculateMessageDialogFlags(m.dialog.MessageDialogOptions)
var button int32
var parentWindow uintptr
var err error
if m.dialog.window != nil {
parentWindow, err = m.dialog.window.NativeWindowHandle()
if err != nil {
w32.Fatal(err.Error())
}
}
if m.UseAppIcon || m.dialog.Icon != nil {
// 3 is the application icon
button, _ = w32.MessageBoxWithIcon(parentWindow, message, title, 3, windows.MB_OK|windows.MB_USERICON)
} else {
button, _ = windows.MessageBox(windows.HWND(parentWindow), 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]
}
// Check if there's a callback for the button pressed
for _, button := range m.dialog.Buttons {
if button.Label == result {
if button.Callback != nil {
button.Callback()
}
}
}
}
func newDialogImpl(d *MessageDialog) *windowsDialog {
return &windowsDialog{
dialog: d,
}
}
type windowOpenFileDialog struct {
dialog *OpenFileDialogStruct
}
func newOpenFileDialogImpl(d *OpenFileDialogStruct) *windowOpenFileDialog {
return &windowOpenFileDialog{
dialog: d,
}
}
func getDefaultFolder(folder string) (string, error) {
if folder == "" {
return "", nil
}
return filepath.Abs(folder)
}
func (m *windowOpenFileDialog) show() (chan string, error) {
defaultFolder, err := getDefaultFolder(m.dialog.directory)
if err != nil {
return nil, err
}
config := cfd.DialogConfig{
Title: m.dialog.title,
Role: "PickFolder",
FileFilters: convertFilters(m.dialog.filters),
Folder: defaultFolder,
}
if m.dialog.window != nil {
config.ParentWindowHandle, err = m.dialog.window.NativeWindowHandle()
if err != nil {
w32.Fatal(err.Error())
}
}
var result []string
if m.dialog.allowsMultipleSelection {
temp, err := showCfdDialog(
func() (cfd.Dialog, error) {
return cfd.NewOpenMultipleFilesDialog(config)
}, true)
if err != nil {
return nil, err
}
result = temp.([]string)
} else {
temp, err := showCfdDialog(
func() (cfd.Dialog, error) {
return cfd.NewOpenFileDialog(config)
}, false)
if err != nil {
return nil, err
}
result = []string{temp.(string)}
}
files := make(chan string)
go func() {
for _, file := range result {
files <- file
}
close(files)
}()
return files, nil
}
type windowSaveFileDialog struct {
dialog *SaveFileDialogStruct
}
func newSaveFileDialogImpl(d *SaveFileDialogStruct) *windowSaveFileDialog {
return &windowSaveFileDialog{
dialog: d,
}
}
func (m *windowSaveFileDialog) show() (chan string, error) {
files := make(chan string)
defaultFolder, err := getDefaultFolder(m.dialog.directory)
if err != nil {
close(files)
return files, err
}
config := cfd.DialogConfig{
Title: m.dialog.title,
Role: "SaveFile",
FileFilters: convertFilters(m.dialog.filters),
FileName: m.dialog.filename,
Folder: defaultFolder,
}
// Original PR for v2 by @almas1992: https://github.com/wailsapp/wails/pull/3205
if len(options.Filters) > 0 {
config.DefaultExtension = strings.TrimPrefix(strings.Split(options.Filters[0].Pattern, ";")[0], "*")
}
result, err := showCfdDialog(
func() (cfd.Dialog, error) {
return cfd.NewSaveFileDialog(config)
}, false)
go func() {
files <- result.(string)
close(files)
}()
return files, err
}
func calculateMessageDialogFlags(options MessageDialogOptions) uint32 {
var flags uint32
switch options.DialogType {
case InfoDialogType:
flags = windows.MB_OK | windows.MB_ICONINFORMATION
case ErrorDialogType:
flags = windows.MB_ICONERROR | windows.MB_OK
case QuestionDialogType:
flags = windows.MB_YESNO
for _, button := range options.Buttons {
if strings.TrimSpace(strings.ToLower(button.Label)) == "no" && button.IsDefault {
flags |= windows.MB_DEFBUTTON2
}
}
case WarningDialogType:
flags = windows.MB_OK | windows.MB_ICONWARNING
}
return flags
}
func convertFilters(filters []FileFilter) []cfd.FileFilter {
var result []cfd.FileFilter
for _, filter := range filters {
result = append(result, cfd.FileFilter(filter))
}
return result
}
func showCfdDialog(newDlg func() (cfd.Dialog, error), isMultiSelect bool) (any, error) {
dlg, err := newDlg()
if err != nil {
return nil, err
}
defer func() {
err := dlg.Release()
if err != nil {
globalApplication.error("Unable to release dialog: " + err.Error())
}
}()
if multi, _ := dlg.(cfd.OpenMultipleFilesDialog); multi != nil && isMultiSelect {
return multi.ShowAndGetResults()
}
return dlg.ShowAndGetResult()
}