gofiledialog

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 33 Imported by: 0

README

gofiledialog

Explorer-style Open, Save, and Select Folder dialogs for Fyne applications.

gofiledialog is a reusable Go package for apps that need more than Fyne's built-in file dialog exposes. It builds a dialog from Fyne primitives so it can offer switchable views, sortable Details columns, persistent shared settings, file-type filters, New Folder support, and asynchronous image thumbnails.

The public API follows the same shape as Fyne's dialog helpers: use ShowOpen, ShowSave, or ShowFolder for simple cases, or construct a dialog with NewOpen, NewSave, or NewFolder when you want to configure it before showing it.

Features

  • Open, Save, and Select Folder dialogs
  • Details, List, Small icons, Medium icons, and Large icons views
  • Sortable Details columns with persisted column order, visibility, widths, and sort direction
  • Shared settings across apps using the OS user config directory
  • Places sidebar with Home, Desktop, Documents, Downloads, Pictures, and drives/mounts
  • Back, Forward, Up, breadcrumb navigation, editable path entry, and hidden-file toggle
  • File-type filters and Save default-extension handling
  • New Folder creation and Save overwrite confirmation
  • Async image thumbnails with bounded workers, memory cache, and disk cache
  • Keyboard polish: Up/Down selection, Enter activation, Backspace up, Escape cancel, and type-ahead search

Install

go get github.com/wierdling/gofiledialog

The package targets Fyne v2 and Go 1.22 or newer.

Quick Start

package main

import (
	"fmt"

	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/widget"

	"github.com/wierdling/gofiledialog"
)

func main() {
	a := app.New()
	win := a.NewWindow("Example")

	btn := widget.NewButton("Open...", func() {
		_ = gofiledialog.ShowOpen(func(paths []string, err error) {
			if err != nil {
				fmt.Println("open failed:", err)
				return
			}
			if len(paths) == 0 {
				fmt.Println("cancelled")
				return
			}
			fmt.Println("chosen:", paths)
		}, win)
	})

	win.SetContent(btn)
	win.ShowAndRun()
}

Open Dialog

err := gofiledialog.ShowOpen(func(paths []string, err error) {
	if err != nil {
		// handle error
		return
	}
	if len(paths) == 0 {
		// cancelled
		return
	}
	// use paths
}, win,
	gofiledialog.WithTitle("Choose images"),
	gofiledialog.WithStartDir(`D:\photos`),
	gofiledialog.WithFilters(
		gofiledialog.Filter{Name: "Images", Extensions: []string{".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tif", ".tiff", ".webp"}},
		gofiledialog.Filter{Name: "All files"},
	),
	gofiledialog.WithMultiSelect(true),
)
if err != nil {
	// dialog construction failed
}

Save Dialog

ShowSave returns the chosen path; it does not create or write the file for you. If the user enters a filename without an extension, the selected filter's first extension is appended.

err := gofiledialog.ShowSave(func(paths []string, err error) {
	if err != nil {
		return
	}
	if len(paths) == 0 {
		return // cancelled
	}

	path := paths[0]
	// write to path
}, win,
	gofiledialog.WithFileName("untitled.txt"),
	gofiledialog.WithFilters(
		gofiledialog.Filter{Name: "Text files", Extensions: []string{".txt"}},
		gofiledialog.Filter{Name: "All files"},
	),
)

Folder Dialog

err := gofiledialog.ShowFolder(func(paths []string, err error) {
	if err != nil {
		return
	}
	if len(paths) == 0 {
		return // cancelled
	}

	folder := paths[0]
	// use folder
}, win)

Configured Dialogs

For more control, construct the dialog, set the callback, then show it:

d, err := gofiledialog.NewOpen(win,
	gofiledialog.WithTitle("Import files"),
	gofiledialog.WithMultiSelect(true),
)
if err != nil {
	return err
}

d.SetOnChosen(func(paths []string, err error) {
	// handle result
})
d.Show()

