mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 22:13:36 +08:00
Support OpenFile /
OpenMultipleFiles
This commit is contained in:
parent
6e30c6770b
commit
6c68e59113
@ -5,19 +5,36 @@ package linux
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "gtk/gtk.h"
|
||||||
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var openFileResults = make(chan string)
|
const (
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN C.GtkFileChooserAction = C.GTK_FILE_CHOOSER_ACTION_OPEN
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SAVE C.GtkFileChooserAction = C.GTK_FILE_CHOOSER_ACTION_SAVE
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER C.GtkFileChooserAction = C.GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
|
||||||
|
)
|
||||||
|
|
||||||
|
var openFileResults = make(chan []string)
|
||||||
|
|
||||||
func (f *Frontend) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (result string, err error) {
|
func (f *Frontend) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) (result string, err error) {
|
||||||
f.mainWindow.OpenFileDialog(dialogOptions)
|
f.mainWindow.OpenFileDialog(dialogOptions, 0, GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||||
result = <-openFileResults
|
results := <-openFileResults
|
||||||
return
|
if len(results) == 1 {
|
||||||
|
return results[0], nil
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) {
|
func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) {
|
||||||
panic("implement me")
|
f.mainWindow.OpenFileDialog(dialogOptions, 1, GTK_FILE_CHOOSER_ACTION_OPEN)
|
||||||
|
result := <-openFileResults
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Frontend) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) {
|
func (f *Frontend) OpenDirectoryDialog(dialogOptions frontend.OpenDialogOptions) (string, error) {
|
||||||
@ -33,6 +50,15 @@ func (f *Frontend) MessageDialog(dialogOptions frontend.MessageDialogOptions) (s
|
|||||||
}
|
}
|
||||||
|
|
||||||
//export processOpenFileResult
|
//export processOpenFileResult
|
||||||
func processOpenFileResult(result *C.char) {
|
func processOpenFileResult(carray **C.char) {
|
||||||
openFileResults <- C.GoString(result)
|
// Create a Go slice from the C array
|
||||||
|
var result []string
|
||||||
|
goArray := (*[1024]*C.char)(unsafe.Pointer(carray))[:1024:1024]
|
||||||
|
for _, s := range goArray {
|
||||||
|
if s == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result = append(result, C.GoString(s))
|
||||||
|
}
|
||||||
|
openFileResults <- result
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ void connectButtons(void* webview) {
|
|||||||
g_signal_connect(WEBKIT_WEB_VIEW(webview), "button-release-event", G_CALLBACK(buttonRelease), NULL);
|
g_signal_connect(WEBKIT_WEB_VIEW(webview), "button-release-event", G_CALLBACK(buttonRelease), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void processURLRequest(WebKitURISchemeRequest *request);
|
extern void processURLRequest(void *request);
|
||||||
|
|
||||||
// This is called when the close button on the window is pressed
|
// This is called when the close button on the window is pressed
|
||||||
gboolean close_button_pressed(GtkWidget *widget, GdkEvent *event, void* data)
|
gboolean close_button_pressed(GtkWidget *widget, GdkEvent *event, void* data)
|
||||||
@ -200,42 +200,121 @@ void ExecuteOnMainThread(void* f, gpointer jscallback) {
|
|||||||
g_idle_add((GSourceFunc)f, (gpointer)jscallback);
|
g_idle_add((GSourceFunc)f, (gpointer)jscallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void extern processOpenFileResult(char*);
|
void extern processOpenFileResult(void*);
|
||||||
|
|
||||||
|
|
||||||
typedef struct OpenFileDialogOptions {
|
typedef struct OpenFileDialogOptions {
|
||||||
void* webview;
|
void* webview;
|
||||||
char* title;
|
char* title;
|
||||||
char** filters;
|
char* defaultFilename;
|
||||||
|
int createDirectories;
|
||||||
|
int multipleFiles;
|
||||||
|
int showHiddenFiles;
|
||||||
|
GtkFileChooserAction action;
|
||||||
|
GtkFileFilter** filters;
|
||||||
} OpenFileDialogOptions;
|
} OpenFileDialogOptions;
|
||||||
|
|
||||||
|
GtkFileFilter** allocFileFilterArray(size_t ln) {
|
||||||
|
return (GtkFileFilter**) malloc(ln * sizeof(GtkFileFilter*));
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeFileFilterArray(GtkFileFilter** filters) {
|
||||||
|
free(filters);
|
||||||
|
}
|
||||||
|
|
||||||
int opendialog(gpointer data) {
|
int opendialog(gpointer data) {
|
||||||
struct OpenFileDialogOptions *options = data;
|
struct OpenFileDialogOptions *options = data;
|
||||||
GtkWidget *dlg = gtk_file_chooser_dialog_new(options->title, options->webview, GTK_FILE_CHOOSER_ACTION_OPEN,
|
GtkWidget *dlgWidget = gtk_file_chooser_dialog_new(options->title, options->webview, GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
"_Cancel", GTK_RESPONSE_CANCEL,
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
||||||
"_Open", GTK_RESPONSE_ACCEPT,
|
"_Open", GTK_RESPONSE_ACCEPT,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
gint response = gtk_dialog_run(GTK_DIALOG(dlg));
|
GtkFileChooser *fc = GTK_FILE_CHOOSER(dlgWidget);
|
||||||
|
// filters
|
||||||
|
if (options->filters != 0) {
|
||||||
|
int index = 0;
|
||||||
|
GtkFileFilter* thisFilter;
|
||||||
|
while(options->filters[index] != NULL) {
|
||||||
|
thisFilter = options->filters[index];
|
||||||
|
gtk_file_chooser_add_filter(fc, thisFilter);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_file_chooser_set_local_only(fc, FALSE);
|
||||||
|
|
||||||
|
if (options->multipleFiles == 1) {
|
||||||
|
gtk_file_chooser_set_select_multiple(fc, TRUE);
|
||||||
|
}
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(fc, TRUE);
|
||||||
|
if (options->createDirectories == 1) {
|
||||||
|
gtk_file_chooser_set_create_folders(fc, TRUE);
|
||||||
|
}
|
||||||
|
if (options->showHiddenFiles == 1) {
|
||||||
|
gtk_file_chooser_set_show_hidden(fc, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options->action == GTK_FILE_CHOOSER_ACTION_SAVE) {
|
||||||
|
if (options->defaultFilename != NULL) {
|
||||||
|
gtk_file_chooser_set_current_name(fc, options->defaultFilename);
|
||||||
|
free(options->defaultFilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gint response = gtk_dialog_run(GTK_DIALOG(dlgWidget));
|
||||||
|
|
||||||
|
// Max 1024 files to select
|
||||||
|
char** result = calloc(1024, sizeof(char*));
|
||||||
|
int resultIndex = 0;
|
||||||
|
|
||||||
if (response == GTK_RESPONSE_ACCEPT) {
|
if (response == GTK_RESPONSE_ACCEPT) {
|
||||||
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
|
GSList* filenames = gtk_file_chooser_get_filenames(fc);
|
||||||
processOpenFileResult(filename);
|
GSList *iter = filenames;
|
||||||
g_free(filename);
|
while(iter) {
|
||||||
|
result[resultIndex++] = (char *)iter->data;
|
||||||
|
iter = g_slist_next(iter);
|
||||||
|
if (resultIndex == 1024) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processOpenFileResult(result);
|
||||||
|
iter = filenames;
|
||||||
|
while(iter) {
|
||||||
|
g_free(iter->data);
|
||||||
|
iter = g_slist_next(iter);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
processOpenFileResult("");
|
processOpenFileResult(result);
|
||||||
}
|
}
|
||||||
gtk_widget_destroy(dlg);
|
free(result);
|
||||||
|
|
||||||
|
// Release filters
|
||||||
|
if (options->filters != NULL) {
|
||||||
|
int index = 0;
|
||||||
|
GtkFileFilter* thisFilter;
|
||||||
|
while(options->filters[index] != 0) {
|
||||||
|
thisFilter = options->filters[index];
|
||||||
|
g_object_unref(thisFilter);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
freeFileFilterArray(options->filters);
|
||||||
|
}
|
||||||
|
gtk_widget_destroy(dlgWidget);
|
||||||
free(options->title);
|
free(options->title);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GtkFileFilter* newFileFilter() {
|
||||||
|
GtkFileFilter* result = gtk_file_filter_new();
|
||||||
|
g_object_ref(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -286,6 +365,7 @@ func NewWindow(appoptions *options.App, debug bool) *Window {
|
|||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
C.devtoolsEnabled(unsafe.Pointer(webview), C.int(1))
|
C.devtoolsEnabled(unsafe.Pointer(webview), C.int(1))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup window
|
// Setup window
|
||||||
@ -460,11 +540,51 @@ func (w *Window) Quit() {
|
|||||||
C.gtk_main_quit()
|
C.gtk_main_quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) OpenFileDialog(dialogOptions frontend.OpenDialogOptions) {
|
func (w *Window) OpenFileDialog(dialogOptions frontend.OpenDialogOptions, multipleFiles int, action C.GtkFileChooserAction) {
|
||||||
|
|
||||||
data := C.OpenFileDialogOptions{
|
data := C.OpenFileDialogOptions{
|
||||||
webview: w.webview,
|
webview: w.webview,
|
||||||
title: C.CString(dialogOptions.Title),
|
title: C.CString(dialogOptions.Title),
|
||||||
|
multipleFiles: C.int(multipleFiles),
|
||||||
|
action: action,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dialogOptions.Filters) > 0 {
|
||||||
|
// Create filter array
|
||||||
|
mem := NewCalloc()
|
||||||
|
arraySize := len(dialogOptions.Filters) + 1
|
||||||
|
data.filters = C.allocFileFilterArray((C.ulong)(arraySize))
|
||||||
|
filters := (*[1 << 30]*C.struct__GtkFileFilter)(unsafe.Pointer(data.filters))
|
||||||
|
for index, filter := range dialogOptions.Filters {
|
||||||
|
thisFilter := C.gtk_file_filter_new()
|
||||||
|
C.g_object_ref(C.gpointer(thisFilter))
|
||||||
|
if filter.DisplayName != "" {
|
||||||
|
cName := mem.String(filter.DisplayName)
|
||||||
|
C.gtk_file_filter_set_name(thisFilter, cName)
|
||||||
|
}
|
||||||
|
if filter.Pattern != "" {
|
||||||
|
for _, thisPattern := range strings.Split(filter.Pattern, ";") {
|
||||||
|
cThisPattern := mem.String(thisPattern)
|
||||||
|
C.gtk_file_filter_add_pattern(thisFilter, cThisPattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add filter to array
|
||||||
|
filters[index] = thisFilter
|
||||||
|
}
|
||||||
|
mem.Free()
|
||||||
|
filters[arraySize-1] = (*C.struct__GtkFileFilter)(unsafe.Pointer(uintptr(0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if dialogOptions.CanCreateDirectories {
|
||||||
|
data.createDirectories = C.int(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dialogOptions.ShowHiddenFiles {
|
||||||
|
data.showHiddenFiles = C.int(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dialogOptions.DefaultFilename != "" {
|
||||||
|
data.defaultFilename = C.CString(dialogOptions.DefaultFilename)
|
||||||
}
|
}
|
||||||
// TODO: Filter
|
|
||||||
C.ExecuteOnMainThread(C.opendialog, C.gpointer(&data))
|
C.ExecuteOnMainThread(C.opendialog, C.gpointer(&data))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user