Exemples de Fonctionnalités Bureau Web Go

Exemples de fonctionnalités spécifiques au bureau Web Go incluant les boîtes de dialogue de fichiers, les boîtes de message et la barre d'état système

Key Facts

Category
Go
Items
3
Format Families
sample

Sample Overview

Exemples de fonctionnalités spécifiques au bureau Web Go incluant les boîtes de dialogue de fichiers, les boîtes de message et la barre d'état système This sample set belongs to Go and can be used to test related workflows inside Elysia Tools.

💻 Boîtes de Message go

🟢 simple ⭐⭐⭐

Afficher des boîtes de message d'information, d'avertissement et d'erreur

⏱️ 20 min 🏷️ go, web, desktop features
Prerequisites: Basic Go, GUI framework
// Web Go Message Box Examples
// Using Fyne and Walk for message dialogs

package main

import (
	"fmt"
	"time"
)

// 1. Using Fyne Framework

/*
import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/dialog"
)

func FyneInfoDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Message Dialog")

	dialog.ShowInformation("Information", "This is an info message", myWindow)
	myWindow.ShowAndRun()
}

func FyneErrorDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Error Dialog")

	dialog.ShowError(errors.New("This is an error message"), myWindow)
	myWindow.ShowAndRun()
}

func FyneConfirmDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Confirm Dialog")

	dialog.ShowConfirm("Confirm", "Are you sure?", func(confirmed bool) {
		if confirmed {
			fmt.Println("User confirmed")
		} else {
			fmt.Println("User cancelled")
		}
	}, myWindow)

	myWindow.ShowAndRun()
}
*/

// 2. Using Walk Framework (Windows)

/*
import (
	"github.com/lxn/walk"
)

func WalkMessageBox() error {
	// Information
	walk.MsgBox(nil, "Information",
		"This is an info message",
		walk.MsgBoxIconInformation)

	// Warning
	walk.MsgBox(nil, "Warning",
		"This is a warning",
		walk.MsgBoxIconWarning)

	// Error
	walk.MsgBox(nil, "Error",
		"This is an error",
		walk.MsgBoxIconError)

	// Question with Yes/No
	ret, err := walk.MsgBox(nil, "Question",
		"Do you want to continue?",
		walk.MsgBoxYesNo|walk.MsgBoxIconQuestion)

	if err == nil {
		if ret == walk.DialogButtonYes {
			fmt.Println("User clicked Yes")
		} else {
			fmt.Println("User clicked No")
		}
	}

	return nil
}
*/

// 3. Cross-Platform Message Box

// MessageType defines message box type
type MessageType int

const (
	InfoMsg MessageType = iota
	WarningMsg
	ErrorMsg
	QuestionMsg
)

// MessageBoxButton defines button type
type MessageBoxButton int

const (
	OKBtn MessageBoxButton = iota
	OKCancelBtn
	YesNoBtn
	YesNoCancelBtn
	RetryCancelBtn
	AbortRetryIgnoreBtn
)

// MessageBoxResult holds message box result
type MessageBoxResult struct {
	ButtonPressed string
	Confirmed     bool
	Err           error
}

// MessageBox shows message box
func MessageBox(title, message string, msgType MessageType, buttons MessageBoxButton) MessageBoxResult {
	// Terminal-based message box
	return showTerminalMessageBox(title, message, msgType, buttons)
}

func showTerminalMessageBox(title, message string, msgType MessageType, buttons MessageBoxButton) MessageBoxResult {
	// Print message header
	var icon string
	switch msgType {
	case InfoMsg:
		icon = "ℹ️"
	case WarningMsg:
		icon = "⚠️"
	case ErrorMsg:
		icon = "❌"
	case QuestionMsg:
		icon = "❓"
	}

	fmt.Printf("\n%s %s\n", icon, title)
	fmt.Printf("%s\n", message)

	// Print buttons
	var options []string
	switch buttons {
	case OKBtn:
		options = []string{"OK"}
	case OKCancelBtn:
		options = []string{"OK", "Cancel"}
	case YesNoBtn:
		options = []string{"Yes", "No"}
	case YesNoCancelBtn:
		options = []string{"Yes", "No", "Cancel"}
	case RetryCancelBtn:
		options = []string{"Retry", "Cancel"}
	case AbortRetryIgnoreBtn:
		options = []string{"Abort", "Retry", "Ignore"}
	}

	fmt.Print("Options: ")
	for i, opt := range options {
		if i > 0 {
			fmt.Print(", ")
		}
		fmt.Printf("[%d] %s", i+1, opt)
	}
	fmt.Println()

	// Get user input
	var choice int
	fmt.Scanln(&choice)

	if choice < 1 || choice > len(options) {
		return MessageBoxResult{Err: fmt.Errorf("invalid choice")}
	}

	selected := options[choice-1]

	return MessageBoxResult{
		ButtonPressed: selected,
		Confirmed:     selected == "OK" || selected == "Yes" || selected == "Retry",
	}
}

