5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-03 05:00:31 +08:00

[windows] Improve Dialog API. Major refactor.

This commit is contained in:
Lea Anthony 2021-06-20 13:48:30 +10:00
parent 102a8cc5a6
commit d521f80dcd
15 changed files with 419 additions and 179 deletions

View File

@ -35,8 +35,6 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/harry1453/go-common-file-dialog v1.0.0 h1:fzBAGhRTqWQyJw5xkm0PSsA+d3CBYBrfh+Nayb6U0nM=
github.com/harry1453/go-common-file-dialog v1.0.0/go.mod h1:3zwmbo7fy+uYGyaec74mu+Z9DPg0aEt10fSjjPwfyiY=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=

View File

@ -125,7 +125,7 @@ func (a *App) Run() error {
return err
}
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback)
runtimesubsystem, err := subsystem.NewRuntime(ctx, a.servicebus, a.logger, a.startupCallback, nil)
if err != nil {
return err
}

View File

@ -41,8 +41,6 @@ type Application struct {
// Logger
logger logger.CustomLogger
// Window handle (used by windows)
hwnd unsafe.Pointer
}
func (a *Application) saveMemoryReference(mem unsafe.Pointer) {

View File

@ -47,6 +47,7 @@ extern void AddContextMenu(struct Application*, char *contextMenuJSON);
extern void UpdateContextMenu(struct Application*, char *contextMenuJSON);
extern void WebviewIsTransparent(struct Application*);
extern void WindowBackgroundIsTranslucent(struct Application*);
extern void* GetWindowHandle(struct Application*);
#ifdef __cplusplus
}

View File

