5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-11 22:49:29 +08:00

[v3 linux/purego] initial file/directory dialogs impl

This commit is contained in:
Travis McLane 2023-06-21 16:31:26 -05:00
parent d52c26e82f
commit e92858f64d
2 changed files with 190 additions and 182 deletions

View File

@ -54,52 +54,7 @@ func newOpenFileDialogImpl(d *OpenFileDialog) *linuxOpenFileDialog {
}
func (m *linuxOpenFileDialog) show() ([]string, error) {
openFileResponses[m.dialog.id] = make(chan string)
// nsWindow := unsafe.Pointer(nil)
if m.dialog.window != nil {
// get NSWindow from window
//nsWindow = m.dialog.window.impl.(*macosWebviewWindow).nsWindow
}
// Massage filter patterns into macOS format
// We iterate all filter patterns, tidy them up and then join them with a semicolon
// This should produce a single string of extensions like "png;jpg;gif"
// var filterPatterns string
// if len(m.dialog.filters) > 0 {
// var allPatterns []string
// for _, filter := range m.dialog.filters {
// patternComponents := strings.Split(filter.Pattern, ";")
// for i, component := range patternComponents {
// filterPattern := strings.TrimSpace(component)
// filterPattern = strings.TrimPrefix(filterPattern, "*.")
// patternComponents[i] = filterPattern
// }
// allPatterns = append(allPatterns, strings.Join(patternComponents, ";"))
// }
// filterPatterns = strings.Join(allPatterns, ";")
// }
// C.showOpenFileDialog(C.uint(m.dialog.id),
// C.bool(m.dialog.canChooseFiles),
// C.bool(m.dialog.canChooseDirectories),
// C.bool(m.dialog.canCreateDirectories),
// C.bool(m.dialog.showHiddenFiles),
// C.bool(m.dialog.allowsMultipleSelection),
// C.bool(m.dialog.resolvesAliases),
// C.bool(m.dialog.hideExtension),
// C.bool(m.dialog.treatsFilePackagesAsDirectories),
// C.bool(m.dialog.allowsOtherFileTypes),
// toCString(filterPatterns),
// C.uint(len(filterPatterns)),
// toCString(m.dialog.message),
// toCString(m.dialog.directory),
// toCString(m.dialog.buttonText),
// nsWindow)
var result []string
for filename := range openFileResponses[m.dialog.id] {
result = append(result, filename)
}
return result, nil
return runOpenFileDialog(m.dialog)
}
type linuxSaveFileDialog struct {
@ -113,24 +68,5 @@ func newSaveFileDialogImpl(d *SaveFileDialog) *linuxSaveFileDialog {
}
func (m *linuxSaveFileDialog) show() (string, error) {
saveFileResponses[m.dialog.id] = make(chan string)
// nsWindow := unsafe.Pointer(nil)
if m.dialog.window != nil {
// get NSWindow from window
// nsWindow = m.dialog.window.impl.(*linuxWebviewWindow).nsWindow
}
// C.showSaveFileDialog(C.uint(m.dialog.id),
// C.bool(m.dialog.canCreateDirectories),
// C.bool(m.dialog.showHiddenFiles),
// C.bool(m.dialog.canSelectHiddenExtension),
// C.bool(m.dialog.hideExtension),
// C.bool(m.dialog.treatsFilePackagesAsDirectories),
// C.bool(m.dialog.allowOtherFileTypes),
// toCString(m.dialog.message),
// toCString(m.dialog.directory),
// toCString(m.dialog.buttonText),
// toCString(m.dialog.filename),
// nsWindow)
return <-saveFileResponses[m.dialog.id], nil
return runSaveFileDialog(m.dialog)
}

View File

@ -16,7 +16,13 @@ import (
type windowPointer uintptr
type identifier uint
type pointer uintptr
type GSList uintptr
// type GSList uintptr
type GSList struct {
data pointer
next *GSList
}
type GSListPointer *GSList
const (
@ -93,6 +99,7 @@ var (
gApplicationRun func(pointer, int, []string) int
gBytesNewStatic func(uintptr, int) uintptr
gBytesUnref func(uintptr)
gFree func(pointer)
gIdleAdd func(uintptr)
gObjectRefSink func(pointer)
gObjectUnref func(pointer)
@ -131,6 +138,13 @@ var (
gtkDialogRun func(pointer) int
gtkDialogSetDefaultResponse func(pointer, int)
gtkDragDestSet func(pointer, uint, pointer, uint, uint)
gtkFileChooserDialogNew func(string, pointer, int, string, int, string, int, pointer) pointer
gtkFileChooserGetFilenames func(pointer) *GSList
gtkFileChooserSetCreateFolders func(pointer, int)
gtkFileChooserSetCurrentFolder func(pointer, string)
gtkFileChooserSetSelectMultiple func(pointer, int)
gtkFileChooserSetShowHidden func(pointer, int)
gtkImageNewFromPixbuf func(pointer) pointer
gtkMenuBarNew func() pointer
gtkMenuItemNewWithLabel func(string) pointer
@ -227,6 +241,7 @@ func init() {
purego.RegisterLibFunc(&gApplicationRun, gtk, "g_application_run")
purego.RegisterLibFunc(&gBytesNewStatic, gtk, "g_bytes_new_static")
purego.RegisterLibFunc(&gBytesUnref, gtk, "g_bytes_unref")
purego.RegisterLibFunc(&gFree, gtk, "g_free")
purego.RegisterLibFunc(&gIdleAdd, gtk, "g_idle_add")
purego.RegisterLibFunc(&gObjectRefSink, gtk, "g_object_ref_sink")
purego.RegisterLibFunc(&gObjectUnref, gtk, "g_object_unref")
@ -265,6 +280,12 @@ func init() {
purego.RegisterLibFunc(&gtkDialogRun, gtk, "gtk_dialog_run")
purego.RegisterLibFunc(&gtkDialogSetDefaultResponse, gtk, "gtk_dialog_set_default_response")
purego.RegisterLibFunc(&gtkDragDestSet, gtk, "gtk_drag_dest_set")
purego.RegisterLibFunc(&gtkFileChooserDialogNew, gtk, "gtk_file_chooser_dialog_new")
purego.RegisterLibFunc(&gtkFileChooserGetFilenames, gtk, "gtk_file_chooser_get_filenames")
purego.RegisterLibFunc(&gtkFileChooserSetCreateFolders, gtk, "gtk_file_chooser_set_create_folders")
purego.RegisterLibFunc(&gtkFileChooserSetCurrentFolder, gtk, "gtk_file_chooser_set_current_folder")
purego.RegisterLibFunc(&gtkFileChooserSetSelectMultiple, gtk, "gtk_file_chooser_set_select_multiple")
purego.RegisterLibFunc(&gtkFileChooserSetShowHidden, gtk, "gtk_file_chooser_set_show_hidden")
purego.RegisterLibFunc(&gtkImageNewFromPixbuf, gtk, "gtk_image_new_from_pixbuf")
purego.RegisterLibFunc(&gtkMenuItemSetLabel, gtk, "gtk_menu_item_set_label")
purego.RegisterLibFunc(&gtkMenuBarNew, gtk, "gtk_menu_bar_new")
@ -919,79 +940,103 @@ func windowMove(window pointer, x, y int) {
gtkWindowMove(window, x, y)
}
/*
func onButtonEvent(_ pointer, event *C.GdkEventButton, data unsafe.Pointer) C.gboolean {
// Constants (defined here to be easier to use with )
GdkButtonPress := C.GDK_BUTTON_PRESS // 4
Gdk2ButtonPress := C.GDK_2BUTTON_PRESS // 5 for double-click
GdkButtonRelease := C.GDK_BUTTON_RELEASE // 7
func runChooserDialog(window pointer, allowMultiple, createFolders, showHidden bool, currentFolder, title string, action int, acceptLabel string, filters []FileFilter) ([]string, error) {
GtkResponseCancel := 0
GtkResponseAccept := 1
windowId := uint(*((*C.uint)(data)))
window := globalApplication.getWindowForID(windowId)
if window == nil {
return C.gboolean(0)
}
lw, ok := (window.impl).(*linuxWebviewWindow)
if !ok {
return C.gboolean(0)
fc := gtkFileChooserDialogNew(
title,
window,
action,
"_Cancel",
GtkResponseCancel,
acceptLabel,
GtkResponseAccept,
0)
for _, filter := range filters {
// TODO: Process and add filters
// gtk_file_chooser_add_filter(fc, thisFilter)
fmt.Println("filter", filter)
}
if event == nil {
return C.gboolean(0)
}
if event.button == 3 {
return C.gboolean(0)
if allowMultiple {
gtkFileChooserSetSelectMultiple(fc, 1)
}
switch int(event._type) {
case GdkButtonPress:
lw.startDrag(uint(event.button), int(event.x_root), int(event.y_root))
case Gdk2ButtonPress:
fmt.Printf("%d - button %d - double-clicked\n", windowId, int(event.button))
case GdkButtonRelease:
lw.endDrag(uint(event.button), int(event.x_root), int(event.y_root))
if createFolders {
gtkFileChooserSetCreateFolders(fc, 1)
}
return C.gboolean(0)
if showHidden {
gtkFileChooserSetShowHidden(fc, 1)
}
if currentFolder != "" {
gtkFileChooserSetCurrentFolder(fc, currentFolder)
}
func onDragNDrop(target unsafe.Pointer, context *C.GdkDragContext, x C.gint, y C.gint, seldata unsafe.Pointer, info C.guint, time C.guint, data unsafe.Pointer) {
fmt.Println("target", target, info)
var length C.gint
selection := unsafe.Pointer(C.gtk_selection_data_get_data_with_length((*C.GtkSelectionData)(seldata), &length))
extracted := C.g_uri_list_extract_uris((*C.char)(selection))
defer C.g_strfreev(extracted)
uris := unsafe.Slice(
(**C.char)(unsafe.Pointer(extracted)),
int(length))
var filenames []string
for _, uri := range uris {
if uri == nil {
buildStringAndFree := func(s pointer) string {
bytes := []byte{}
p := unsafe.Pointer(s)
for {
val := *(*byte)(p)
if val == 0 { // this is the null terminator
break
}
filenames = append(filenames, strings.TrimPrefix(C.GoString(uri), "file://"))
bytes = append(bytes, val)
p = unsafe.Add(p, 1)
}
windowDragAndDropBuffer <- &dragAndDropMessage{
windowId: uint(*((*C.uint)(data))),
filenames: filenames,
}
C.gtk_drag_finish(context, C.true, C.false, time)
gFree(s) // so we don't have to iterate a second time
return string(bytes)
}
func onProcessRequest(request unsafe.Pointer, data unsafe.Pointer) {
windowId := uint(*((*C.uint)(data)))
webviewRequests <- &webViewAssetRequest{
Request: webview.NewRequest(request),
windowId: windowId,
windowName: globalApplication.getWindowForID(windowId).Name(),
response := gtkDialogRun(fc)
selections := []string{}
if response == GtkResponseAccept {
filenames := gtkFileChooserGetFilenames(fc)
iter := filenames
count := 0
for {
selection := buildStringAndFree(iter.data)
selections = append(selections, selection)
iter = iter.next
if iter == nil || count == 1024 {
break
}
count++
}
}
*/
defer gtkWidgetDestroy(fc)
return selections, nil
}
// dialog related
func runOpenFileDialog(dialog *OpenFileDialog) ([]string, error) {
GtkFileChooserActionOpen := 0
// GtkFileChooserActionSave := 1
// GtkFileChooserActionSelectFolder := 2
// GtkFileChooserActionCreateFolder := 3
// (dialog.window.impl).(*linuxWebviewWindow).window // FIXME: dialog.window == nil!
window := pointer(0)
buttonText := dialog.buttonText
if buttonText == "" {
buttonText = "_Open"
}
return runChooserDialog(
window,
dialog.allowsMultipleSelection,
dialog.canCreateDirectories,
dialog.showHiddenFiles,
dialog.directory,
dialog.title,
GtkFileChooserActionOpen,
buttonText,
dialog.filters)
}
// dialog reloated
func runQuestionDialog(parent pointer, options *MessageDialog) int {
dType, ok := map[DialogType]int{
InfoDialog: GtkMessageInfo,
@ -1052,3 +1097,30 @@ func runQuestionDialog(parent pointer, options *MessageDialog) int {
defer gtkWidgetDestroy(dialog)
return gtkDialogRun(dialog)
}
func runSaveFileDialog(dialog *SaveFileDialog) (string, error) {
GtkFileChooserActionSave := 1
// GtkFileChooserActionSelectFolder := 2
// GtkFileChooserActionCreateFolder := 3
window := pointer(0)
buttonText := dialog.buttonText
if buttonText == "" {
buttonText = "_Save"
}
results, err := runChooserDialog(
window,
false, // multiple selection
dialog.canCreateDirectories,
dialog.showHiddenFiles,
dialog.directory,
dialog.title,
GtkFileChooserActionSave,
buttonText,
dialog.filters)
if err != nil || len(results) == 0 {
return "", err
}
return results[0], nil
}