Options

  • WithTitle(title string) sets the dialog window title.
  • WithStartDir(dir string) sets the initial directory.
  • WithFilters(filters ...Filter) configures the Type dropdown.
  • WithMultiSelect(enabled bool) lets Open dialogs accumulate multiple clicked files.
  • WithFileName(name string) pre-fills Save dialogs.
  • WithStore(store Store) overrides the default shared settings store.

Parent Window Parameter

The parent fyne.Window parameter on ShowOpen, ShowSave, ShowFolder, NewOpen, NewSave, and NewFolder is accepted for API compatibility with Fyne's dialog helpers. gofiledialog currently creates top-level windows and centers them on screen because Fyne's public fyne.Window interface does not expose portable parent-relative window placement.

Settings

By default, view mode, sort column/direction, visible columns, column order, column widths, dialog size, hidden-file visibility, and the last folder are persisted in:

os.UserConfigDir()/wierdling-gofiledialog/settings.json

That means settings are shared by every app on the machine that uses the default gofiledialog store. Use WithStore if an app needs isolated or custom persistence. Settings persistence is best-effort: load failures fall back to defaults, and save failures are ignored so a settings backend cannot break a user's file-dialog interaction.

When no WithStartDir is supplied, the dialog first uses Fyne's saved fyne:fileDialogLastFolder preference (when it names an accessible local folder); otherwise it uses the saved lastDir setting.

The default store writes through a temporary file and atomically replaces the settings file, so readers never observe partial JSON. Saves are serialized within the process and coordinated across processes with a short-lived settings.json.lock file. If another process holds the lock for too long, the save is skipped and the last valid settings file is left intact.

Thumbnails

Icon views show generic file-type icons immediately, then load real image thumbnails asynchronously. Thumbnail work is bounded, prioritized by smaller files first, cached in memory, and cached on disk under the OS user cache directory.

Supported thumbnail formats include PNG, JPEG, GIF, BMP, TIFF, and WebP.

Large files and very high-resolution images are skipped so opening a folder with many photos stays responsive.

Demo

Run the demo:

go run ./cmd/demo

Build the demo:

go build -buildvcs=false -o demo.exe ./cmd/demo

Then run:

.\demo.exe

Development

Run tests:

go test ./...

Check package docs locally:

go doc .

Status

This project is at the first release-pass stage for v0.1.0.

Known limitation: WithMultiSelect(true) currently accumulates clicked files. Native Explorer-style Ctrl/Shift range selection will require custom row/item widgets because Fyne's stock List, Table, and GridWrap callbacks do not expose modifier-key selection state.

Documentation

Overview

Package gofiledialog provides Explorer-style Open, Save, and Select Folder dialogs for Fyne applications.

The dialogs are built from Fyne primitives instead of wrapping Fyne's built-in file dialog, which allows gofiledialog to provide switchable views, sortable/configurable Details columns, persistent shared settings, filters, New Folder support, and asynchronous image thumbnails.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ShowFolder

func ShowFolder(onChosen func(paths []string, err error), parent fyne.Window, opts ...Option) error

ShowFolder is a convenience wrapper that builds and immediately shows a folder-selection dialog. parent is accepted for API compatibility but is not used for placement.

func ShowOpen

func ShowOpen(onChosen func(paths []string, err error), parent fyne.Window, opts ...Option) error

ShowOpen is a convenience wrapper that builds and immediately shows an Open dialog, in the style of fyne.io/fyne/v2/dialog.ShowFileOpen. parent is accepted for API compatibility but is not used for placement.

func ShowSave

func ShowSave(onChosen func(paths []string, err error), parent fyne.Window, opts ...Option) error

ShowSave is a convenience wrapper that builds and immediately shows a Save dialog. parent is accepted for API compatibility but is not used for placement.

Types

type Browser