@ -1,3 +1,5 @@
// +build !windows
package ffenestri
/*
@ -15,7 +17,7 @@ import (
"github.com/wailsapp/wails/v2/internal/logger"
)
// Client is our implentation of messageDispatcher.Client
// Client is our implementation of messageDispatcher.Client
type Client struct {
app *Application
logger logger.CustomLogger
@ -124,8 +126,8 @@ func (c *Client) WindowSetColour(colour int) {
C.SetColour(c.app.app, r, g, b, a)
}
// OpenDialog will open a dialog with the given title and filter
func (c *Client) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
// OpenFileDialog will open a dialog with the given title and filter
func (c *Client) OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {
@ -148,8 +150,33 @@ func (c *Client) OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string)
)
}
// OpenMultipleDialog will open a dialog with the given title and filter
func (c *Client) OpenMultipleDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
// OpenDirectoryDialog will open a dialog with the given title and filter
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {
filters = append(filters, strings.Split(filter.Pattern, ",")...)
}
}
C.OpenDialog(c.app.app,
c.app.string2CString(callbackID),
c.app.string2CString(dialogOptions.Title),
c.app.string2CString(strings.Join(filters, ";")),
c.app.string2CString(dialogOptions.DefaultFilename),
c.app.string2CString(dialogOptions.DefaultDirectory),
c.app.bool2Cint(false), // Files
c.app.bool2Cint(true), // Directories
c.app.bool2Cint(false), // Multiple
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
c.app.bool2Cint(dialogOptions.ResolvesAliases),
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
)
}
// OpenMultipleFilesDialog will open a dialog with the given title and filter
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {

View File

@ -0,0 +1,301 @@
// +build windows
package ffenestri
/*
#include "ffenestri.h"
*/
import "C"
import (
"encoding/json"
"github.com/harry1453/go-common-file-dialog/cfd"
"log"
"runtime"
"strconv"
"strings"
"github.com/wailsapp/wails/v2/pkg/options/dialog"
"github.com/wailsapp/wails/v2/internal/logger"
)
// Client is our implementation of messageDispatcher.Client
type Client struct {
app *Application
logger logger.CustomLogger
}
func newClient(app *Application) *Client {
return &Client{
app: app,
logger: app.logger,
}
}
// Quit the application
func (c *Client) Quit() {
c.app.logger.Trace("Got shutdown message")
C.Quit(c.app.app)
}
// NotifyEvent will pass on the event message to the frontend
func (c *Client) NotifyEvent(message string) {
eventMessage := `window.wails._.Notify(` + strconv.Quote(message) + `);`
c.app.logger.Trace("eventMessage = %+v", eventMessage)
C.ExecJS(c.app.app, c.app.string2CString(eventMessage))
}
// CallResult contains the result of the call from JS
func (c *Client) CallResult(message string) {
callbackMessage := `window.wails._.Callback(` + strconv.Quote(message) + `);`
c.app.logger.Trace("callbackMessage = %+v", callbackMessage)
C.ExecJS(c.app.app, c.app.string2CString(callbackMessage))
}
// WindowSetTitle sets the window title to the given string
func (c *Client) WindowSetTitle(title string) {
C.SetTitle(c.app.app, c.app.string2CString(title))
}
// WindowFullscreen will set the window to be fullscreen
func (c *Client) WindowFullscreen() {
C.Fullscreen(c.app.app)
}
// WindowUnFullscreen will unfullscreen the window
func (c *Client) WindowUnFullscreen() {
C.UnFullscreen(c.app.app)
}
// WindowShow will show the window
func (c *Client) WindowShow() {
C.Show(c.app.app)
}
// WindowHide will hide the window
func (c *Client) WindowHide() {
C.Hide(c.app.app)
}
// WindowCenter will hide the window
func (c *Client) WindowCenter() {
C.Center(c.app.app)
}
// WindowMaximise will maximise the window
func (c *Client) WindowMaximise() {
C.Maximise(c.app.app)
}
// WindowMinimise will minimise the window
func (c *Client) WindowMinimise() {
C.Minimise(c.app.app)
}
// WindowUnmaximise will unmaximise the window
func (c *Client) WindowUnmaximise() {
C.Unmaximise(c.app.app)
}
// WindowUnminimise will unminimise the window
func (c *Client) WindowUnminimise() {
C.Unminimise(c.app.app)
}
// WindowPosition will position the window to x,y on the
// monitor that the window is mostly on
func (c *Client) WindowPosition(x int, y int) {
C.SetPosition(c.app.app, C.int(x), C.int(y))
}
// WindowSize will resize the window to the given
// width and height
func (c *Client) WindowSize(width int, height int) {
C.SetSize(c.app.app, C.int(width), C.int(height))
}
func (c *Client) WindowSetMinSize(width int, height int) {
C.SetMinWindowSize(c.app.app, C.int(width), C.int(height))
}
func (c *Client) WindowSetMaxSize(width int, height int) {
C.SetMaxWindowSize(c.app.app, C.int(width), C.int(height))
}
// WindowSetColour sets the window colour
func (c *Client) WindowSetColour(colour int) {
r, g, b, a := intToColour(colour)
C.SetColour(c.app.app, r, g, b, a)
}
func convertFilters(filters []dialog.FileFilter) []cfd.FileFilter {
var result []cfd.FileFilter
for _, filter := range filters {
result = append(result, cfd.FileFilter(filter))
}
return result
}
// OpenFileDialog will open a dialog with the given title and filter
func (c *Client) OpenFileDialog(options *dialog.OpenDialog, callbackID string) {
config := cfd.DialogConfig{
Folder: options.DefaultDirectory,
FileFilters: convertFilters(options.Filters),
FileName: options.DefaultFilename,
}
thisdialog, err := cfd.NewOpenFileDialog(config)
if err != nil {
log.Fatal(err)
}
thisdialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
defer func(thisdialog cfd.OpenFileDialog) {
err := thisdialog.Release()
if err != nil {
log.Fatal(err)
}
}(thisdialog)
result, err := thisdialog.ShowAndGetResult()
if err != nil {
log.Fatal(err)
}
resultJSON, err := json.Marshal([]string{result})
if err != nil {
log.Fatal(err)
}
dispatcher.DispatchMessage("DO" + callbackID + "|" + string(resultJSON))
}
// OpenDirectoryDialog will open a dialog with the given title and filter
func (c *Client) OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
config := cfd.DialogConfig{
Title: dialogOptions.Title,
Role: "PickFolder",
Folder: dialogOptions.DefaultDirectory,
}
thisDialog, err := cfd.NewSelectFolderDialog(config)
if err != nil {
log.Fatal()
}
thisDialog.SetParentWindowHandle(uintptr(C.GetWindowHandle(c.app.app)))
defer func(thisDialog cfd.SelectFolderDialog) {
err := thisDialog.Release()
if err != nil {
log.Fatal(err)
}
}(thisDialog)
result, err := thisDialog.ShowAndGetResult()
resultJSON, err := json.Marshal(result)
if err != nil {
log.Fatal(err)
}
dispatcher.DispatchMessage("DD" + callbackID + "|" + string(resultJSON))
}
// OpenMultipleFilesDialog will open a dialog with the given title and filter
func (c *Client) OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string) {
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 {
log.Fatal(err)
}
handle := uintptr(C.GetWindowHandle(c.app.app))
thisdialog.SetParentWindowHandle(handle)
defer func(thisdialog cfd.OpenMultipleFilesDialog) {
err := thisdialog.Release()
if err != nil {
log.Fatal(err)
}
}(thisdialog)
result, err := thisdialog.ShowAndGetResults()
if err != nil {
log.Fatal(err)
}
resultJSON, err := json.Marshal(result)
if err != nil {
log.Fatal(err)
}
dispatcher.DispatchMessage("D*" + callbackID + "|" + string(resultJSON))
}
// SaveDialog will open a dialog with the given title and filter
func (c *Client) SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string) {
filters := []string{}
if runtime.GOOS == "darwin" {
for _, filter := range dialogOptions.Filters {
filters = append(filters, strings.Split(filter.Pattern, ",")...)
}
}
C.SaveDialog(c.app.app,
c.app.string2CString(callbackID),
c.app.string2CString(dialogOptions.Title),
c.app.string2CString(strings.Join(filters, ";")),
c.app.string2CString(dialogOptions.DefaultFilename),
c.app.string2CString(dialogOptions.DefaultDirectory),
c.app.bool2Cint(dialogOptions.ShowHiddenFiles),
c.app.bool2Cint(dialogOptions.CanCreateDirectories),
c.app.bool2Cint(dialogOptions.TreatPackagesAsDirectories),
)
}
// MessageDialog will open a message dialog with the given options
func (c *Client) MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string) {
// Sanity check button length
if len(dialogOptions.Buttons) > 4 {
c.app.logger.Error("Given %d message dialog buttons. Maximum is 4", len(dialogOptions.Buttons))
return
}
// Process buttons
buttons := []string{"", "", "", ""}
for i, button := range dialogOptions.Buttons {
buttons[i] = button
}
C.MessageDialog(c.app.app,
c.app.string2CString(callbackID),
c.app.string2CString(string(dialogOptions.Type)),
c.app.string2CString(dialogOptions.Title),
c.app.string2CString(dialogOptions.Message),
c.app.string2CString(dialogOptions.Icon),
c.app.string2CString(buttons[0]),
c.app.string2CString(buttons[1]),
c.app.string2CString(buttons[2]),
c.app.string2CString(buttons[3]),
c.app.string2CString(dialogOptions.DefaultButton),
c.app.string2CString(dialogOptions.CancelButton))
}
func (c *Client) DarkModeEnabled(callbackID string) {
C.DarkModeEnabled(c.app.app, c.app.string2CString(callbackID))
}
func (c *Client) SetApplicationMenu(applicationMenuJSON string) {
C.SetApplicationMenu(c.app.app, c.app.string2CString(applicationMenuJSON))
}
func (c *Client) SetTrayMenu(trayMenuJSON string) {
C.SetTrayMenu(c.app.app, c.app.string2CString(trayMenuJSON))
}
func (c *Client) UpdateTrayMenuLabel(JSON string) {
C.UpdateTrayMenuLabel(c.app.app, c.app.string2CString(JSON))
}
func (c *Client) UpdateContextMenu(contextMenuJSON string) {
C.UpdateContextMenu(c.app.app, c.app.string2CString(contextMenuJSON))
}
func (c *Client) DeleteTrayMenuByID(id string) {
C.DeleteTrayMenuByID(c.app.app, c.app.string2CString(id))
}

