diff options
| author | Paul Buetow <paul@buetow.org> | 2025-07-16 13:13:38 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-07-16 13:13:38 +0300 |
| commit | 7187e7464f16a9d2991ba2da3c672fdb3cf5de72 (patch) | |
| tree | 208d8e301dc55512a078f836f4f0c9ad2a927427 /internal/gui/widgets.go | |
| parent | b105333c061ea165b3b79317415cbb8b9cfb7c75 (diff) | |
feat: add Fyne GUI mode with interactive flashcard management
- Add --gui flag to launch interactive GUI mode
- Implement word navigation with prev/next buttons through existing cards
- Add delete functionality to remove unwanted flashcards
- Add fine-grained regeneration (image-only, audio-only, or both)
- Implement audio playback using mpg123 on Linux
- Auto-load first word on startup if cards exist
- Save translation files for navigation persistence
- Use DALL-E 2 with 512x512 images (half size)
- Update audio speed to 0.9 (from 0.8)
- Add comprehensive GUI documentation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'internal/gui/widgets.go')
| -rw-r--r-- | internal/gui/widgets.go | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/internal/gui/widgets.go b/internal/gui/widgets.go new file mode 100644 index 0000000..eb9818c --- /dev/null +++ b/internal/gui/widgets.go @@ -0,0 +1,122 @@ +package gui + +import ( + "fmt" + "image" + _ "image/gif" + _ "image/jpeg" + _ "image/png" + "os" + "path/filepath" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" +) + +// ImageDisplay is a custom widget for displaying images +type ImageDisplay struct { + widget.BaseWidget + + container *fyne.Container + imageCanvas *canvas.Image + imageLabel *widget.Label + + currentImage string +} + +// NewImageDisplay creates a new image display widget +func NewImageDisplay() *ImageDisplay { + d := &ImageDisplay{} + + // Create image canvas + d.imageCanvas = canvas.NewImageFromResource(nil) + d.imageCanvas.FillMode = canvas.ImageFillContain + d.imageCanvas.SetMinSize(fyne.NewSize(200, 150)) // Half the size + + // Create label + d.imageLabel = widget.NewLabel("No image") + d.imageLabel.Alignment = fyne.TextAlignCenter + + // Create main container - no navigation buttons here + d.container = container.NewBorder( + nil, + d.imageLabel, + nil, nil, + d.imageCanvas, + ) + + d.ExtendBaseWidget(d) + return d +} + +// CreateRenderer implements fyne.Widget +func (d *ImageDisplay) CreateRenderer() fyne.WidgetRenderer { + return widget.NewSimpleRenderer(d.container) +} + +// SetImage sets a single image to display +func (d *ImageDisplay) SetImage(imagePath string) { + if imagePath == "" { + d.Clear() + return + } + + d.currentImage = imagePath + + // Load image from file + file, err := os.Open(imagePath) + if err != nil { + d.imageLabel.SetText(fmt.Sprintf("Error loading image: %v", err)) + return + } + defer file.Close() + + img, _, err := image.Decode(file) + if err != nil { + d.imageLabel.SetText(fmt.Sprintf("Error decoding image: %v", err)) + return + } + + // Update canvas + d.imageCanvas.Image = img + d.imageCanvas.Refresh() + + // Update label + d.imageLabel.SetText(filepath.Base(imagePath)) +} + +// SetImages sets multiple images but only displays the first one +func (d *ImageDisplay) SetImages(images []string) { + if len(images) > 0 { + d.SetImage(images[0]) + } else { + d.Clear() + } +} + +// Clear clears the display +func (d *ImageDisplay) Clear() { + d.currentImage = "" + d.imageCanvas.Image = nil + d.imageCanvas.Refresh() + d.imageLabel.SetText("No image") +} + + +// ResourceFromPath creates a Fyne resource from a file path +func ResourceFromPath(path string) (fyne.Resource, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + return fyne.NewStaticResource(filepath.Base(path), data), nil +}
\ No newline at end of file |