type Browser struct {

	// OnActivate fires when the user activates a file row. Directories are
	// navigated into as soon as they are selected because Fyne's collection
	// widgets do not emit a second OnSelected event for the already-selected
	// item.
	OnActivate func(entry FileEntry)

	// OnDirChanged fires whenever the browser finishes navigating to a new
	// directory, so a toolbar/breadcrumb can refresh its state.
	OnDirChanged func(dir string)

	// OnSelectionChanged fires when the selected entry set changes.
	OnSelectionChanged func()

	// OnError fires when a navigation attempt (double-click, Back/Forward/Up,
	// or a path typed into a breadcrumb) fails, e.g. permission denied.
	OnError func(err error)

	// OnSettingsChanged fires whenever persisted dialog state (sort, column
	// visibility/width, show-hidden) changes, so a caller can save it.
	OnSettingsChanged func()
	// contains filtered or unexported fields
}

Browser is the core directory-browsing widget shared by the Open, Save and Folder dialogs. It supports Details, List, and Small/Medium/Large icon views over the same underlying entries.

func NewBrowser

func NewBrowser(startDir string) (*Browser, error)

NewBrowser creates a Browser listing startDir.

func (*Browser) ActivateSelected

func (b *Browser) ActivateSelected()

ActivateSelected opens the selected directory or activates the selected file through OnActivate.

func (*Browser) Back

func (b *Browser) Back() error

Back navigates to the previous directory in history, if any.

func (*Browser) CanGoBack

func (b *Browser) CanGoBack() bool

CanGoBack reports whether Back would move to a different directory.

func (*Browser) CanGoForward

func (b *Browser) CanGoForward() bool

CanGoForward reports whether Forward would move to a different directory.

func (*Browser) Close added in v0.1.2

func (b *Browser) Close()

Close releases background resources owned by the browser. A closed browser must not be reused.

func (*Browser) Columns

func (b *Browser) Columns() []Column

Columns returns every registered column (visible or not), for building a "choose columns" menu.

func (*Browser) Content

func (b *Browser) Content() fyne.CanvasObject

Content returns the canvas object to embed in a dialog window.

func (*Browser) CurrentDir

func (b *Browser) CurrentDir() string

CurrentDir returns the directory currently being browsed.

func (*Browser) Forward

func (b *Browser) Forward() error

Forward navigates to the next directory in history, if any.

func (*Browser) MoveSelection

func (b *Browser) MoveSelection(delta int)

MoveSelection moves the current row highlight by delta, clamped to the current listing. It is used by keyboard navigation.

func (*Browser) MultiSelect added in v0.1.2

func (b *Browser) MultiSelect() bool

MultiSelect reports whether the browser permits more than one selected file.

func (*Browser) NavigateTo

func (b *Browser) NavigateTo(dir string) error

NavigateTo lists dir, replaces the browser's current contents, and pushes dir onto the navigation history (discarding any forward history).

func (*Browser) Refresh

func (b *Browser) Refresh() error

func (*Browser) Selected

func (b *Browser) Selected() (FileEntry, bool)

Selected returns the currently highlighted entry, if any.

func (*Browser) SelectedEntries

func (b *Browser) SelectedEntries() []FileEntry

SelectedEntries returns selected files in display order. Directories are intentionally excluded for Open dialogs; Folder dialogs use CurrentDir.

func (*Browser) SetColumnVisible

func (b *Browser) SetColumnVisible(id ColumnID, visible bool)

SetColumnVisible shows or hides a column. Name cannot be hidden.

func (*Browser) SetFilter

func (b *Browser) SetFilter(filter func(FileEntry) bool) error

SetFilter sets a display filter for files and refreshes the current directory. Directories are always shown so users can keep navigating.

func (*Browser) SetMultiSelect

func (b *Browser) SetMultiSelect(enabled bool)

SetMultiSelect controls whether selected files accumulate. Directory activation still navigates immediately.

func (*Browser) SetSort

func (b *Browser) SetSort(id ColumnID)

SetSort sorts the Details view by column id, toggling direction if id is already the active sort column. Unknown column IDs are ignored.

func (*Browser) SetViewMode

func (b *Browser) SetViewMode(mode ViewMode)

SetViewMode switches the active view.

func (*Browser) ShowHidden

func (b *Browser) ShowHidden() bool

ShowHidden reports whether hidden files/directories are currently listed.