View File

@ -88,6 +88,10 @@ struct Application *NewApplication(const char *title, int width, int height, int
return result;
}
void* GetWindowHandle(struct Application *app) {
return (void*)app->window;
}
void SetMinWindowSize(struct Application* app, int minWidth, int minHeight) {
app->minWidth = (LONG)minWidth;
app->minHeight = (LONG)minHeight;

View File

@ -72,6 +72,7 @@ void completed(struct Application* app);
extern "C" {
void DisableWindowIcon(struct Application* app);
void messageFromWindowCallback(const char *);
void* GetWindowHandle(struct Application*);
}
#endif

View File

@ -14,7 +14,9 @@ type Client interface {
Quit()
NotifyEvent(message string)
CallResult(message string)
OpenDialog(dialogOptions *dialog.OpenDialog, callbackID string)
OpenFileDialog(dialogOptions *dialog.OpenDialog, callbackID string)
OpenMultipleFilesDialog(dialogOptions *dialog.OpenDialog, callbackID string)
OpenDirectoryDialog(dialogOptions *dialog.OpenDialog, callbackID string)
SaveDialog(dialogOptions *dialog.SaveDialog, callbackID string)
MessageDialog(dialogOptions *dialog.MessageDialog, callbackID string)
WindowSetTitle(title string)

View File

@ -32,13 +32,29 @@ func dialogMessageParser(message string) (*parsedMessage, error) {
switch dialogType {
case 'O':
var data []string
var data string
topic = "dialog:openselected:" + callbackID
err := json.Unmarshal([]byte(payloadData), &data)
if err != nil {
return nil, err
}
responseMessage = &parsedMessage{Topic: topic, Data: data}
case 'D':
var data string
topic = "dialog:opendirectoryselected:" + callbackID
err := json.Unmarshal([]byte(payloadData), &data)
if err != nil {
return nil, err
}
responseMessage = &parsedMessage{Topic: topic, Data: data}
case '*':
var data []string
topic = "dialog:openmultipleselected:" + callbackID
err := json.Unmarshal([]byte(payloadData), &data)
if err != nil {
return nil, err
}
responseMessage = &parsedMessage{Topic: topic, Data: data}
case 'S':
topic = "dialog:saveselected:" + callbackID
responseMessage = &parsedMessage{Topic: topic, Data: payloadData}

View File

@ -422,7 +422,35 @@ func (d *Dispatcher) processDialogMessage(result *servicebus.Message) {
// TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one
for _, client := range d.clients {
client.frontend.OpenDialog(dialogOptions, callbackID)
client.frontend.OpenFileDialog(dialogOptions, callbackID)
}
case "openmultiple":
dialogOptions, ok := result.Data().(*dialog.OpenDialog)
if !ok {
d.logger.Error("Invalid data for 'dialog:select:openmultiple' : %#v", result.Data())
return
}
// This is hardcoded in the sender too
callbackID := splitTopic[3]
// TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one
for _, client := range d.clients {
client.frontend.OpenMultipleFilesDialog(dialogOptions, callbackID)
}
case "directory":
dialogOptions, ok := result.Data().(*dialog.OpenDialog)
if !ok {
d.logger.Error("Invalid data for 'dialog:select:directory' : %#v", result.Data())
return
}
// This is hardcoded in the sender too
callbackID := splitTopic[3]
// TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one
for _, client := range d.clients {
client.frontend.OpenDirectoryDialog(dialogOptions, callbackID)
}
case "save":
dialogOptions, ok := result.Data().(*dialog.SaveDialog)

View File

@ -1,5 +1,3 @@
// +build !windows
package runtime
import (
@ -31,6 +29,7 @@ func newDialog(bus *servicebus.ServiceBus) Dialog {
}
}
// processTitleAndFilter return the title and filter from the given params.
// title is the first string, filter is the second
func (r *dialog) processTitleAndFilter(params ...string) (string, string) {
@ -48,7 +47,8 @@ func (r *dialog) processTitleAndFilter(params ...string) (string, string) {
return title, filter
}
func OpenDirectory(dialogOptions *dialogoptions.OpenDialog) (string, error) {
// OpenDirectory prompts the user to select a directory
func (r *dialog) OpenDirectory(dialogOptions *dialogoptions.OpenDialog) (string, error) {
// Create unique dialog callback
uniqueCallback := crypto.RandomID()
@ -57,14 +57,14 @@ func OpenDirectory(dialogOptions *dialogoptions.OpenDialog) (string, error) {
responseTopic := "dialog:opendirectoryselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
return nil, fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:selectdirectory:open:" + uniqueCallback
message := "dialog:select:directory:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
@ -72,7 +72,7 @@ func OpenDirectory(dialogOptions *dialogoptions.OpenDialog) (string, error) {
return result.Data().(string), nil
}
// Open prompts the user to select a file
// OpenFile prompts the user to select a file
func (r *dialog) OpenFile(dialogOptions *dialogoptions.OpenDialog) (string, error) {
// Create unique dialog callback
@ -82,22 +82,28 @@ func (r *dialog) OpenFile(dialogOptions *dialogoptions.OpenDialog) (string, erro
responseTopic := "dialog:openselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
return nil, fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:open:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().(string), nil
files := result.Data().([]string)
res := ""
if len(files) > 0 {
res = files[0]
}
return res, nil
}
// OpenMultiple prompts the user to select a file
// OpenMultipleFiles prompts the user to select a file
func (r *dialog) OpenMultipleFiles(dialogOptions *dialogoptions.OpenDialog) ([]string, error) {
// Create unique dialog callback
@ -107,22 +113,22 @@ func (r *dialog) OpenMultipleFiles(dialogOptions *dialogoptions.OpenDialog) ([]s
responseTopic := "dialog:openmultipleselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
return nil, fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return nil, fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:openmultiple:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().(string), nil
return result.Data().([]string), nil
}
// Save prompts the user to select a file
// SaveFile prompts the user to select a file
func (r *dialog) SaveFile(dialogOptions *dialogoptions.SaveDialog) (string, error) {
// Create unique dialog callback
@ -132,14 +138,14 @@ func (r *dialog) SaveFile(dialogOptions *dialogoptions.SaveDialog) (string, erro
responseTopic := "dialog:saveselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
return nil, fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:save:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
@ -148,7 +154,7 @@ func (r *dialog) SaveFile(dialogOptions *dialogoptions.SaveDialog) (string, erro
}
// Message show a message to the user
func (r *dialog) Message(dialogOptions *dialogoptions.MessageDialog) string {
func (r *dialog) Message(dialogOptions *dialogoptions.MessageDialog) (string, error) {
// Create unique dialog callback
uniqueCallback := crypto.RandomID()
@ -157,17 +163,17 @@ func (r *dialog) Message(dialogOptions *dialogoptions.MessageDialog) string {
responseTopic := "dialog:messageselected:" + uniqueCallback
dialogResponseChannel, err := r.bus.Subscribe(responseTopic)
if err != nil {
fmt.Printf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
return "", fmt.Errorf("ERROR: Cannot subscribe to bus topic: %+v\n", err.Error())
}
message := "dialog:select:message:" + uniqueCallback
r.bus.Publish(message, dialogOptions)
// Wait for result
var result *servicebus.Message = <-dialogResponseChannel
var result = <-dialogResponseChannel
// Delete subscription to response topic
r.bus.UnSubscribe(responseTopic)
return result.Data().(string)
return result.Data().(string), nil
}

View File

@ -1,141 +0,0 @@
// +build windows
package runtime
import (
"golang.org/x/sys/windows"
"syscall"
"github.com/harry1453/go-common-file-dialog/cfd"
"github.com/harry1453/go-common-file-dialog/cfdutil"
"github.com/wailsapp/wails/v2/internal/servicebus"
dialogoptions "github.com/wailsapp/wails/v2/pkg/options/dialog"
)
// Dialog defines all Dialog related operations
type Dialog interface {
OpenFile(dialogOptions *dialogoptions.OpenDialog) (string, error)
OpenMultipleFiles(dialogOptions *dialogoptions.OpenDialog) ([]string, error)
OpenDirectory(dialogOptions *dialogoptions.OpenDialog) (string, error)
Save(dialogOptions *dialogoptions.SaveDialog) (string, error)
Message(dialogOptions *dialogoptions.MessageDialog) (string, error)
}
// dialog exposes the Dialog interface
type dialog struct {
bus *servicebus.ServiceBus
}
// newDialogs creates a new Dialogs struct
func newDialog(bus *servicebus.ServiceBus) Dialog {
return &dialog{
bus: bus,
}
}
// processTitleAndFilter return the title and filter from the given params.
// title is the first string, filter is the second
func (r *dialog) 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
}
func convertFilters(filters []dialogoptions.FileFilter) []cfd.FileFilter {
var result []cfd.FileFilter
for _, filter := range filters {
result = append(result, cfd.FileFilter(filter))
}
return result
}
func pickMultipleFiles(options *dialogoptions.OpenDialog) ([]string, error) {
results, err := cfdutil.ShowOpenMultipleFilesDialog(cfd.DialogConfig{
Title: options.Title,
Role: "OpenMultipleFiles",
FileFilters: convertFilters(options.Filters),
FileName: options.DefaultFilename,
Folder: options.DefaultDirectory,
})
return results, err
}
func (r *dialog) OpenMultipleFiles(options *dialogoptions.OpenDialog) ([]string, error) {
return pickMultipleFiles(options)
}
func (r *dialog) OpenDirectory(options *dialogoptions.OpenDialog) (string, error) {
return cfdutil.ShowPickFolderDialog(cfd.DialogConfig{
Title: options.Title,
Role: "PickFolder",
Folder: options.DefaultDirectory,
})
}
func (r *dialog) OpenFile(options *dialogoptions.OpenDialog) (string, error) {
result, err := cfdutil.ShowOpenFileDialog(cfd.DialogConfig{
Folder: options.DefaultDirectory,
FileFilters: convertFilters(options.Filters),
FileName: options.DefaultFilename,
})
return result, err
}
// Save prompts the user to select a file
func (r *dialog) Save(options *dialogoptions.SaveDialog) (string, error) {
result, err := cfdutil.ShowSaveFileDialog(cfd.DialogConfig{
Title: options.Title,
Role: "SaveFile",
FileName: options.DefaultFilename,
FileFilters: convertFilters(options.Filters),
})
return result, err
}
// Message show a message to the user
func (r *dialog) Message(options *dialogoptions.MessageDialog) (string, error) {
// TODO: error handling
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 dialogoptions.InfoDialog:
flags = windows.MB_OK | windows.MB_ICONINFORMATION
case dialogoptions.ErrorDialog:
flags = windows.MB_ICONERROR | windows.MB_OK
case dialogoptions.QuestionDialog:
flags = windows.MB_YESNO
case dialogoptions.WarningDialog:
flags = windows.MB_OK | windows.MB_ICONWARNING
}
result, _ := windows.MessageBox(0, message, title, flags|windows.MB_SYSTEMMODAL)
if options.Type == dialogoptions.QuestionDialog {
if result == 6 { // IDYES
return "Yes", nil
}
if result == 7 { // IDNO
return "No", nil
}
}
return "", nil
}

View File

@ -151,7 +151,7 @@ func (c *Call) processSystemCall(payload *message.CallMessage, clientID string)
if err != nil {
c.logger.Error("Error decoding: %s", err)
}
result, err := c.runtime.Dialog.Save(dialogOptions)
result, err := c.runtime.Dialog.SaveFile(dialogOptions)
if err != nil {
c.logger.Error("Error: %s", err)
}

View File

@ -3,12 +3,11 @@ package subsystem
import (
"context"
"fmt"
"strings"
"sync"
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/runtime"
"github.com/wailsapp/wails/v2/internal/servicebus"
"strings"
"sync"
)
// Runtime is the Runtime subsystem. It handles messages with topics starting