VideoTools/internal/ui/tappable.go
Stu e25f0c4284 Add video interaction: double-click fullscreen and right-click play/pause
Implements intuitive video player interactions for enhanced user experience.

Video Interaction Features:
- Double-click video area to toggle fullscreen
- Right-click video area to play/pause
- Single-click does nothing (reserved for future use)
- Transparent tappable overlay on video canvas

Implementation:
- Created TappableOverlay widget in internal/ui/tappable.go
- Invisible widget captures tap, double-tap, and secondary-tap events
- Extends widget.BaseWidget for Fyne compatibility
- Added overlay to stage container after video image

User Experience:
- Double-click anywhere on video → instant fullscreen
- Right-click anywhere on video → quick play/pause
- Works alongside existing keyboard shortcuts (F11, Space, ESC)
- Play button icon updates when using right-click

Technical Details:
- TappableOverlay has no visual representation
- Implements Tapped(), DoubleTapped(), TappedSecondary()
- Callbacks are configurable per instance
- Positioned as top layer in container.NewMax() stack

Usage:
1. Load a video
2. Double-click video to enter fullscreen
3. Right-click to pause/play
4. ESC or F11 to exit fullscreen

Next Steps:
- Consider adding single-click functionality
- Add visual feedback for interactions
- Implement mouse cursor auto-hide in fullscreen

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-09 11:23:26 -05:00

65 lines
1.7 KiB
Go

package ui
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/widget"
)
// TappableOverlay is an invisible widget that captures tap and double-tap events
type TappableOverlay struct {
widget.BaseWidget
OnTapped func()
OnDoubleTapped func()
OnSecondaryTapped func()
}
// NewTappableOverlay creates a new tappable overlay
func NewTappableOverlay(onTapped, onDoubleTapped, onSecondaryTapped func()) *TappableOverlay {
t := &TappableOverlay{
OnTapped: onTapped,
OnDoubleTapped: onDoubleTapped,
OnSecondaryTapped: onSecondaryTapped,
}
t.ExtendBaseWidget(t)
return t
}
// Tapped handles single tap events
func (t *TappableOverlay) Tapped(*fyne.PointEvent) {
if t.OnTapped != nil {
t.OnTapped()
}
}
// TappedSecondary handles right-click events
func (t *TappableOverlay) TappedSecondary(*fyne.PointEvent) {
if t.OnSecondaryTapped != nil {
t.OnSecondaryTapped()
}
}
// DoubleTapped handles double-tap events
func (t *TappableOverlay) DoubleTapped(*fyne.PointEvent) {
if t.OnDoubleTapped != nil {
t.OnDoubleTapped()
}
}
// CreateRenderer implements fyne.Widget
func (t *TappableOverlay) CreateRenderer() fyne.WidgetRenderer {
return &tappableRenderer{}
}
// MinSize returns minimum size (should fill parent)
func (t *TappableOverlay) MinSize() fyne.Size {
return fyne.NewSize(1, 1)
}
type tappableRenderer struct{}
func (r *tappableRenderer) Layout(size fyne.Size) {}
func (r *tappableRenderer) MinSize() fyne.Size { return fyne.NewSize(1, 1) }
func (r *tappableRenderer) Refresh() {}
func (r *tappableRenderer) Objects() []fyne.CanvasObject { return nil }
func (r *tappableRenderer) Destroy() {}