func (*Browser) SortAscending

func (b *Browser) SortAscending() bool

func (*Browser) SortColumn

func (b *Browser) SortColumn() ColumnID

SortColumn and SortAscending report the current Details-view sort state.

func (*Browser) ToggleShowHidden

func (b *Browser) ToggleShowHidden(show bool) error

ToggleShowHidden sets whether hidden files/directories are listed and re-lists the current directory.

func (*Browser) TypeAhead

func (b *Browser) TypeAhead(prefix string) bool

TypeAhead selects the next entry whose name begins with prefix, wrapping around from the current selection.

func (*Browser) Up

func (b *Browser) Up() error

Up navigates to the parent of the current directory, if any.

func (*Browser) ViewMode

func (b *Browser) ViewMode() ViewMode

ViewMode returns the currently active view.

func (*Browser) VisibleColumns

func (b *Browser) VisibleColumns() []Column

VisibleColumns returns the currently visible columns in display order.

type Column

type Column struct {
	ID      ColumnID
	Title   string
	Width   float32
	Visible bool
	Text    func(e FileEntry) string
	Less    func(a, b FileEntry) bool
}

Column describes one Details-view column: how to render a cell and how to compare two entries for sorting.

type ColumnID

type ColumnID int

ColumnID identifies one of the built-in Details-view columns.

const (
	ColName ColumnID = iota
	ColDateModified
	ColType
	ColSize
	ColDateCreated
)

type ColumnSetting

type ColumnSetting struct {
	ID      ColumnID `json:"id"`
	Visible bool     `json:"visible"`
	Width   float32  `json:"width"`
}

ColumnSetting is the persisted state of a single Details-view column.

type FileEntry

type FileEntry struct {
	Name        string
	Path        string
	IsDir       bool
	Hidden      bool
	Size        int64
	ModTime     time.Time
	CreatedTime time.Time
}

FileEntry describes a single file or directory shown in the browser.

type Filter

type Filter struct {
	Name       string
	Extensions []string
}

Filter describes one file-type option in the dialog's Type dropdown. Extensions are case-insensitive and may be written with or without a leading dot. A nil or empty Extensions slice matches all files.

func (Filter) DefaultExtension

func (f Filter) DefaultExtension() string

func (Filter) Label

func (f Filter) Label() string

func (Filter) Match

func (f Filter) Match(entry FileEntry) bool

type FolderDialog

type FolderDialog struct {
	// contains filtered or unexported fields
}

FolderDialog is a folder-selection dialog window.

func NewFolder

func NewFolder(parent fyne.Window, opts ...Option) (*FolderDialog, error)

NewFolder builds a folder-selection dialog. The currently displayed folder is returned when the user chooses Select Folder. parent is accepted for API compatibility with Fyne's dialog helpers; gofiledialog currently creates a top-level window and centers it on screen because fyne.Window does not expose portable parent-relative placement.

func (*FolderDialog) SetOnChosen

func (d *FolderDialog) SetOnChosen(f func(paths []string, err error))

SetOnChosen sets the callback invoked when the Folder dialog closes.

func (*FolderDialog) Show

func (d *FolderDialog) Show()

Show displays the Folder dialog window, centered on screen.

type OpenDialog

type OpenDialog struct {
	// contains filtered or unexported fields
}

OpenDialog is a file-open dialog window.

func NewOpen

func NewOpen(parent fyne.Window, opts ...Option) (*OpenDialog, error)

NewOpen builds an Open-file dialog. The dialog is not shown until Show is called. parent is accepted for API compatibility with Fyne's dialog helpers; gofiledialog currently creates a top-level window and centers it on screen because fyne.Window does not expose portable parent-relative placement.

func (*OpenDialog) SetOnChosen

func (d *OpenDialog) SetOnChosen(f func(paths []string, err error))

SetOnChosen sets the callback invoked when the dialog closes. paths is nil if the user cancelled.

func (*OpenDialog) Show

func (d *OpenDialog) Show()

Show displays the dialog window, centered on screen.

type Option

type Option func(*options)

