845 lines
17 KiB
Text
845 lines
17 KiB
Text
|
|
---
|
||
|
|
title: Dialogs API
|
||
|
|
description: Complete reference for native dialog APIs
|
||
|
|
sidebar:
|
||
|
|
order: 5
|
||
|
|
---
|
||
|
|
|
||
|
|
import { Card, CardGrid } from "@astrojs/starlight/components";
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
The Dialogs API provides methods to show native file dialogs and message dialogs. Access dialogs through the `app.Dialog` manager.
|
||
|
|
|
||
|
|
**Dialog Types:**
|
||
|
|
- **File Dialogs** - Open and Save dialogs
|
||
|
|
- **Message Dialogs** - Info, Error, Warning, and Question dialogs
|
||
|
|
|
||
|
|
All dialogs are **native OS dialogs** that match the platform's look and feel.
|
||
|
|
|
||
|
|
## Accessing Dialogs
|
||
|
|
|
||
|
|
Dialogs are accessed through the `app.Dialog` manager:
|
||
|
|
|
||
|
|
```go
|
||
|
|
app.Dialog.OpenFile()
|
||
|
|
app.Dialog.SaveFile()
|
||
|
|
app.Dialog.Info()
|
||
|
|
app.Dialog.Question()
|
||
|
|
app.Dialog.Warning()
|
||
|
|
app.Dialog.Error()
|
||
|
|
```
|
||
|
|
|
||
|
|
## File Dialogs
|
||
|
|
|
||
|
|
### OpenFile()
|
||
|
|
|
||
|
|
Creates a file open dialog.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (dm *DialogManager) OpenFile() *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
dialog := app.Dialog.OpenFile()
|
||
|
|
```
|
||
|
|
|
||
|
|
### OpenFileDialogStruct Methods
|
||
|
|
|
||
|
|
#### SetTitle()
|
||
|
|
|
||
|
|
Sets the dialog title.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) SetTitle(title string) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
dialog.SetTitle("Select Image")
|
||
|
|
```
|
||
|
|
|
||
|
|
#### AddFilter()
|
||
|
|
|
||
|
|
Adds a file type filter.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) AddFilter(displayName, pattern string) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Parameters:**
|
||
|
|
- `displayName` - Filter description shown to user (e.g., "Images", "Documents")
|
||
|
|
- `pattern` - Semicolon-separated list of extensions (e.g., "*.png;*.jpg")
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
dialog.AddFilter("Images", "*.png;*.jpg;*.gif").
|
||
|
|
AddFilter("Documents", "*.pdf;*.docx").
|
||
|
|
AddFilter("All Files", "*.*")
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetDirectory()
|
||
|
|
|
||
|
|
Sets the initial directory.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) SetDirectory(directory string) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
homeDir, _ := os.UserHomeDir()
|
||
|
|
dialog.SetDirectory(homeDir)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### CanChooseDirectories()
|
||
|
|
|
||
|
|
Enables or disables directory selection.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) CanChooseDirectories(canChooseDirectories bool) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example (folder selection):**
|
||
|
|
```go
|
||
|
|
// Select folders instead of files
|
||
|
|
path, err := app.Dialog.OpenFile().
|
||
|
|
SetTitle("Select Folder").
|
||
|
|
CanChooseDirectories(true).
|
||
|
|
CanChooseFiles(false).
|
||
|
|
PromptForSingleSelection()
|
||
|
|
```
|
||
|
|
|
||
|
|
#### CanChooseFiles()
|
||
|
|
|
||
|
|
Enables or disables file selection.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) CanChooseFiles(canChooseFiles bool) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
#### CanCreateDirectories()
|
||
|
|
|
||
|
|
Enables or disables creating new directories.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) CanCreateDirectories(canCreateDirectories bool) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
#### ShowHiddenFiles()
|
||
|
|
|
||
|
|
Shows or hides hidden files.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) ShowHiddenFiles(showHiddenFiles bool) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
#### AttachToWindow()
|
||
|
|
|
||
|
|
Attaches the dialog to a specific window.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) AttachToWindow(window Window) *OpenFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
#### PromptForSingleSelection()
|
||
|
|
|
||
|
|
Shows the dialog and returns the selected file.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) PromptForSingleSelection() (string, error)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Returns:**
|
||
|
|
- `string` - Selected file path (empty if cancelled)
|
||
|
|
- `error` - Error if dialog failed
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
path, err := app.Dialog.OpenFile().
|
||
|
|
SetTitle("Select Image").
|
||
|
|
AddFilter("Images", "*.png;*.jpg;*.gif").
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
// User cancelled or error occurred
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// Use the selected file
|
||
|
|
processFile(path)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### PromptForMultipleSelection()
|
||
|
|
|
||
|
|
Shows the dialog and returns multiple selected files.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *OpenFileDialogStruct) PromptForMultipleSelection() ([]string, error)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Returns:**
|
||
|
|
- `[]string` - Array of selected file paths
|
||
|
|
- `error` - Error if dialog failed
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
paths, err := app.Dialog.OpenFile().
|
||
|
|
SetTitle("Select Images").
|
||
|
|
AddFilter("Images", "*.png;*.jpg").
|
||
|
|
PromptForMultipleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, path := range paths {
|
||
|
|
processFile(path)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### SaveFile()
|
||
|
|
|
||
|
|
Creates a file save dialog.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (dm *DialogManager) SaveFile() *SaveFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
dialog := app.Dialog.SaveFile()
|
||
|
|
```
|
||
|
|
|
||
|
|
### SaveFileDialogStruct Methods
|
||
|
|
|
||
|
|
#### SetTitle()
|
||
|
|
|
||
|
|
Sets the dialog title.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *SaveFileDialogStruct) SetTitle(title string) *SaveFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetFilename()
|
||
|
|
|
||
|
|
Sets the default filename.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *SaveFileDialogStruct) SetFilename(filename string) *SaveFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
dialog.SetFilename("document.pdf")
|
||
|
|
```
|
||
|
|
|
||
|
|
#### AddFilter()
|
||
|
|
|
||
|
|
Adds a file type filter.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *SaveFileDialogStruct) AddFilter(displayName, pattern string) *SaveFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
dialog.AddFilter("PDF Document", "*.pdf").
|
||
|
|
AddFilter("Text Document", "*.txt")
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetDirectory()
|
||
|
|
|
||
|
|
Sets the initial directory.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *SaveFileDialogStruct) SetDirectory(directory string) *SaveFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
#### AttachToWindow()
|
||
|
|
|
||
|
|
Attaches the dialog to a specific window.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *SaveFileDialogStruct) AttachToWindow(window Window) *SaveFileDialogStruct
|
||
|
|
```
|
||
|
|
|
||
|
|
#### PromptForSingleSelection()
|
||
|
|
|
||
|
|
Shows the dialog and returns the save path.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *SaveFileDialogStruct) PromptForSingleSelection() (string, error)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
path, err := app.Dialog.SaveFile().
|
||
|
|
SetTitle("Save Document").
|
||
|
|
SetFilename("untitled.pdf").
|
||
|
|
AddFilter("PDF Document", "*.pdf").
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
// User cancelled
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// Save to the selected path
|
||
|
|
saveDocument(path)
|
||
|
|
```
|
||
|
|
|
||
|
|
### Folder Selection
|
||
|
|
|
||
|
|
There is no separate `SelectFolderDialog`. Use `OpenFile()` with directory options:
|
||
|
|
|
||
|
|
```go
|
||
|
|
path, err := app.Dialog.OpenFile().
|
||
|
|
SetTitle("Select Output Folder").
|
||
|
|
CanChooseDirectories(true).
|
||
|
|
CanChooseFiles(false).
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
// User cancelled
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// Use the selected folder
|
||
|
|
outputDir = path
|
||
|
|
```
|
||
|
|
|
||
|
|
## Message Dialogs
|
||
|
|
|
||
|
|
All message dialogs return `*MessageDialog` and share the same methods.
|
||
|
|
|
||
|
|
### Info()
|
||
|
|
|
||
|
|
Creates an information dialog.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (dm *DialogManager) Info() *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
app.Dialog.Info().
|
||
|
|
SetTitle("Success").
|
||
|
|
SetMessage("File saved successfully!").
|
||
|
|
Show()
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error()
|
||
|
|
|
||
|
|
Creates an error dialog.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (dm *DialogManager) Error() *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
app.Dialog.Error().
|
||
|
|
SetTitle("Error").
|
||
|
|
SetMessage("Failed to save file: " + err.Error()).
|
||
|
|
Show()
|
||
|
|
```
|
||
|
|
|
||
|
|
### Warning()
|
||
|
|
|
||
|
|
Creates a warning dialog.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (dm *DialogManager) Warning() *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
app.Dialog.Warning().
|
||
|
|
SetTitle("Warning").
|
||
|
|
SetMessage("This action cannot be undone.").
|
||
|
|
Show()
|
||
|
|
```
|
||
|
|
|
||
|
|
### Question()
|
||
|
|
|
||
|
|
Creates a question dialog with custom buttons.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (dm *DialogManager) Question() *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
dialog := app.Dialog.Question().
|
||
|
|
SetTitle("Confirm").
|
||
|
|
SetMessage("Do you want to save changes?")
|
||
|
|
|
||
|
|
save := dialog.AddButton("Save")
|
||
|
|
save.OnClick(func() {
|
||
|
|
saveDocument()
|
||
|
|
})
|
||
|
|
|
||
|
|
dontSave := dialog.AddButton("Don't Save")
|
||
|
|
dontSave.OnClick(func() {
|
||
|
|
// Continue without saving
|
||
|
|
})
|
||
|
|
|
||
|
|
cancel := dialog.AddButton("Cancel")
|
||
|
|
cancel.OnClick(func() {
|
||
|
|
// Do nothing
|
||
|
|
})
|
||
|
|
|
||
|
|
dialog.SetDefaultButton(save)
|
||
|
|
dialog.SetCancelButton(cancel)
|
||
|
|
dialog.Show()
|
||
|
|
```
|
||
|
|
|
||
|
|
### MessageDialog Methods
|
||
|
|
|
||
|
|
#### SetTitle()
|
||
|
|
|
||
|
|
Sets the dialog title.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) SetTitle(title string) *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetMessage()
|
||
|
|
|
||
|
|
Sets the dialog message.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) SetMessage(message string) *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetIcon()
|
||
|
|
|
||
|
|
Sets a custom icon for the dialog.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) SetIcon(icon []byte) *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
#### AddButton()
|
||
|
|
|
||
|
|
Adds a button to the dialog and returns the button for configuration.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) AddButton(label string) *Button
|
||
|
|
```
|
||
|
|
|
||
|
|
**Returns:** `*Button` - The button instance for further configuration
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
button := dialog.AddButton("OK")
|
||
|
|
button.OnClick(func() {
|
||
|
|
// Handle click
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetDefaultButton()
|
||
|
|
|
||
|
|
Sets which button is the default (activated by pressing Enter).
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) SetDefaultButton(button *Button) *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
yes := dialog.AddButton("Yes")
|
||
|
|
no := dialog.AddButton("No")
|
||
|
|
dialog.SetDefaultButton(yes)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetCancelButton()
|
||
|
|
|
||
|
|
Sets which button is the cancel button (activated by pressing Escape).
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) SetCancelButton(button *Button) *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
**Example:**
|
||
|
|
```go
|
||
|
|
ok := dialog.AddButton("OK")
|
||
|
|
cancel := dialog.AddButton("Cancel")
|
||
|
|
dialog.SetCancelButton(cancel)
|
||
|
|
```
|
||
|
|
|
||
|
|
#### AttachToWindow()
|
||
|
|
|
||
|
|
Attaches the dialog to a specific window.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) AttachToWindow(window Window) *MessageDialog
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Show()
|
||
|
|
|
||
|
|
Shows the dialog. Button callbacks handle user responses.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (d *MessageDialog) Show()
|
||
|
|
```
|
||
|
|
|
||
|
|
**Note:** `Show()` does not return a value. Use button callbacks to handle user responses.
|
||
|
|
|
||
|
|
### Button Methods
|
||
|
|
|
||
|
|
#### OnClick()
|
||
|
|
|
||
|
|
Sets the callback function for when the button is clicked.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (b *Button) OnClick(callback func()) *Button
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetAsDefault()
|
||
|
|
|
||
|
|
Marks this button as the default button.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (b *Button) SetAsDefault() *Button
|
||
|
|
```
|
||
|
|
|
||
|
|
#### SetAsCancel()
|
||
|
|
|
||
|
|
Marks this button as the cancel button.
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (b *Button) SetAsCancel() *Button
|
||
|
|
```
|
||
|
|
|
||
|
|
## Complete Examples
|
||
|
|
|
||
|
|
### File Selection Example
|
||
|
|
|
||
|
|
```go
|
||
|
|
type FileService struct {
|
||
|
|
app *application.App
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *FileService) OpenImage() (string, error) {
|
||
|
|
path, err := s.app.Dialog.OpenFile().
|
||
|
|
SetTitle("Select Image").
|
||
|
|
AddFilter("Images", "*.png;*.jpg;*.jpeg;*.gif").
|
||
|
|
AddFilter("All Files", "*.*").
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
return path, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *FileService) SaveDocument(defaultName string) (string, error) {
|
||
|
|
path, err := s.app.Dialog.SaveFile().
|
||
|
|
SetTitle("Save Document").
|
||
|
|
SetFilename(defaultName).
|
||
|
|
AddFilter("PDF Document", "*.pdf").
|
||
|
|
AddFilter("Text Document", "*.txt").
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
return path, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *FileService) SelectOutputFolder() (string, error) {
|
||
|
|
path, err := s.app.Dialog.OpenFile().
|
||
|
|
SetTitle("Select Output Folder").
|
||
|
|
CanChooseDirectories(true).
|
||
|
|
CanChooseFiles(false).
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
return path, nil
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Confirmation Dialog Example
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (s *Service) DeleteItem(app *application.App, id string) {
|
||
|
|
dialog := app.Dialog.Question().
|
||
|
|
SetTitle("Confirm Delete").
|
||
|
|
SetMessage("Are you sure you want to delete this item?")
|
||
|
|
|
||
|
|
deleteBtn := dialog.AddButton("Delete")
|
||
|
|
deleteBtn.OnClick(func() {
|
||
|
|
deleteFromDatabase(id)
|
||
|
|
})
|
||
|
|
|
||
|
|
cancelBtn := dialog.AddButton("Cancel")
|
||
|
|
// Cancel does nothing
|
||
|
|
|
||
|
|
dialog.SetDefaultButton(cancelBtn) // Default to Cancel for safety
|
||
|
|
dialog.SetCancelButton(cancelBtn)
|
||
|
|
dialog.Show()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Save Changes Dialog
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (s *Editor) PromptSaveChanges(app *application.App) {
|
||
|
|
dialog := app.Dialog.Question().
|
||
|
|
SetTitle("Unsaved Changes").
|
||
|
|
SetMessage("Do you want to save your changes before closing?")
|
||
|
|
|
||
|
|
save := dialog.AddButton("Save")
|
||
|
|
save.OnClick(func() {
|
||
|
|
s.Save()
|
||
|
|
s.Close()
|
||
|
|
})
|
||
|
|
|
||
|
|
dontSave := dialog.AddButton("Don't Save")
|
||
|
|
dontSave.OnClick(func() {
|
||
|
|
s.Close()
|
||
|
|
})
|
||
|
|
|
||
|
|
cancel := dialog.AddButton("Cancel")
|
||
|
|
// Cancel does nothing, dialog closes
|
||
|
|
|
||
|
|
dialog.SetDefaultButton(save)
|
||
|
|
dialog.SetCancelButton(cancel)
|
||
|
|
dialog.Show()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Multi-File Processing
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (s *Service) ProcessMultipleFiles(app *application.App) error {
|
||
|
|
// Select multiple files
|
||
|
|
paths, err := app.Dialog.OpenFile().
|
||
|
|
SetTitle("Select Files to Process").
|
||
|
|
AddFilter("Images", "*.png;*.jpg").
|
||
|
|
PromptForMultipleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(paths) == 0 {
|
||
|
|
app.Dialog.Info().
|
||
|
|
SetTitle("No Files Selected").
|
||
|
|
SetMessage("Please select at least one file.").
|
||
|
|
Show()
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Process files
|
||
|
|
for _, path := range paths {
|
||
|
|
err := processFile(path)
|
||
|
|
if err != nil {
|
||
|
|
app.Dialog.Error().
|
||
|
|
SetTitle("Processing Error").
|
||
|
|
SetMessage(fmt.Sprintf("Failed to process %s: %v", path, err)).
|
||
|
|
Show()
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Show completion
|
||
|
|
app.Dialog.Info().
|
||
|
|
SetTitle("Complete").
|
||
|
|
SetMessage(fmt.Sprintf("Successfully processed %d files", len(paths))).
|
||
|
|
Show()
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error Handling with Dialogs
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (s *Service) SaveFile(app *application.App, data []byte) error {
|
||
|
|
// Select save location
|
||
|
|
path, err := app.Dialog.SaveFile().
|
||
|
|
SetTitle("Save File").
|
||
|
|
SetFilename("data.json").
|
||
|
|
AddFilter("JSON File", "*.json").
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
// User cancelled - not an error
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Attempt to save
|
||
|
|
err = os.WriteFile(path, data, 0644)
|
||
|
|
if err != nil {
|
||
|
|
// Show error dialog
|
||
|
|
app.Dialog.Error().
|
||
|
|
SetTitle("Save Failed").
|
||
|
|
SetMessage(fmt.Sprintf("Could not save file: %v", err)).
|
||
|
|
Show()
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
// Show success
|
||
|
|
app.Dialog.Info().
|
||
|
|
SetTitle("Success").
|
||
|
|
SetMessage("File saved successfully!").
|
||
|
|
Show()
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Platform-Specific Defaults
|
||
|
|
|
||
|
|
```go
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"runtime"
|
||
|
|
)
|
||
|
|
|
||
|
|
func (s *Service) GetDefaultDirectory() string {
|
||
|
|
homeDir, _ := os.UserHomeDir()
|
||
|
|
|
||
|
|
switch runtime.GOOS {
|
||
|
|
case "windows":
|
||
|
|
return filepath.Join(homeDir, "Documents")
|
||
|
|
case "darwin":
|
||
|
|
return filepath.Join(homeDir, "Documents")
|
||
|
|
case "linux":
|
||
|
|
return filepath.Join(homeDir, "Documents")
|
||
|
|
default:
|
||
|
|
return homeDir
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Service) OpenWithDefaults(app *application.App) (string, error) {
|
||
|
|
return app.Dialog.OpenFile().
|
||
|
|
SetTitle("Open File").
|
||
|
|
SetDirectory(s.GetDefaultDirectory()).
|
||
|
|
AddFilter("All Files", "*.*").
|
||
|
|
PromptForSingleSelection()
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Best Practices
|
||
|
|
|
||
|
|
### Do
|
||
|
|
|
||
|
|
- **Use native dialogs** - They match the platform's look and feel
|
||
|
|
- **Provide clear titles** - Help users understand the purpose
|
||
|
|
- **Set appropriate filters** - Guide users to correct file types
|
||
|
|
- **Handle cancellation** - Check for errors (user may cancel)
|
||
|
|
- **Show confirmation for destructive actions** - Use Question dialogs
|
||
|
|
- **Provide feedback** - Use Info dialogs for success messages
|
||
|
|
- **Set sensible defaults** - Default directory, filename, etc.
|
||
|
|
- **Use callbacks for button actions** - Handle user responses properly
|
||
|
|
|
||
|
|
### Don't
|
||
|
|
|
||
|
|
- **Don't ignore errors** - User cancellation returns an error
|
||
|
|
- **Don't use ambiguous button labels** - Be specific: "Save"/"Cancel"
|
||
|
|
- **Don't overuse dialogs** - They interrupt workflow
|
||
|
|
- **Don't show errors for cancellation** - It's a normal action
|
||
|
|
- **Don't forget file filters** - Help users find the right files
|
||
|
|
- **Don't hardcode paths** - Use os.UserHomeDir() or similar
|
||
|
|
|
||
|
|
## Dialog Types by Platform
|
||
|
|
|
||
|
|
### macOS
|
||
|
|
|
||
|
|
- Dialogs slide down from title bar
|
||
|
|
- "Sheet" style attached to parent window
|
||
|
|
- Native macOS appearance
|
||
|
|
|
||
|
|
### Windows
|
||
|
|
|
||
|
|
- Standard Windows dialogs
|
||
|
|
- Follows Windows design guidelines
|
||
|
|
- Modern Windows 10/11 appearance
|
||
|
|
|
||
|
|
### Linux
|
||
|
|
|
||
|
|
- GTK dialogs on GTK-based systems
|
||
|
|
- Qt dialogs on Qt-based systems
|
||
|
|
- Matches desktop environment
|
||
|
|
|
||
|
|
#### Linux GTK4 Limitations
|
||
|
|
|
||
|
|
On Linux with GTK4 (the default for modern distributions), file dialogs use the **xdg-desktop-portal**
|
||
|
|
for native integration. This provides better desktop integration but means some options have no effect:
|
||
|
|
|
||
|
|
| Option | GTK3 | GTK4 | Notes |
|
||
|
|
|--------|------|------|-------|
|
||
|
|
| `ShowHiddenFiles()` | ✅ Works | ❌ No effect | User controls via dialog's UI toggle (Ctrl+H or menu) |
|
||
|
|
| `CanCreateDirectories()` | ✅ Works | ❌ No effect | Always enabled in the portal |
|
||
|
|
| `ResolvesAliases()` | ✅ Works | ❌ No effect | Portal handles symlink resolution |
|
||
|
|
| `SetButtonText()` | ✅ Works | ✅ Works | Custom accept button text works |
|
||
|
|
|
||
|
|
**Why these limitations exist:** GTK4's portal-based dialogs delegate UI control to the desktop
|
||
|
|
environment (GNOME, KDE, etc.). This is by design - the portal provides consistent UX across
|
||
|
|
applications and respects user preferences.
|
||
|
|
|
||
|
|
:::note
|
||
|
|
The table above shows GTK4 behavior when building with `-tags gtk4`. By default, Wails uses GTK3
|
||
|
|
which provides full control over these dialog options.
|
||
|
|
:::
|
||
|
|
|
||
|
|
## Common Patterns
|
||
|
|
|
||
|
|
### "Save As" Pattern
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (s *Service) SaveAs(app *application.App, currentPath string) (string, error) {
|
||
|
|
// Extract filename from current path
|
||
|
|
filename := filepath.Base(currentPath)
|
||
|
|
|
||
|
|
// Show save dialog
|
||
|
|
path, err := app.Dialog.SaveFile().
|
||
|
|
SetTitle("Save As").
|
||
|
|
SetFilename(filename).
|
||
|
|
PromptForSingleSelection()
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
return "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
return path, nil
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### "Open Recent" Pattern
|
||
|
|
|
||
|
|
```go
|
||
|
|
func (s *Service) OpenRecent(app *application.App, recentPath string) error {
|
||
|
|
// Check if file still exists
|
||
|
|
if _, err := os.Stat(recentPath); os.IsNotExist(err) {
|
||
|
|
dialog := app.Dialog.Question().
|
||
|
|
SetTitle("File Not Found").
|
||
|
|
SetMessage("The file no longer exists. Remove from recent files?")
|
||
|
|
|
||
|
|
remove := dialog.AddButton("Remove")
|
||
|
|
remove.OnClick(func() {
|
||
|
|
s.removeFromRecent(recentPath)
|
||
|
|
})
|
||
|
|
|
||
|
|
cancel := dialog.AddButton("Cancel")
|
||
|
|
dialog.SetCancelButton(cancel)
|
||
|
|
dialog.Show()
|
||
|
|
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
return s.openFile(recentPath)
|
||
|
|
}
|
||
|
|
```
|