// 4. Convenience Functions

// ShowInfo shows information message
func ShowInfo(title, message string) MessageBoxResult {
	return MessageBox(title, message, InfoMsg, OKBtn)
}

// ShowWarning shows warning message
func ShowWarning(title, message string) MessageBoxResult {
	return MessageBox(title, message, WarningMsg, OKBtn)
}

// ShowError shows error message
func ShowError(title, message string) MessageBoxResult {
	return MessageBox(title, message, ErrorMsg, OKBtn)
}

// ShowQuestion shows question with Yes/No
func ShowQuestion(title, message string) MessageBoxResult {
	result := MessageBox(title, message, QuestionMsg, YesNoBtn)
	return result
}

// ShowConfirm shows confirmation dialog
func ShowConfirm(title, message string) MessageBoxResult {
	result := MessageBox(title, message, QuestionMsg, OKCancelBtn)
	return result
}

// 5. Progress Dialog

// ProgressDialog shows progress for operations
type ProgressDialog struct {
	title      string
	total      int64
	current    int64
	cancelled bool
}

// NewProgressDialog creates progress dialog
func NewProgressDialog(title string, total int64) *ProgressDialog {
	return &ProgressDialog{
		title:   title,
		total:   total,
		current: 0,
	}
}

// Update updates progress
func (pd *ProgressDialog) Update(current int64) {
	pd.current = current

	// Clear line and show progress
	fmt.Printf("\r%s: ", pd.title)

	percentage := float64(current) / float64(pd.total) * 100
	barWidth := 40
	filled := int(float64(barWidth) * float64(current) / float64(pd.total))

	fmt.Print("[")
	for i := 0; i < barWidth; i++ {
		if i < filled {
			fmt.Print("=")
		} else {
			fmt.Print(" ")
		}
	}
	fmt.Printf("] %.1f%%", percentage)
}

// Complete marks progress as complete
func (pd *ProgressDialog) Complete() {
	pd.Update(pd.total)
	fmt.Println(" - Complete!")
}

// 6. Notification

// NotificationType defines notification type
type NotificationType int

const (
	NotificationInfo NotificationType = iota
	NotificationWarning
	NotificationError
	NotificationSuccess
)

// ShowNotification shows desktop notification
func ShowNotification(title, message string, notifType NotificationType) {
	// Terminal notification
	var icon string
	switch notifType {
	case NotificationInfo:
		icon = "ℹ️"
	case NotificationWarning:
		icon = "⚠️"
	case NotificationError:
		icon = "❌"
	case NotificationSuccess:
		icon = "✅"
	}

	fmt.Printf("\n%s %s: %s\n", icon, title, message)
}

// 7. Input Dialog

// InputDialogResult holds input dialog result
type InputDialogResult struct {
	Value string
	Err   error
}

// ShowInputDialog shows input dialog
func ShowInputDialog(title, prompt, defaultValue string) InputDialogResult {
	fmt.Printf("\n%s\n", title)
	fmt.Printf("%s", prompt)
	if defaultValue != "" {
		fmt.Printf(" [%s]", defaultValue)
	}
	fmt.Print(": ")

	var input string
	fmt.Scanln(&input)

	if input == "" {
		input = defaultValue
	}

	return InputDialogResult{Value: input}
}

// ShowPasswordDialog shows password input dialog
func ShowPasswordDialog(title, prompt string) InputDialogResult {
	fmt.Printf("\n%s\n", title)
	fmt.Printf("%s: ", prompt)

	// Note: In terminal, password won't be hidden
	// For real applications, use terminal password reading
	var input string
	fmt.Scanln(&input)

	return InputDialogResult{Value: input}
}

// 8. Select Dialog

// SelectDialogResult holds selection dialog result
type SelectDialogResult struct {
	SelectedIndex int
	SelectedValue string
	Err           error
}

// ShowSelectDialog shows selection dialog
func ShowSelectDialog(title string, options []string) SelectDialogResult {
	fmt.Printf("\n%s\n", title)

	for i, opt := range options {
		fmt.Printf("[%d] %s\n", i+1, opt)
	}

	fmt.Print("Select: ")
	var choice int
	fmt.Scanln(&choice)

	if choice < 1 || choice > len(options) {
		return SelectDialogResult{Err: fmt.Errorf("invalid choice")}
	}

	return SelectDialogResult{
		SelectedIndex: choice - 1,
		SelectedValue: options[choice-1],
	}
}

// 9. Dialog Builder