Option configures a dialog created by NewOpen (and, in later phases, NewSave / NewFolder).

func WithFileName

func WithFileName(name string) Option

WithFileName pre-fills the Save dialog filename entry.

func WithFilters

func WithFilters(filters ...Filter) Option

WithFilters sets the file-type choices shown in the Type dropdown. The first filter is selected initially. Directories are never filtered out.

func WithMultiSelect

func WithMultiSelect(enabled bool) Option

WithMultiSelect allows Open dialogs to accumulate multiple selected files. Fyne's built-in collection widgets do not expose modifier-key selection, so selections accumulate as files are clicked.

func WithStartDir

func WithStartDir(dir string) Option

WithStartDir sets the directory the dialog opens to.

func WithStore

func WithStore(store Store) Option

WithStore overrides where the last folder and view/sort/column/window settings are persisted. By default they're shared, via a JSON file in the OS config directory, across every app on the machine using gofiledialog's default settings.

func WithTitle

func WithTitle(title string) Option

WithTitle sets the dialog window's title.

type Place

type Place struct {
	Name string
	Path string
}

Place is a shortcut shown in the dialog's sidebar (a drive, a known folder, etc).

type SaveDialog

type SaveDialog struct {
	// contains filtered or unexported fields
}

SaveDialog is a file-save dialog window.

func NewSave

func NewSave(parent fyne.Window, opts ...Option) (*SaveDialog, error)

NewSave builds a Save-file dialog. The chosen path is returned without creating the file; callers decide how to write it. parent is accepted for API compatibility with Fyne's dialog helpers; gofiledialog currently creates a top-level window and centers it on screen because fyne.Window does not expose portable parent-relative placement.

func (*SaveDialog) SetOnChosen

func (d *SaveDialog) SetOnChosen(f func(paths []string, err error))

SetOnChosen sets the callback invoked when the Save dialog closes.

func (*SaveDialog) Show

func (d *SaveDialog) Show()

Show displays the Save dialog window, centered on screen.

type Settings

type Settings struct {
	// LastDir is used when Fyne has no remembered file-dialog location.
	LastDir       string          `json:"lastDir"`
	ViewMode      string          `json:"viewMode"`
	ShowHidden    bool            `json:"showHidden"`
	SortColumn    ColumnID        `json:"sortColumn"`
	SortAscending bool            `json:"sortAscending"`
	Columns       []ColumnSetting `json:"columns"`
	WindowWidth   float32         `json:"windowWidth"`
	WindowHeight  float32         `json:"windowHeight"`
}

Settings is the dialog state that persists across processes: the last folder, view mode, sort, visible columns and their widths, the hidden-files toggle, and window size. It is shared by every app that imports gofiledialog and uses the default Store (see WithStore to opt out).

type Store

type Store interface {
	Load() (Settings, error)
	Save(Settings) error
}

Store loads and saves Settings. Dialog persistence is best-effort: Load errors fall back to defaults, and Save errors are intentionally ignored so a settings backend cannot break user interaction.

The default, used unless an app supplies its own via WithStore, is a JSON file shared across every app on the machine that uses gofiledialog with its default settings. The default store serializes in-process saves, coordinates writes with other processes through a lock file, and replaces the settings file atomically.

type ViewMode

type ViewMode string

ViewMode selects how the Browser displays its entries.

const (
	ViewDetails     ViewMode = "details"
	ViewList        ViewMode = "list"
	ViewSmallIcons  ViewMode = "small"
	ViewMediumIcons ViewMode = "medium"
	ViewLargeIcons  ViewMode = "large"
)

func (ViewMode) Label

func (m ViewMode) Label() string

Label returns the human-readable name for m, e.g. for a view-switcher menu.

Directories

Path Synopsis
cmd
demo command
Command demo exercises the gofiledialog dialogs.
Command demo exercises the gofiledialog dialogs.
internal
lru
Package lru implements a small, fixed-capacity, concurrency-safe least-recently-used cache.
Package lru implements a small, fixed-capacity, concurrency-safe least-recently-used cache.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL