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:
parent
102a8cc5a6
commit
d521f80dcd
@ -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=
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
301
v2/internal/ffenestri/ffenestri_client_windows.go
Normal file
301
v2/internal/ffenestri/ffenestri_client_windows.go
Normal 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))
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user