// DialogBuilder builds message dialogs
type DialogBuilder struct {
	title       string
	message     string
	msgType     MessageType
	buttons     MessageBoxButton
	onConfirm   func()
	onCancel    func()
	defaultAction func()
}

// NewDialogBuilder creates dialog builder
func NewDialogBuilder(title, message string) *DialogBuilder {
	return &DialogBuilder{
		title:   title,
		message: message,
		msgType: InfoMsg,
		buttons: OKBtn,
	}
}

func (db *DialogBuilder) WithType(msgType MessageType) *DialogBuilder {
	db.msgType = msgType
	return db
}

func (db *DialogBuilder) WithButtons(buttons MessageBoxButton) *DialogBuilder {
	db.buttons = buttons
	return db
}

func (db *DialogBuilder) OnConfirm(fn func()) *DialogBuilder {
	db.onConfirm = fn
	return db
}

func (db *DialogBuilder) OnCancel(fn func()) *DialogBuilder {
	db.onCancel = fn
	return db
}

func (db *DialogBuilder) Show() MessageBoxResult {
	result := MessageBox(db.title, db.message, db.msgType, db.buttons)

	if result.Confirmed && db.onConfirm != nil {
		db.onConfirm()
	} else if !result.Confirmed && db.onCancel != nil {
		db.onCancel()
	}

	return result
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go Message Box Examples ===\n")

	// 1. Info message
	fmt.Println("--- 1. Info Message ---")
	ShowInfo("Information", "This is an informational message")

	// 2. Warning message
	fmt.Println("\n--- 2. Warning Message ---")
	ShowWarning("Warning", "This is a warning message")

	// 3. Error message
	fmt.Println("\n--- 3. Error Message ---")
	ShowError("Error", "An error occurred!")

	// 4. Question dialog
	fmt.Println("\n--- 4. Question Dialog ---")
	result := ShowQuestion("Question", "Do you want to continue?")
	if result.Confirmed {
		fmt.Println("User chose Yes")
	} else {
		fmt.Println("User chose No")
	}

	// 5. Input dialog
	fmt.Println("\n--- 5. Input Dialog ---")
	input := ShowInputDialog("Name", "Enter your name", "")
	if input.Err == nil {
		fmt.Printf("Hello, %s!\n", input.Value)
	}

	// 6. Select dialog
	fmt.Println("\n--- 6. Select Dialog ---")
	selectResult := ShowSelectDialog("Choose Option", []string{"Option A", "Option B", "Option C"})
	if selectResult.Err == nil {
		fmt.Printf("Selected: %s\n", selectResult.SelectedValue)
	}

	// 7. Progress dialog
	fmt.Println("\n--- 7. Progress Dialog ---")
	progress := NewProgressDialog("Processing", 100)
	for i := 0; i <= 100; i += 10 {
		progress.Update(int64(i))
		time.Sleep(100 * time.Millisecond)
	}
	progress.Complete()

	// 8. Notification
	fmt.Println("
--- 8. Notification ---")
	ShowNotification("Success", "Operation completed successfully!", NotificationSuccess)

	// 9. Dialog builder
	fmt.Println("
--- 9. Dialog Builder ---")
	builderResult := NewDialogBuilder("Confirm Action", "Are you sure?").
		WithType(QuestionMsg).
		WithButtons(YesNoBtn).
		OnConfirm(func() {
			fmt.Println("Action confirmed!")
		}).
		Show()

	fmt.Printf("
Builder result: %v\n", builderResult.ButtonPressed)

	fmt.Println("
=== All Message Box Examples Completed ===")
	fmt.Println("Note: For full GUI functionality, install Fyne or Walk framework")
}

💻 Boîtes de Dialogue de Fichiers go

🟡 intermediate ⭐⭐⭐

Ouvrir et enregistrer des boîtes de dialogue de fichiers en utilisant les frameworks GUI Fyne ou Walk

⏱️ 30 min 🏷️ go, web, desktop features
Prerequisites: Intermediate Go, GUI framework
// Web Go File Dialog Examples
// Using Fyne and Walk frameworks for file dialogs

package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
)

// 1. Using Fyne Framework (Cross-platform)

// FyneFileDialogExample demonstrates file dialogs with Fyne
// Install: go get fyne.io/fyne/v2

/*
import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/widget"
)

func FyneOpenFileDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("File Dialog")

	// Create open file dialog
	fd := dialog.NewFileOpen(func(reader fyne.URIReadCloser, err error) {
		if err == nil && reader != nil {
			defer reader.Close()
			fmt.Printf("Opened file: %v\n", reader.URI())
		}
	}, myWindow)

	fd.SetFilter(storage.NewExtensionFileFilter([]string{".txt", ".go"}))
	fd.Show()

	// Keep window running
	myWindow.ShowAndRun()
}

func FyneSaveFileDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Save Dialog")

	// Create save file dialog
	sd := dialog.NewFileSave(func(writer fyne.URIWriteCloser, err error) {
		if err == nil && writer != nil {
			defer writer.Close()
			writer.Write([]byte("Hello, World!"))
			fmt.Printf("Saved file: %v\n", writer.URI())
		}
	}, myWindow)

	sd.SetFileName("untitled.txt")
	sd.Show()

	myWindow.ShowAndRun()
}

func FyneSelectFolderDialog() {
	myApp := app.New()
	myWindow := myApp.NewWindow("Folder Dialog")

	// Create folder select dialog
	fd := dialog.NewFolderOpen(func(uri fyne.ListableURI, err error) {
		if err == nil && uri != nil {
			fmt.Printf("Selected folder: %v\n", uri)
		}
	}, myWindow)

	fd.Show()
	myWindow.ShowAndRun()
}
*/

// 2. Using Walk Framework (Windows)

// WalkFileDialogExample demonstrates file dialogs with Walk
// Install: go get github.com/lxn/walk

/*
import (
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
)

func WalkOpenFileDialog() {
	var dlg *walk.Dialog
	var text *walk.TextEdit

	MainWindow{
		Title:  "File Dialog",
		MinSize: Size{400, 300},
		Layout:  VBox{},
		Children: []Widget{
			PushButton{
				Text: "Open File",
				OnClicked: func() {
					filePath, err := walk.FileDialog{
						Filter:   "Text Files (*.txt)|*.txt|All Files (*.*)|*.*",
						Title:    "Open File",
					}.ShowOpen(nil)

					if err == nil && filePath != "" {
						text.SetText(filePath)
						fmt.Printf("Opened: %s\n", filePath)
					}
				},
			},
			TextEdit{AssignTo: &text},
		},
	}.Create()
}

func WalkSaveFileDialog() {
	var fileName *walk.LineEdit

	MainWindow{
		Title:  "Save Dialog",
		Layout: VBox{},
		Children: []Widget{
			PushButton{
				Text: "Save File",
				OnClicked: func() {
					filePath, err := walk.FileDialog{
						Filter:   "Text Files (*.txt)|*.txt",
						Title:    "Save File",
					}.ShowSave(nil)

					if err == nil && filePath != "" {
						fmt.Printf("Save to: %s\n", filePath)
					}
				},
			},
			LineEdit{AssignTo: &fileName},
		},
	}.Create()
}
*/

// 3. Cross-Platform File Dialog Wrapper

// FileDialogOptions holds options for file dialogs
type FileDialogOptions struct {
	Title       string
	Filter      string
	InitialDir  string
	DefaultName string
}

// FileDialogResult holds file dialog result
type FileDialogResult struct {
	FilePath string
	FileName string
	Dir      string
	Err      error
}

// OpenFileDialog opens file selection dialog
func OpenFileDialog(options FileDialogOptions) FileDialogResult {
	result := FileDialogResult{}

	// Check if running in terminal environment
	if os.Getenv("TERM") != "" || os.Getenv("TERM_PROGRAM") != "" {
		// Terminal-based file selection
		return openTerminalFileDialog(options)
	}

	// Try GUI frameworks
	// Note: In a real application, you'd use Fyne or Walk here
	result.Err = fmt.Errorf("no GUI framework available")

	return result
}

// SaveFileDialog opens save file dialog
func SaveFileDialog(options FileDialogOptions) FileDialogResult {
	result := FileDialogResult{}

	// Check environment
	if os.Getenv("TERM") != "" {
		return saveTerminalFileDialog(options)
	}

	result.Err = fmt.Errorf("no GUI framework available")
	return result
}

// 4. Terminal-Based File Dialog (Fallback)

func openTerminalFileDialog(options FileDialogOptions) FileDialogResult {
	fmt.Printf("%s\n", options.Title)
	fmt.Println("Enter file path (or 'cancel'): ")

	var input string
	fmt.Scanln(&input)

	if input == "cancel" {
		return FileDialogResult{Err: fmt.Errorf("cancelled")}
	}

	if _, err := os.Stat(input); err != nil {
		return FileDialogResult{Err: err}
	}

	return FileDialogResult{
		FilePath: input,
		FileName: filepath.Base(input),
		Dir:      filepath.Dir(input),
	}
}

func saveTerminalFileDialog(options FileDialogOptions) FileDialogResult {
	fmt.Printf("%s\n", options.Title)
	defaultName := options.DefaultName
	if defaultName == "" {
		defaultName = "untitled.txt"
	}

	fmt.Printf("Enter save path [%s]: ", defaultName)
	var input string
	fmt.Scanln(&input)

	if input == "" {
		input = defaultName
	}

	return FileDialogResult{
		FilePath: input,
		FileName: filepath.Base(input),
		Dir:      filepath.Dir(input),
	}
}

// 5. File Dialog with Validation

// OpenFileDialogWithValidation opens dialog and validates file
func OpenFileDialogWithValidation(options FileDialogOptions, validateFunc func(string) error) FileDialogResult {
	result := OpenFileDialog(options)

	if result.Err != nil {
		return result
	}

	if validateFunc != nil {
		if err := validateFunc(result.FilePath); err != nil {
			return FileDialogResult{Err: err}
		}
	}

	return result
}

// ValidateFileExtension validates file extension
func ValidateFileExtension(extensions []string) func(string) error {
	return func(filePath string) error {
		ext := filepath.Ext(filePath)
		for _, validExt := range extensions {
			if ext == validExt {
				return nil
			}
		}
		return fmt.Errorf("invalid extension: %s", ext)
	}
}

// ValidateFileSize validates file size
func ValidateFileSize(maxSizeMB int64) func(string) error {
	return func(filePath string) error {
		info, err := os.Stat(filePath)
		if err != nil {
			return err
		}

		sizeMB := info.Size() / (1024 * 1024)
		if sizeMB > maxSizeMB {
			return fmt.Errorf("file too large: %dMB (max %dMB)", sizeMB, maxSizeMB)
		}

		return nil
	}
}

// 6. Batch File Selection

// BatchFileDialogResult holds multiple file selection results
type BatchFileDialogResult struct {
	FilePaths []string
	Err       error
}

// OpenMultipleFilesDialog opens dialog for multiple file selection
func OpenMultipleFilesDialog(options FileDialogOptions) BatchFileDialogResult {
	result := BatchFileDialogResult{}

	fmt.Printf("%s (Multiple files)\n", options.Title)
	fmt.Println("Enter file paths (one per line, empty line to finish):")

	var filePaths []string
	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		path := scanner.Text()
		if path == "" {
			break
		}
		filePaths = append(filePaths, path)
	}

	if len(filePaths) == 0 {
		result.Err = fmt.Errorf("no files selected")
		return result
	}

	// Validate all files
	for _, path := range filePaths {
		if _, err := os.Stat(path); err != nil {
			result.Err = fmt.Errorf("invalid file: %s - %v", path, err)
			return result
		}
	}

	result.FilePaths = filePaths
	return result
}

// 7. Recent Files Management

// RecentFiles manages recent file list
type RecentFiles struct {
	files []string
	max   int
}

// NewRecentFiles creates recent files manager
func NewRecentFiles(maxFiles int) *RecentFiles {
	return &RecentFiles{
		files: []string{},
		max:   maxFiles,
	}
}

// Add adds file to recent list
func (rf *RecentFiles) Add(filePath string) {
	// Remove if already exists
	for i, f := range rf.files {
		if f == filePath {
			rf.files = append(rf.files[:i], rf.files[i+1:]...)
			break
		}
	}

	// Add to front
	rf.files = append([]string{filePath}, rf.files...)

	// Limit size
	if len(rf.files) > rf.max {
		rf.files = rf.files[:rf.max]
	}
}

// GetFiles returns recent files list
func (rf *RecentFiles) GetFiles() []string {
	return rf.files
}

// SaveToFile saves recent files to file
func (rf *RecentFiles) SaveToFile(filePath string) error {
	file, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	for _, f := range rf.files {
		file.WriteString(f + "\n")
	}

	return nil
}

// LoadFromFile loads recent files from file
func (rf *RecentFiles) LoadFromFile(filePath string) error {
	file, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		rf.Add(scanner.Text())
	}

	return scanner.Err()
}

// 8. File Dialog Presets

// OpenImageDialog opens image file dialog
func OpenImageDialog() FileDialogResult {
	return OpenFileDialog(FileDialogOptions{
		Title:  "Open Image",
		Filter: "*.png;*.jpg;*.jpeg;*.gif;*.bmp",
	})
}

// SaveTextFileDialog opens text file save dialog
func SaveTextFileDialog() FileDialogResult {
	return SaveFileDialog(FileDialogOptions{
		Title:       "Save Text File",
		Filter:      "*.txt",
		DefaultName: "untitled.txt",
	})
}

// OpenCodeFileDialog opens code file dialog
func OpenCodeFileDialog() FileDialogResult {
	return OpenFileDialog(FileDialogOptions{
		Title:  "Open Code File",
		Filter: "*.go;*.js;*.py;*.java;*.cpp",
	})
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go File Dialog Examples ===\n")

	// 1. Open file dialog
	fmt.Println("--- 1. Open File Dialog ---")
	result := OpenFileDialog(FileDialogOptions{
		Title:  "Select a File",
		Filter: "*.txt",
	})
	if result.Err == nil {
		fmt.Printf("Selected: %s\n", result.FilePath)
	}

	// 2. Save file dialog
	fmt.Println("\n--- 2. Save File Dialog ---")
	saveResult := SaveFileDialog(FileDialogOptions{
		Title:       "Save File",
		DefaultName: "output.txt",
	})
	if saveResult.Err == nil {
		fmt.Printf("Save to: %s\n", saveResult.FilePath)
	}

	// 3. File dialog with validation
	fmt.Println("\n--- 3. File Dialog with Validation ---")
	validated := OpenFileDialogWithValidation(
		FileDialogOptions{Title: "Select Text File"},
		ValidateFileExtension([]string{".txt"}),
	)
	if validated.Err != nil {
		fmt.Printf("Validation error: %v\n", validated.Err)
	}

	// 4. Multiple files
	fmt.Println("\n--- 4. Multiple Files ---")
	multi := OpenMultipleFilesDialog(FileDialogOptions{
		Title: "Select Files",
	})
	if multi.Err == nil {
		fmt.Printf("Selected %d files\n", len(multi.FilePaths))
	}

	// 5. Recent files
	fmt.Println("\n--- 5. Recent Files ---")
	recent := NewRecentFiles(5)
	recent.Add("file1.txt")
	recent.Add("file2.txt")
	recent.Add("file3.txt")
	fmt.Printf("Recent files: %v\n", recent.GetFiles())

	// 6. Presets
	fmt.Println("\n--- 6. Preset Dialogs ---")
	imageResult := OpenImageDialog()
	if imageResult.Err == nil {
		fmt.Printf("Image: %s\n", imageResult.FileName)
	}

	fmt.Println("\n=== All File Dialog Examples Completed ===")
	fmt.Println("Note: For full GUI functionality, install Fyne or Walk framework")
}

💻 Barre d'État Système go

🔴 complex ⭐⭐⭐⭐

Afficher une icône de barre d'état système avec menu et notifications

⏱️ 30 min 🏷️ go, web, desktop features
Prerequisites: Intermediate Go, GUI framework, goroutines
// Web Go System Tray Examples
// System tray icon with menu using Fyne or other frameworks

package main

import (
	"fmt"
	"time"
)

// 1. Using Fyne Framework

/*
import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/menu"
	"fyne.io/fyne/v2/storage"
)

func FyneSystemTray() {
	myApp := app.New()
	myWindow := myApp.NewWindow("System Tray")

	// Create system tray
	if desk, ok := myApp.(desktop.App); ok {
		// Set system tray icon
		icon := storage.NewFileURI("icon.png")
		desk.SetSystemTrayIcon(icon)
		desk.SetSystemTrayMenu(menu.New(
			menu.NewItem("Show", func() { myWindow.Show() }),
			menu.NewItem("Hide", func() { myWindow.Hide() }),
			menu.NewSeparator(),
			menu.NewItem("Quit", func() { myApp.Quit() }),
		))
	}

	myWindow.ShowAndRun()
}
*/

// 2. Using Systray Framework (Cross-platform)

/*
import (
	"github.com/getlantern/systray"
)

func SystrayExample() {
	systray.Run(onReady, onExit)
}

func onReady() {
	// Set icon
	// iconBytes, _ := ioutil.ReadFile("icon.ico")
	// systray.SetIcon(iconBytes)

	systray.SetTitle("My App")
	systray.SetTooltip("My Application")

	// Add menu items
	mQuit := systray.AddMenuItem("Quit", "Quit the whole app")
	mShow := systray.AddMenuItem("Show", "Show window")
	mHide := systray.AddMenuItem("Hide", "Hide window")

	// Handle menu clicks
	go func() {
		for {
			select {
			case <-mShow.ClickedCh:
				fmt.Println("Show clicked")
			case <-mHide.ClickedCh:
				fmt.Println("Hide clicked")
			case <-mQuit.ClickedCh:
				fmt.Println("Quitting...")
				systray.Quit()
				return
			}
		}
	}()
}

func onExit() {
	fmt.Println("Exiting systray")
}
*/

// 3. Simulated System Tray (Terminal)

// TrayIcon represents a system tray icon
type TrayIcon struct {
	title      string
	tooltip    string
	menuItems  []TrayMenuItem
	visible    bool
	running    bool
	onQuit     func()
	notification string
}

// TrayMenuItem represents a menu item
type TrayMenuItem struct {
	Title    string
	Tooltip  string
	Disabled bool
	OnClick  func()
}

// NewTrayIcon creates new tray icon
func NewTrayIcon(title, tooltip string) *TrayIcon {
	return &TrayIcon{
		title:     title,
		tooltip:   tooltip,
		menuItems: []TrayMenuItem{},
		visible:   false,
		running:   false,
	}
}

// SetTitle sets tray icon title
func (ti *TrayIcon) SetTitle(title string) {
	ti.title = title
	fmt.Printf("[Tray] Title set to: %s\n", title)
}

// SetTooltip sets tooltip
func (ti *TrayIcon) SetTooltip(tooltip string) {
	ti.tooltip = tooltip
	fmt.Printf("[Tray] Tooltip set to: %s\n", tooltip)
}

// AddMenuItem adds menu item
func (ti *TrayIcon) AddMenuItem(title, tooltip string, onClick func()) {
	item := TrayMenuItem{
		Title:   title,
		Tooltip: tooltip,
		OnClick: onClick,
	}
	ti.menuItems = append(ti.menuItems, item)
	fmt.Printf("[Tray] Menu item added: %s\n", title)
}

// AddSeparator adds separator
func (ti *TrayIcon) AddSeparator() {
	fmt.Println("[Tray] Separator added")
}

// Show shows tray icon
func (ti *TrayIcon) Show() {
	ti.visible = true
	ti.running = true
	fmt.Printf("[Tray] Icon shown: %s\n", ti.title)
	ti.run()
}

// Hide hides tray icon
func (ti *TrayIcon) Hide() {
	ti.visible = false
	fmt.Println("[Tray] Icon hidden")
}

// Quit quits tray icon
func (ti *TrayIcon) Quit() {
	ti.running = false
	if ti.onQuit != nil {
		ti.onQuit()
	}
	fmt.Println("[Tray] Quit")
}

// OnQuit sets quit handler
func (ti *TrayIcon) OnQuit(fn func()) {
	ti.onQuit = fn
}

// ShowNotification shows notification
func (ti *TrayIcon) ShowNotification(title, message string) {
	ti.notification = fmt.Sprintf("%s: %s", title, message)
	fmt.Printf("[Tray] Notification: %s\n", ti.notification)
}

// run runs tray icon loop
func (ti *TrayIcon) run() {
	fmt.Println("[Tray] Running... (Press Ctrl+C to quit)")
	fmt.Println("Menu items:")

	for i, item := range ti.menuItems {
		fmt.Printf("  [%d] %s\n", i+1, item.Title)
	}

	// Simple menu loop
	for ti.running {
		time.Sleep(100 * time.Millisecond)
	}
}

// 4. Tray Menu Manager

// TrayMenu manages tray menu
type TrayMenu struct {
	items []TrayMenuItem
}

// NewTrayMenu creates tray menu
func NewTrayMenu() *TrayMenu {
	return &TrayMenu{
		items: []TrayMenuItem{},
	}
}

// AddItem adds menu item
func (tm *TrayMenu) AddItem(title, tooltip string, onClick func()) {
	tm.items = append(tm.items, TrayMenuItem{
		Title:   title,
		Tooltip: tooltip,
		OnClick: onClick,
	})
}

// AddSubmenu adds submenu
func (tm *TrayMenu) AddSubmenu(title string) *TrayMenu {
	submenu := &TrayMenu{}
	fmt.Printf("[Tray] Submenu added: %s\n", title)
	return submenu
}

// AddSeparator adds separator
func (tm *TrayMenu) AddSeparator() {
	fmt.Println("[Tray] Separator added")
}

// 5. Tray Application

// TrayApp represents a complete tray application
type TrayApp struct {
	tray     *TrayIcon
	menu     *TrayMenu
	running  bool
}

// NewTrayApp creates new tray application
func NewTrayApp(title, tooltip string) *TrayApp {
	tray := NewTrayIcon(title, tooltip)
	return &TrayApp{
		tray:    tray,
		menu:    NewTrayMenu(),
		running: false,
	}
}

// AddMenuItem adds menu item
func (ta *TrayApp) AddMenuItem(title, tooltip string, onClick func()) {
	ta.tray.AddMenuItem(title, tooltip, onClick)
}

// AddSeparator adds separator
func (ta *TrayApp) AddSeparator() {
	ta.tray.AddSeparator()
}

// SetOnQuit sets quit handler
func (ta *TrayApp) SetOnQuit(fn func()) {
	ta.tray.OnQuit(fn)
}

// Run runs tray application
func (ta *TrayApp) Run() {
	ta.running = true
	ta.tray.Show()
}

// ShowNotification shows notification
func (ta *TrayApp) ShowNotification(title, message string) {
	ta.tray.ShowNotification(title, message)
}

// Quit quits application
func (ta *TrayApp) Quit() {
	ta.running = false
	ta.tray.Quit()
}

// 6. Tray Builder

// TrayBuilder builds tray applications
type TrayBuilder struct {
	app *TrayApp
}

// NewTrayBuilder creates tray builder
func NewTrayBuilder(title, tooltip string) *TrayBuilder {
	return &TrayBuilder{
		app: NewTrayApp(title, tooltip),
	}
}

func (tb *TrayBuilder) WithItem(title, tooltip string, onClick func()) *TrayBuilder {
	tb.app.AddMenuItem(title, tooltip, onClick)
	return tb
}

func (tb *TrayBuilder) WithSeparator() *TrayBuilder {
	tb.app.AddSeparator()
	return tb
}

func (tb *TrayBuilder) OnQuit(fn func()) *TrayBuilder {
	tb.app.SetOnQuit(fn)
	return tb
}

func (tb *TrayBuilder) Build() *TrayApp {
	return tb.app
}

// 7. Advanced Tray Features

// TrayStatus holds tray status
type TrayStatus struct {
	Enabled   bool
	Tooltip   string
	IconIndex int
}

// UpdateStatus updates tray status
func (ta *TrayApp) UpdateStatus(status TrayStatus) {
	if status.Tooltip != "" {
		ta.tray.SetTooltip(status.Tooltip)
	}
	fmt.Printf("[Tray] Status updated\n")
}

// SetIcon sets tray icon
func (ta *TrayApp) SetIcon(iconPath string) {
	fmt.Printf("[Tray] Icon set to: %s\n", iconPath)
}

// ToggleVisibility toggles tray visibility
func (ta *TrayApp) ToggleVisibility() {
	fmt.Println("[Tray] Visibility toggled")
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go System Tray Examples ===\n")

	// 1. Basic tray icon
	fmt.Println("--- 1. Basic Tray Icon ---")
	tray := NewTrayIcon("My App", "My Application")
	tray.AddMenuItem("Show", "Show window", func() {
		fmt.Println("Show clicked")
	})
	tray.AddMenuItem("Hide", "Hide window", func() {
		fmt.Println("Hide clicked")
	})
	tray.AddSeparator()
	tray.AddMenuItem("Quit", "Quit application", func() {
		fmt.Println("Quit clicked")
		tray.Quit()
	})
	tray.OnQuit(func() {
		fmt.Println("Cleanup on quit")
	})

	// Simulate running (in real app, this would be goroutine)
	fmt.Println("Tray icon created (simulated)")
	tray.running = true
	time.Sleep(1 * time.Second)
	tray.Quit()

	// 2. Tray application
	fmt.Println("
--- 2. Tray Application ---")
	app := NewTrayApp("Tray App", "System Tray Application")
	app.AddMenuItem("Open", "Open application", func() {
		fmt.Println("Open clicked")
	})
	app.AddMenuItem("Settings", "Open settings", func() {
		fmt.Println("Settings clicked")
	})
	app.AddSeparator()
	app.SetOnQuit(func() {
		fmt.Println("Application quitting")
	})

	fmt.Println("Tray application created (simulated)")

	// 3. Tray builder
	fmt.Println("
--- 3. Tray Builder ---")
	builtApp := NewTrayBuilder("Builder App", "Built with Builder").
		WithItem("Start", "Start service", func() {
			fmt.Println("Service started")
		}).
		WithItem("Stop", "Stop service", func() {
			fmt.Println("Service stopped")
		}).
		WithSeparator().
		WithItem("Exit", "Exit application", func() {
			fmt.Println("Exiting")
		}).
		OnQuit(func() {
			fmt.Println("Builder cleanup")
		}).
		Build()

	fmt.Println("Built app created (simulated)")

	// 4. Status update
	fmt.Println("
--- 4. Status Update ---")
	builtApp.UpdateStatus(TrayStatus{
		Enabled: true,
		Tooltip: "Running",
	})

	// 5. Notification
	fmt.Println("
--- 5. Notification ---")
	builtApp.ShowNotification("Update Available", "Version 2.0 is ready")

	// 6. Menu manager
	fmt.Println("
--- 6. Menu Manager ---")
	menu := NewTrayMenu()
	menu.AddItem("File", "File operations", func() {
		fmt.Println("File menu")
	})
	menu.AddItem("Edit", "Edit operations", func() {
		fmt.Println("Edit menu")
	})
	menu.AddSeparator()
	menu.AddItem("View", "View options", func() {
		fmt.Println("View menu")
	})

	fmt.Printf("Menu created with %d items\n", len(menu.items))

	fmt.Println("
=== All System Tray Examples Completed ===")
	fmt.Println("Note: For full system tray functionality, install Systray or Fyne framework")
}