summaryrefslogtreecommitdiff
path: root/internal/gui/widgets.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-16 13:13:38 +0300
committerPaul Buetow <paul@buetow.org>2025-07-16 13:13:38 +0300
commit7187e7464f16a9d2991ba2da3c672fdb3cf5de72 (patch)
tree208d8e301dc55512a078f836f4f0c9ad2a927427 /internal/gui/widgets.go
parentb105333c061ea165b3b79317415cbb8b9cfb7c75 (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.go122
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