WIP: Support multiple value return

This commit is contained in:
Lea Anthony
2020-09-25 07:09:55 +10:00
parent 69c4e6ea28
commit bed5619d4e
12 changed files with 1599 additions and 123 deletions

View File

@@ -18,7 +18,7 @@ type Renderer interface {
// Dialog Runtime // Dialog Runtime
SelectFile(title string, filter string) string SelectFile(title string, filter string) string
SelectDirectory() string SelectDirectory() []string
SelectSaveFile(title string, filter string) string SelectSaveFile(title string, filter string) string
// Window Runtime // Window Runtime

View File

@@ -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 // 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 var result string
// We need to run this on the main thread, however Dispatch is // We need to run this on the main thread, however Dispatch is
// non-blocking so we launch this in a goroutine and wait for // non-blocking so we launch this in a goroutine and wait for

View File

@@ -1,7 +1,10 @@
package runtime package runtime
import "github.com/wailsapp/wails/lib/interfaces" import (
import "strings" "strings"
"github.com/wailsapp/wails/lib/interfaces"
)
// Dialog exposes an interface to native dialogs // Dialog exposes an interface to native dialogs
type Dialog struct { type Dialog struct {
@@ -29,7 +32,7 @@ func (r *Dialog) SelectFile(params ...string) string {
} }
// SelectDirectory prompts the user to select a directory // SelectDirectory prompts the user to select a directory
func (r *Dialog) SelectDirectory() string { func (r *Dialog) SelectDirectory() []string {
return r.renderer.SelectDirectory() return r.renderer.SelectDirectory()
} }

View File

@@ -30,7 +30,7 @@ extern void UnFullscreen(void *app);
extern void ToggleFullscreen(void *app); extern void ToggleFullscreen(void *app);
extern void DisableFrame(void *app); extern void DisableFrame(void *app);
extern char *SaveFileDialog(void *appPointer, char *title, char *filter); 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); extern char *OpenDirectoryDialog(void *appPointer, char *title, char *filter);
#endif #endif

View File

@@ -12,6 +12,9 @@ package ffenestri
import "C" import "C"
import ( import (
"encoding/json"
"fmt"
"log"
"strconv" "strconv"
"unsafe" "unsafe"
@@ -119,41 +122,66 @@ func (c *Client) WindowSetColour(colour int) {
C.SetColour(c.app.app, r, g, b, a) C.SetColour(c.app.app, r, g, b, a)
} }
// OpenFileDialog will open a file dialog with the given title // // OpenFileDialog will open a file dialog with the given title
func (c *Client) OpenFileDialog(title string, filter string) string { // 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)) // cstring := C.OpenFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
var result string // if cstring == nil {
if cstring != nil { // return result
result = C.GoString(cstring) // }
// Free the C string that was allocated by the dialog
C.free(unsafe.Pointer(cstring)) // json := C.GoString(cstring)
} // // Free the C string that was allocated by the dialog
return result // C.free(unsafe.Pointer(cstring))
}
// // Unmarshal the json
// SaveFileDialog will open a save file dialog with the given title // err := json.Unmarshal([]byte(json), &result)
func (c *Client) SaveFileDialog(title string, filter string) string { // if err != nil {
// // ???
cstring := C.SaveFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter)) // log.Fatal(err)
var result string // }
if cstring != nil {
result = C.GoString(cstring) // fmt.Printf("result = %+v\n", result)
// Free the C string that was allocated by the dialog
C.free(unsafe.Pointer(cstring)) // return result
} // }
return result
} // // SaveFileDialog will open a save file dialog with the given title
// func (c *Client) SaveFileDialog(title string, filter string) string {
// OpenDirectoryDialog will open a directory dialog with the given title
func (c *Client) OpenDirectoryDialog(title string, filter string) string { // cstring := C.SaveFileDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter))
// var result string
cstring := C.OpenDirectoryDialog(c.app.app, c.app.string2CString(title), c.app.string2CString(filter)) // if cstring != nil {
var result string // result = C.GoString(cstring)
if cstring != nil { // // Free the C string that was allocated by the dialog
result = C.GoString(cstring) // C.free(unsafe.Pointer(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 return result
} }

View File

@@ -4,6 +4,7 @@
#define OBJC_OLD_DISPATCH_PROTOTYPES 1 #define OBJC_OLD_DISPATCH_PROTOTYPES 1
#include <objc/objc-runtime.h> #include <objc/objc-runtime.h>
#include <CoreGraphics/CoreGraphics.h> #include <CoreGraphics/CoreGraphics.h>
#include "json.h"
// Macros to make it slightly more sane // Macros to make it slightly more sane
#define msg objc_msgSend #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 // OpenFileDialog opens a dialog to select a file
// NOTE: The result is a string that will need to be freed! // 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"); Debug("OpenFileDialog Called");
char *filename = concat("","BogusOpenFilename");
// 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);
return filename; return filename;
} }
// SaveFileDialog opens a dialog to select a file // SaveFileDialog opens a dialog to select a file
// NOTE: The result is a string that will need to be freed! // 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"); Debug("SaveFileDialog Called");
char *filename = "BogusSaveFilename"; char *filename = concat("","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);
*/
return filename; 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! // 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"); Debug("OpenDirectoryDialog Called");
char *foldername = "BogusDirectory"; JsonNode *result = json_mkarray();
/* json_append_element(result, json_mkstring("BogusDirectory 1"));
struct Application *app = (struct Application*) appPointer; json_append_element(result, json_mkstring("BogusDirectory 2"));
GtkFileChooserNative *native; char *encoded = json_stringify(result, "");
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; json_delete(result);
gint res; return encoded;
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;
} }
const char *invoke = "window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}};"; const char *invoke = "window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}};";

1383
v2/internal/ffenestri/json.c Normal file

File diff suppressed because it is too large Load Diff

View 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

View File

@@ -13,9 +13,9 @@ type Client interface {
Quit() Quit()
NotifyEvent(message string) NotifyEvent(message string)
CallResult(message string) CallResult(message string)
SaveFileDialog(title string, filter string) string // SaveFileDialog(title string, filter string) []string
OpenFileDialog(title string, filter string) string OpenDialog(title string, filter string) []string
OpenDirectoryDialog(title string, filter string) string // OpenDirectoryDialog(title string, filter string) string
WindowSetTitle(title string) WindowSetTitle(title string)
WindowShow() WindowShow()
WindowHide() WindowHide()

View File

@@ -343,9 +343,9 @@ func (d *Dispatcher) processDialogMessage(result *servicebus.Message) {
// TODO: Work out what we mean in a multi window environment... // TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one // For now we will just pick the first one
var result string var result []string
for _, client := range d.clients { for _, client := range d.clients {
result = client.frontend.OpenFileDialog(title, filter) result = client.frontend.OpenDialog(title, filter)
} }
// Send dummy response // 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... // TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one // For now we will just pick the first one
var result string var result []string
for _, client := range d.clients { for _, client := range d.clients {
result = client.frontend.SaveFileDialog(title, filter) result = client.frontend.OpenDialog(title, filter)
} }
// Send dummy response // 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... // TODO: Work out what we mean in a multi window environment...
// For now we will just pick the first one // For now we will just pick the first one
var result string var result []string
for _, client := range d.clients { for _, client := range d.clients {
result = client.frontend.OpenDirectoryDialog(title, filter) result = client.frontend.OpenDialog(title, filter)
} }
// Send dummy response // Send dummy response
d.servicebus.Publish(responseTopic, result) d.servicebus.Publish(responseTopic, result)

View File

@@ -11,7 +11,7 @@ import (
type Dialog interface { type Dialog interface {
SaveFile(params ...string) string SaveFile(params ...string) string
SelectFile(params ...string) string SelectFile(params ...string) string
SelectDirectory(params ...string) string SelectDirectory(params ...string) []string
} }
// dialog exposes the Dialog interface // dialog exposes the Dialog interface
@@ -108,7 +108,7 @@ func (r *dialog) SaveFile(params ...string) string {
} }
// SelectDirectory prompts the user to select a file // 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 // Extract title + filter
title, filter := r.processTitleAndFilter(params...) title, filter := r.processTitleAndFilter(params...)
@@ -136,5 +136,5 @@ func (r *dialog) SelectDirectory(params ...string) string {
// Delete subscription to response topic // Delete subscription to response topic
r.bus.UnSubscribe(responseTopic) r.bus.UnSubscribe(responseTopic)
return result.Data().(string) return result.Data().([]string)
} }

View File

@@ -77,7 +77,7 @@ func (r *RuntimeTest) SaveFile(title string, filter string) string {
} }
// SelectDirectory will call the Runtime.Dialog.OpenDirectory method // 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) return r.runtime.Dialog.SelectDirectory(title, filter)
} }