mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 14:45:49 +01:00
Start of file dialogs
This commit is contained in:
parent
45adc49683
commit
b1e8f2f887
7 changed files with 252 additions and 35 deletions
|
|
@ -135,6 +135,63 @@ func main() {
|
|||
dialog.Show()
|
||||
})
|
||||
|
||||
openMenu := menu.AddSubmenu("Open")
|
||||
openMenu.Add("Open File").OnClick(func(ctx *application.Context) {
|
||||
result, _ := app.NewOpenFileDialog().
|
||||
CanChooseFiles(true).
|
||||
Show()
|
||||
if result != "" {
|
||||
app.NewInfoDialog().SetMessage(result).Show()
|
||||
} else {
|
||||
app.NewInfoDialog().SetMessage("No file selected").Show()
|
||||
}
|
||||
})
|
||||
openMenu.Add("Open File (Show Hidden Files)").OnClick(func(ctx *application.Context) {
|
||||
result, _ := app.NewOpenFileDialog().
|
||||
CanChooseFiles(true).
|
||||
CanCreateDirectories(true).
|
||||
ShowHiddenFiles(true).
|
||||
Show()
|
||||
if result != "" {
|
||||
app.NewInfoDialog().SetMessage(result).Show()
|
||||
} else {
|
||||
app.NewInfoDialog().SetMessage("No file selected").Show()
|
||||
}
|
||||
})
|
||||
//openMenu.Add("Open Multiple Files (Show Hidden Files)").OnClick(func(ctx *application.Context) {
|
||||
// result, _ := app.NewOpenMultipleFilesDialog().
|
||||
// CanChooseFiles(true).
|
||||
// CanCreateDirectories(true).
|
||||
// ShowHiddenFiles(true).
|
||||
// Show()
|
||||
// if len(result) > 0 {
|
||||
// app.NewInfoDialog().SetMessage(strings.Join(result, ",")).Show()
|
||||
// } else {
|
||||
// app.NewInfoDialog().SetMessage("No file selected").Show()
|
||||
// }
|
||||
//})
|
||||
openMenu.Add("Open Directory").OnClick(func(ctx *application.Context) {
|
||||
result, _ := app.NewOpenFileDialog().
|
||||
CanChooseDirectories(true).
|
||||
Show()
|
||||
if result != "" {
|
||||
app.NewInfoDialog().SetMessage(result).Show()
|
||||
} else {
|
||||
app.NewInfoDialog().SetMessage("No directory selected").Show()
|
||||
}
|
||||
})
|
||||
openMenu.Add("Open Directory (Create Directories)").OnClick(func(ctx *application.Context) {
|
||||
result, _ := app.NewOpenFileDialog().
|
||||
CanChooseDirectories(true).
|
||||
CanCreateDirectories(true).
|
||||
Show()
|
||||
if result != "" {
|
||||
app.NewInfoDialog().SetMessage(result).Show()
|
||||
} else {
|
||||
app.NewInfoDialog().SetMessage("No directory selected").Show()
|
||||
}
|
||||
})
|
||||
|
||||
app.SetMenu(menu)
|
||||
|
||||
app.NewWindow()
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 KiB |
|
|
@ -11,12 +11,6 @@ import (
|
|||
"github.com/wailsapp/wails/exp/pkg/options"
|
||||
)
|
||||
|
||||
//go:embed icon.png
|
||||
var icon []byte
|
||||
|
||||
//go:embed macos_icon.png
|
||||
var macosIcon []byte
|
||||
|
||||
func main() {
|
||||
app := application.NewWithOptions(&options.Application{
|
||||
Mac: &options.Mac{
|
||||
|
|
@ -67,9 +61,9 @@ func main() {
|
|||
mySystray := app.NewSystemTray()
|
||||
mySystray.SetLabel("Wails")
|
||||
if runtime.GOOS == "darwin" {
|
||||
mySystray.SetTemplateIcon(macosIcon)
|
||||
mySystray.SetTemplateIcon(application.DefaultMacTemplateIcon)
|
||||
} else {
|
||||
mySystray.SetIcon(icon)
|
||||
mySystray.SetIcon(application.DefaultApplicationIcon)
|
||||
}
|
||||
myMenu := app.NewMenu()
|
||||
myMenu.Add("Item 1")
|
||||
|
|
@ -107,9 +101,9 @@ func main() {
|
|||
mySystray := app.NewSystemTray()
|
||||
mySystray.SetLabel("Wails is awesome")
|
||||
if runtime.GOOS == "darwin" {
|
||||
mySystray.SetTemplateIcon(macosIcon)
|
||||
mySystray.SetTemplateIcon(application.DefaultMacTemplateIcon)
|
||||
} else {
|
||||
mySystray.SetIcon(icon)
|
||||
mySystray.SetIcon(application.DefaultApplicationIcon)
|
||||
}
|
||||
mySystray.SetMenu(myMenu)
|
||||
mySystray.SetIconPosition(application.NSImageLeading)
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ type App struct {
|
|||
// The main application menu
|
||||
ApplicationMenu *Menu
|
||||
|
||||
// About Dialog
|
||||
// About MessageDialog
|
||||
name string
|
||||
description string
|
||||
icon []byte
|
||||
|
|
@ -321,18 +321,26 @@ func (a *App) ShowAboutDialog() {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *App) NewInfoDialog() *Dialog {
|
||||
return newDialog(InfoDialog)
|
||||
func (a *App) NewInfoDialog() *MessageDialog {
|
||||
return newMessageDialog(InfoDialog)
|
||||
}
|
||||
|
||||
func (a *App) NewQuestionDialog() *Dialog {
|
||||
return newDialog(QuestionDialog)
|
||||
func (a *App) NewQuestionDialog() *MessageDialog {
|
||||
return newMessageDialog(QuestionDialog)
|
||||
}
|
||||
|
||||
func (a *App) NewWarningDialog() *Dialog {
|
||||
return newDialog(WarningDialog)
|
||||
func (a *App) NewWarningDialog() *MessageDialog {
|
||||
return newMessageDialog(WarningDialog)
|
||||
}
|
||||
|
||||
func (a *App) NewErrorDialog() *Dialog {
|
||||
return newDialog(ErrorDialog)
|
||||
func (a *App) NewErrorDialog() *MessageDialog {
|
||||
return newMessageDialog(ErrorDialog)
|
||||
}
|
||||
|
||||
func (a *App) NewOpenDirectoryDialog() *MessageDialog {
|
||||
return newMessageDialog(OpenDirectoryDialog)
|
||||
}
|
||||
|
||||
func (a *App) NewOpenFileDialog() *OpenFileDialog {
|
||||
return newOpenFileDialog()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,30 @@
|
|||
package application
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DialogType int
|
||||
|
||||
var dialogID uint
|
||||
var dialogIDLock sync.RWMutex
|
||||
|
||||
func getDialogID() uint {
|
||||
dialogIDLock.Lock()
|
||||
defer dialogIDLock.Unlock()
|
||||
dialogID++
|
||||
return dialogID
|
||||
}
|
||||
|
||||
var openFileResponses = make(map[uint]chan string)
|
||||
|
||||
const (
|
||||
InfoDialog DialogType = iota
|
||||
QuestionDialog
|
||||
WarningDialog
|
||||
ErrorDialog
|
||||
OpenDirectoryDialog
|
||||
)
|
||||
|
||||
type Button struct {
|
||||
|
|
@ -20,19 +38,19 @@ func (b *Button) OnClick(callback func()) {
|
|||
b.callback = callback
|
||||
}
|
||||
|
||||
type dialogImpl interface {
|
||||
type messageDialogImpl interface {
|
||||
show()
|
||||
}
|
||||
|
||||
type Dialog struct {
|
||||
type MessageDialog struct {
|
||||
dialogType DialogType
|
||||
title string
|
||||
message string
|
||||
buttons []*Button
|
||||
icon []byte
|
||||
|
||||
// platform independent
|
||||
impl dialogImpl
|
||||
icon []byte
|
||||
impl messageDialogImpl
|
||||
}
|
||||
|
||||
var defaultTitles = map[DialogType]string{
|
||||
|
|
@ -42,36 +60,36 @@ var defaultTitles = map[DialogType]string{
|
|||
ErrorDialog: "Error",
|
||||
}
|
||||
|
||||
func newDialog(dialogType DialogType) *Dialog {
|
||||
return &Dialog{
|
||||
func newMessageDialog(dialogType DialogType) *MessageDialog {
|
||||
return &MessageDialog{
|
||||
dialogType: dialogType,
|
||||
title: defaultTitles[dialogType],
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dialog) SetTitle(title string) *Dialog {
|
||||
func (d *MessageDialog) SetTitle(title string) *MessageDialog {
|
||||
d.title = title
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Dialog) SetMessage(message string) *Dialog {
|
||||
func (d *MessageDialog) SetMessage(message string) *MessageDialog {
|
||||
d.message = message
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Dialog) Show() {
|
||||
func (d *MessageDialog) Show() {
|
||||
if d.impl == nil {
|
||||
d.impl = newDialogImpl(d)
|
||||
}
|
||||
d.impl.show()
|
||||
}
|
||||
|
||||
func (d *Dialog) SetIcon(icon []byte) *Dialog {
|
||||
func (d *MessageDialog) SetIcon(icon []byte) *MessageDialog {
|
||||
d.icon = icon
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Dialog) AddButton(s string) *Button {
|
||||
func (d *MessageDialog) AddButton(s string) *Button {
|
||||
result := &Button{
|
||||
label: s,
|
||||
}
|
||||
|
|
@ -79,7 +97,7 @@ func (d *Dialog) AddButton(s string) *Button {
|
|||
return result
|
||||
}
|
||||
|
||||
func (d *Dialog) SetDefaultButton(button *Button) *Dialog {
|
||||
func (d *MessageDialog) SetDefaultButton(button *Button) *MessageDialog {
|
||||
for _, b := range d.buttons {
|
||||
b.isDefault = false
|
||||
}
|
||||
|
|
@ -87,10 +105,62 @@ func (d *Dialog) SetDefaultButton(button *Button) *Dialog {
|
|||
return d
|
||||
}
|
||||
|
||||
func (d *Dialog) SetCancelButton(button *Button) *Dialog {
|
||||
func (d *MessageDialog) SetCancelButton(button *Button) *MessageDialog {
|
||||
for _, b := range d.buttons {
|
||||
b.isCancel = false
|
||||
}
|
||||
button.isCancel = true
|
||||
return d
|
||||
}
|
||||
|
||||
type openFileDialogImpl interface {
|
||||
show() ([]string, error)
|
||||
}
|
||||
|
||||
type OpenFileDialog struct {
|
||||
id uint
|
||||
canChooseDirectories bool
|
||||
canChooseFiles bool
|
||||
canCreateDirectories bool
|
||||
showHiddenFiles bool
|
||||
allowsMultipleSelection bool
|
||||
|
||||
impl openFileDialogImpl
|
||||
}
|
||||
|
||||
func (d *OpenFileDialog) CanChooseFiles(canChooseFiles bool) *OpenFileDialog {
|
||||
d.canChooseFiles = canChooseFiles
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *OpenFileDialog) CanChooseDirectories(canChooseDirectories bool) *OpenFileDialog {
|
||||
d.canChooseDirectories = canChooseDirectories
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *OpenFileDialog) CanCreateDirectories(canCreateDirectories bool) *OpenFileDialog {
|
||||
d.canCreateDirectories = canCreateDirectories
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *OpenFileDialog) ShowHiddenFiles(showHiddenFiles bool) *OpenFileDialog {
|
||||
d.showHiddenFiles = showHiddenFiles
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *OpenFileDialog) Show() (string, error) {
|
||||
if d.impl == nil {
|
||||
d.impl = newOpenFileDialogImpl(d)
|
||||
}
|
||||
result, err := d.impl.show()
|
||||
return result[0], err
|
||||
}
|
||||
|
||||
func newOpenFileDialog() *OpenFileDialog {
|
||||
return &OpenFileDialog{
|
||||
id: getDialogID(),
|
||||
canChooseDirectories: false,
|
||||
canChooseFiles: true,
|
||||
canCreateDirectories: false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ package application
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
extern void openFileDialogCallback(uint id, char* path);
|
||||
extern void openFileDialogCallbackEnd(uint id);
|
||||
|
||||
static void showAboutBox(char* title, char *message, void *icon, int length) {
|
||||
|
||||
// run on main thread
|
||||
|
|
@ -99,9 +102,46 @@ static void alertAddButton(void *dialog, char *label, bool isDefault, bool isCan
|
|||
}
|
||||
}
|
||||
|
||||
static void showOpenFileDialog(unsigned int dialogID, bool canChooseFiles, bool canChooseDirectories, bool canCreateDirectories, bool showHiddenFiles, bool allowsMultipleSelection) {
|
||||
|
||||
// run on main thread
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
|
||||
[panel setCanChooseFiles:canChooseFiles];
|
||||
[panel setCanChooseDirectories:canChooseDirectories];
|
||||
[panel setCanCreateDirectories:canCreateDirectories];
|
||||
[panel setShowsHiddenFiles:showHiddenFiles];
|
||||
[panel setAllowsMultipleSelection:allowsMultipleSelection];
|
||||
|
||||
|
||||
// Show panel
|
||||
[panel beginWithCompletionHandler:^(NSInteger result) {
|
||||
const char *path = NULL;
|
||||
if (result == NSModalResponseOK) {
|
||||
if (allowsMultipleSelection) {
|
||||
NSArray *urls = [panel URLs];
|
||||
for (NSURL *url in urls) {
|
||||
path = [[url path] UTF8String];
|
||||
openFileDialogCallback(dialogID, (char *)path);
|
||||
}
|
||||
|
||||
} else {
|
||||
NSURL *url = [panel URL];
|
||||
path = [[url path] UTF8String];
|
||||
openFileDialogCallback(dialogID, (char *)path);
|
||||
}
|
||||
}
|
||||
openFileDialogCallbackEnd(dialogID);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const NSAlertStyleWarning = C.int(0)
|
||||
const NSAlertStyleInformational = C.int(1)
|
||||
|
|
@ -123,7 +163,7 @@ func (m *macosApp) showAboutDialog(title string, message string, icon []byte) {
|
|||
}
|
||||
|
||||
type macosDialog struct {
|
||||
dialog *Dialog
|
||||
dialog *MessageDialog
|
||||
|
||||
nsDialog unsafe.Pointer
|
||||
}
|
||||
|
|
@ -188,8 +228,56 @@ func (m *macosDialog) show() {
|
|||
|
||||
}
|
||||
|
||||
func newDialogImpl(d *Dialog) *macosDialog {
|
||||
func newDialogImpl(d *MessageDialog) *macosDialog {
|
||||
return &macosDialog{
|
||||
dialog: d,
|
||||
}
|
||||
}
|
||||
|
||||
type macosOpenFileDialog struct {
|
||||
dialog *OpenFileDialog
|
||||
}
|
||||
|
||||
func newOpenFileDialogImpl(d *OpenFileDialog) *macosOpenFileDialog {
|
||||
return &macosOpenFileDialog{
|
||||
dialog: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *macosOpenFileDialog) show() ([]string, error) {
|
||||
openFileResponses[dialogID] = make(chan string)
|
||||
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))
|
||||
var result []string
|
||||
for filename := range openFileResponses[m.dialog.id] {
|
||||
result = append(result, filename)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
//export openFileDialogCallback
|
||||
func openFileDialogCallback(id C.uint, path *C.char) {
|
||||
// Covert the path to a string
|
||||
filePath := C.GoString(path)
|
||||
// put response on channel
|
||||
channel, ok := openFileResponses[uint(id)]
|
||||
if ok {
|
||||
channel <- filePath
|
||||
} else {
|
||||
panic("No channel found for open file dialog")
|
||||
}
|
||||
}
|
||||
|
||||
//export openFileDialogCallbackEnd
|
||||
func openFileDialogCallbackEnd(id C.uint) {
|
||||
channel, ok := openFileResponses[uint(id)]
|
||||
if ok {
|
||||
close(channel)
|
||||
} else {
|
||||
panic("No channel found for open file dialog")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue