mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 05:08:54 -07:00
WIP: Support multiple value return
This commit is contained in:
@@ -18,7 +18,7 @@ type Renderer interface {
|
||||
|
||||
// Dialog Runtime
|
||||
SelectFile(title string, filter string) string
|
||||
SelectDirectory() string
|
||||
SelectDirectory() []string
|
||||
SelectSaveFile(title string, filter string) string
|
||||
|
||||
// Window Runtime
|
||||
|
||||
@@ -264,7 +264,7 @@ func (w *WebView) SelectFile(title string, filter string) string {
|
||||
}
|
||||
|
||||
// SelectDirectory opens a dialog that allows the user to select a directory
|
||||
func (w *WebView) SelectDirectory() string {
|
||||
func (w *WebView) SelectDirectory() []string {
|
||||
var result string
|
||||
// We need to run this on the main thread, however Dispatch is
|
||||
// non-blocking so we launch this in a goroutine and wait for
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package runtime
|
||||
|
||||
import "github.com/wailsapp/wails/lib/interfaces"
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/lib/interfaces"
|
||||
)
|
||||
|
||||
// Dialog exposes an interface to native dialogs
|
||||
type Dialog struct {
|
||||
@@ -29,7 +32,7 @@ func (r *Dialog) SelectFile(params ...string) string {
|
||||
}
|
||||
|
||||
// SelectDirectory prompts the user to select a directory
|
||||
func (r *Dialog) SelectDirectory() string {
|
||||
func (r *Dialog) SelectDirectory() []string {
|
||||
return r.renderer.SelectDirectory()
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ extern void UnFullscreen(void *app);
|
||||
extern void ToggleFullscreen(void *app);
|
||||
extern void DisableFrame(void *app);
|
||||
extern char *SaveFileDialog(void *appPointer, char *title, char *filter);
|
||||
extern char *OpenFileDialog(void *appPointer, char *title, char *filter);
|
||||
extern char *OpenDialog(void *appPointer, char *title, char *filter);
|
||||
extern char *OpenDirectoryDialog(void *appPointer, char *title, char *filter);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,9 @@ package ffenestri
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
|
||||
@@ -119,41 +122,66 @@ func (c *Client) WindowSetColour(colour int) {
|
||||
C.SetColour(c.app.app, r, g, b, a)
|
||||
}
|
||||
|
||||
// OpenFileDialog will open a file dialog with the given title
|
||||
func (c *Client) OpenFileDialog(title string, filter string) string {
|
||||
// // OpenFileDialog will open a file dialog with the given title
|
||||
// func (c *Client) OpenFileDialog(title string, filter string) []string {
|
||||
// var result []string
|
||||
|
||||
cstring := C.OpenFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
||||
var result string
|
||||
if cstring != nil {
|
||||
result = C.GoString(cstring)
|
||||
// Free the C string that was allocated by the dialog
|
||||
C.free(unsafe.Pointer(cstring))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SaveFileDialog will open a save file dialog with the given title
|
||||
func (c *Client) SaveFileDialog(title string, filter string) string {
|
||||
|
||||
cstring := C.SaveFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
||||
var result string
|
||||
if cstring != nil {
|
||||
result = C.GoString(cstring)
|
||||
// Free the C string that was allocated by the dialog
|
||||
C.free(unsafe.Pointer(cstring))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// OpenDirectoryDialog will open a directory dialog with the given title
|
||||
func (c *Client) OpenDirectoryDialog(title string, filter string) string {
|
||||
|
||||
cstring := C.OpenDirectoryDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
||||
var result string
|
||||
if cstring != nil {
|
||||
result = C.GoString(cstring)
|
||||
// Free the C string that was allocated by the dialog
|
||||
C.free(unsafe.Pointer(cstring))
|
||||
// cstring := C.OpenFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
||||
// if cstring == nil {
|
||||
// return result
|
||||
// }
|
||||
|
||||
// json := C.GoString(cstring)
|
||||
// // Free the C string that was allocated by the dialog
|
||||
// C.free(unsafe.Pointer(cstring))
|
||||
|
||||
// // Unmarshal the json
|
||||
// err := json.Unmarshal([]byte(json), &result)
|
||||
// if err != nil {
|
||||
// // ???
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
|
||||
// fmt.Printf("result = %+v\n", result)
|
||||
|
||||
// return result
|
||||
// }
|
||||
|
||||
// // SaveFileDialog will open a save file dialog with the given title
|
||||
// func (c *Client) SaveFileDialog(title string, filter string) string {
|
||||
|
||||
// cstring := C.SaveFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
||||
// var result string
|
||||
// if cstring != nil {
|
||||
// result = C.GoString(cstring)
|
||||
// // Free the C string that was allocated by the dialog
|
||||
// C.free(unsafe.Pointer(cstring))
|
||||
// }
|
||||
// return result
|
||||
// }
|
||||
|
||||
// OpenDialog will open a dialog with the given title and filter
|
||||
func (c *Client) OpenDialog(title string, filter string) []string {
|
||||
|
||||
var result []string
|
||||
|
||||
cstring := C.OpenDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
|
||||
if cstring == nil {
|
||||
return result
|
||||
}
|
||||
|
||||
jsondata := C.GoString(cstring)
|
||||
// Free the C string that was allocated by the dialog
|
||||
C.free(unsafe.Pointer(cstring))
|
||||
|
||||
// Unmarshal the json
|
||||
err := json.Unmarshal([]byte(jsondata), &result)
|
||||
if err != nil {
|
||||
// ???
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("result = %+v\n", result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
|
||||
#include <objc/objc-runtime.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include "json.h"
|
||||
|
||||
// Macros to make it slightly more sane
|
||||
#define msg objc_msgSend
|
||||
@@ -407,88 +408,30 @@ void SetPosition(struct Application *app, int x, int y) {
|
||||
|
||||
// OpenFileDialog opens a dialog to select a file
|
||||
// NOTE: The result is a string that will need to be freed!
|
||||
char* OpenFileDialog(void *appPointer, char *title) {
|
||||
char* OpenFileDialog(struct Application *app, char *title, char *filter) {
|
||||
Debug("OpenFileDialog Called");
|
||||
|
||||
// struct Application *app = (struct Application*) appPointer;
|
||||
// GtkFileChooserNative *native;
|
||||
// GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
// gint res;
|
||||
char *filename = "BogusFilename";
|
||||
|
||||
// native = gtk_file_chooser_native_new (title,
|
||||
// app->mainWindow,
|
||||
// action,
|
||||
// "_Open",
|
||||
// "_Cancel");
|
||||
|
||||
// res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
|
||||
// if (res == GTK_RESPONSE_ACCEPT)
|
||||
// {
|
||||
// GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
|
||||
// filename = gtk_file_chooser_get_filename (chooser);
|
||||
// }
|
||||
|
||||
// g_object_unref (native);
|
||||
|
||||
char *filename = concat("","BogusOpenFilename");
|
||||
return filename;
|
||||
}
|
||||
|
||||
// SaveFileDialog opens a dialog to select a file
|
||||
// NOTE: The result is a string that will need to be freed!
|
||||
char* SaveFileDialog(void *appPointer, char *title) {
|
||||
char* SaveFileDialog(void *appPointer, char *title, char *filter) {
|
||||
Debug("SaveFileDialog Called");
|
||||
char *filename = "BogusSaveFilename";
|
||||
/* struct Application *app = (struct Application*) appPointer;
|
||||
GtkFileChooserNative *native;
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
|
||||
gint res;
|
||||
|
||||
native = gtk_file_chooser_native_new (title,
|
||||
app->mainWindow,
|
||||
action,
|
||||
"_Save",
|
||||
"_Cancel");
|
||||
|
||||
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
|
||||
if (res == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
|
||||
filename = gtk_file_chooser_get_filename (chooser);
|
||||
}
|
||||
|
||||
g_object_unref (native);
|
||||
*/
|
||||
char *filename = concat("","BogusSaveFilename");
|
||||
return filename;
|
||||
}
|
||||
|
||||
// OpenDirectoryDialog opens a dialog to select a directory
|
||||
// OpenDialog opens a dialog to select files/directories
|
||||
// NOTE: The result is a string that will need to be freed!
|
||||
char* OpenDirectoryDialog(void *appPointer, char *title) {
|
||||
char* OpenDialog(void *appPointer, char *title, char *filter) {
|
||||
Debug("OpenDirectoryDialog Called");
|
||||
char *foldername = "BogusDirectory";
|
||||
/*
|
||||
struct Application *app = (struct Application*) appPointer;
|
||||
GtkFileChooserNative *native;
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
gint res;
|
||||
|
||||
native = gtk_file_chooser_native_new (title,
|
||||
app->mainWindow,
|
||||
action,
|
||||
"_Open",
|
||||
"_Cancel");
|
||||
|
||||
res = gtk_native_dialog_run (GTK_NATIVE_DIALOG (native));
|
||||
if (res == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GtkFileChooser *chooser = GTK_FILE_CHOOSER (native);
|
||||
foldername = gtk_file_chooser_get_filename (chooser);
|
||||
}
|
||||
|
||||
g_object_unref (native);
|
||||
*/
|
||||
return foldername;
|
||||
JsonNode *result = json_mkarray();
|
||||
json_append_element(result, json_mkstring("BogusDirectory 1"));
|
||||
json_append_element(result, json_mkstring("BogusDirectory 2"));
|
||||
char *encoded = json_stringify(result, "");
|
||||
json_delete(result);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
const char *invoke = "window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}};";
|
||||
|
||||
1383
v2/internal/ffenestri/json.c
Normal file
1383
v2/internal/ffenestri/json.c
Normal file
File diff suppressed because it is too large
Load Diff
119
v2/internal/ffenestri/json.h
Normal file
119
v2/internal/ffenestri/json.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Source: http://git.ozlabs.org/?p=ccan;a=tree;f=ccan/json;hb=HEAD
|
||||
*/
|
||||
|
||||
#ifndef CCAN_JSON_H
|
||||
#define CCAN_JSON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum {
|
||||
JSON_NULL,
|
||||
JSON_BOOL,
|
||||
JSON_STRING,
|
||||
JSON_NUMBER,
|
||||
JSON_ARRAY,
|
||||
JSON_OBJECT,
|
||||
} JsonTag;
|
||||
|
||||
typedef struct JsonNode JsonNode;
|
||||
|
||||
struct JsonNode
|
||||
{
|
||||
/* only if parent is an object or array (NULL otherwise) */
|
||||
JsonNode *parent;
|
||||
JsonNode *prev, *next;
|
||||
|
||||
/* only if parent is an object (NULL otherwise) */
|
||||
char *key; /* Must be valid UTF-8. */
|
||||
|
||||
JsonTag tag;
|
||||
union {
|
||||
/* JSON_BOOL */
|
||||
bool bool_;
|
||||
|
||||
/* JSON_STRING */
|
||||
char *string_; /* Must be valid UTF-8. */
|
||||
|
||||
/* JSON_NUMBER */
|
||||
double number_;
|
||||
|
||||
/* JSON_ARRAY */
|
||||
/* JSON_OBJECT */
|
||||
struct {
|
||||
JsonNode *head, *tail;
|
||||
} children;
|
||||
};
|
||||
};
|
||||
|
||||
/*** Encoding, decoding, and validation ***/
|
||||
|
||||
JsonNode *json_decode (const char *json);
|
||||
char *json_encode (const JsonNode *node);
|
||||
char *json_encode_string (const char *str);
|
||||
char *json_stringify (const JsonNode *node, const char *space);
|
||||
void json_delete (JsonNode *node);
|
||||
|
||||
bool json_validate (const char *json);
|
||||
|
||||
/*** Lookup and traversal ***/
|
||||
|
||||
JsonNode *json_find_element (JsonNode *array, int index);
|
||||
JsonNode *json_find_member (JsonNode *object, const char *key);
|
||||
|
||||
JsonNode *json_first_child (const JsonNode *node);
|
||||
|
||||
#define json_foreach(i, object_or_array) \
|
||||
for ((i) = json_first_child(object_or_array); \
|
||||
(i) != NULL; \
|
||||
(i) = (i)->next)
|
||||
|
||||
/*** Construction and manipulation ***/
|
||||
|
||||
JsonNode *json_mknull(void);
|
||||
JsonNode *json_mkbool(bool b);
|
||||
JsonNode *json_mkstring(const char *s);
|
||||
JsonNode *json_mknumber(double n);
|
||||
JsonNode *json_mkarray(void);
|
||||
JsonNode *json_mkobject(void);
|
||||
|
||||
void json_append_element(JsonNode *array, JsonNode *element);
|
||||
void json_prepend_element(JsonNode *array, JsonNode *element);
|
||||
void json_append_member(JsonNode *object, const char *key, JsonNode *value);
|
||||
void json_prepend_member(JsonNode *object, const char *key, JsonNode *value);
|
||||
|
||||
void json_remove_from_parent(JsonNode *node);
|
||||
|
||||
/*** Debugging ***/
|
||||
|
||||
/*
|
||||
* Look for structure and encoding problems in a JsonNode or its descendents.
|
||||
*
|
||||
* If a problem is detected, return false, writing a description of the problem
|
||||
* to errmsg (unless errmsg is NULL).
|
||||
*/
|
||||
bool json_check(const JsonNode *node, char errmsg[256]);
|
||||
|
||||
#endif
|
||||
@@ -13,9 +13,9 @@ type Client interface {
|
||||
Quit()
|
||||
NotifyEvent(message string)
|
||||
CallResult(message string)
|
||||
SaveFileDialog(title string, filter string) string
|
||||
OpenFileDialog(title string, filter string) string
|
||||
OpenDirectoryDialog(title string, filter string) string
|
||||
// SaveFileDialog(title string, filter string) []string
|
||||
OpenDialog(title string, filter string) []string
|
||||
// OpenDirectoryDialog(title string, filter string) string
|
||||
WindowSetTitle(title string)
|
||||
WindowShow()
|
||||
WindowHide()
|
||||
|
||||
@@ -343,9 +343,9 @@ 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
|
||||
var result string
|
||||
var result []string
|
||||
for _, client := range d.clients {
|
||||
result = client.frontend.OpenFileDialog(title, filter)
|
||||
result = client.frontend.OpenDialog(title, filter)
|
||||
}
|
||||
|
||||
// Send dummy response
|
||||
@@ -360,9 +360,9 @@ 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
|
||||
var result string
|
||||
var result []string
|
||||
for _, client := range d.clients {
|
||||
result = client.frontend.SaveFileDialog(title, filter)
|
||||
result = client.frontend.OpenDialog(title, filter)
|
||||
}
|
||||
|
||||
// Send dummy response
|
||||
@@ -377,9 +377,9 @@ 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
|
||||
var result string
|
||||
var result []string
|
||||
for _, client := range d.clients {
|
||||
result = client.frontend.OpenDirectoryDialog(title, filter)
|
||||
result = client.frontend.OpenDialog(title, filter)
|
||||
}
|
||||
// Send dummy response
|
||||
d.servicebus.Publish(responseTopic, result)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type Dialog interface {
|
||||
SaveFile(params ...string) string
|
||||
SelectFile(params ...string) string
|
||||
SelectDirectory(params ...string) string
|
||||
SelectDirectory(params ...string) []string
|
||||
}
|
||||
|
||||
// dialog exposes the Dialog interface
|
||||
@@ -108,7 +108,7 @@ func (r *dialog) SaveFile(params ...string) string {
|
||||
}
|
||||
|
||||
// SelectDirectory prompts the user to select a file
|
||||
func (r *dialog) SelectDirectory(params ...string) string {
|
||||
func (r *dialog) SelectDirectory(params ...string) []string {
|
||||
|
||||
// Extract title + filter
|
||||
title, filter := r.processTitleAndFilter(params...)
|
||||
@@ -136,5 +136,5 @@ func (r *dialog) SelectDirectory(params ...string) string {
|
||||
// Delete subscription to response topic
|
||||
r.bus.UnSubscribe(responseTopic)
|
||||
|
||||
return result.Data().(string)
|
||||
return result.Data().([]string)
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func (r *RuntimeTest) SaveFile(title string, filter string) string {
|
||||
}
|
||||
|
||||
// SelectDirectory will call the Runtime.Dialog.OpenDirectory method
|
||||
func (r *RuntimeTest) SelectDirectory(title string, filter string) string {
|
||||
func (r *RuntimeTest) SelectDirectory(title string, filter string) []string {
|
||||
return r.runtime.Dialog.SelectDirectory(title, filter)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user