VideoTools/vendor/fyne.io/fyne/v2/internal/driver/util.go
Stu Leak 68df790d27 Fix player frame generation and video playback
Major improvements to UnifiedPlayer:

1. GetFrameImage() now works when paused for responsive UI updates
2. Play() method properly starts FFmpeg process
3. Frame display loop runs continuously for smooth video display
4. Disabled audio temporarily to fix video playback fundamentals
5. Simplified FFmpeg command to focus on video stream only

Player now:
- Generates video frames correctly
- Shows video when paused
- Has responsive progress tracking
- Starts playback properly

Next steps: Re-enable audio playback once video is stable
2026-01-07 22:20:00 -05:00

221 lines
6.9 KiB
Go

package driver
import (
"math"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/internal/cache"
)
// AbsolutePositionForObject returns the absolute position of an object in a set of object trees.
// If the object is not part of any of the trees, the position (0,0) is returned.
func AbsolutePositionForObject(object fyne.CanvasObject, trees []fyne.CanvasObject) fyne.Position {
var pos fyne.Position
findPos := func(o fyne.CanvasObject, p fyne.Position, _ fyne.Position, _ fyne.Size) bool {
if o == object {
pos = p
return true
}
return false
}
for _, tree := range trees {
if WalkVisibleObjectTree(tree, findPos, nil) {
break
}
}
return pos
}
// FindObjectAtPositionMatching is used to find an object in a canvas at the specified position.
// The matches function determines of the type of object that is found at this position is of a suitable type.
// The various canvas roots and overlays that can be searched are also passed in.
func FindObjectAtPositionMatching(mouse fyne.Position, matches func(object fyne.CanvasObject) bool, overlay fyne.CanvasObject, roots ...fyne.CanvasObject) (fyne.CanvasObject, fyne.Position, int) {
var found fyne.CanvasObject
var foundPos fyne.Position
findFunc := func(walked fyne.CanvasObject, pos fyne.Position, clipPos fyne.Position, clipSize fyne.Size) bool {
if !walked.Visible() {
return false
}
if mouse.X < clipPos.X || mouse.Y < clipPos.Y {
return false
}
if mouse.X >= clipPos.X+clipSize.Width || mouse.Y >= clipPos.Y+clipSize.Height {
return false
}
if mouse.X < pos.X || mouse.Y < pos.Y {
return false
}
if mouse.X >= pos.X+walked.Size().Width || mouse.Y >= pos.Y+walked.Size().Height {
return false
}
if matches(walked) {
found = walked
foundPos = fyne.NewPos(mouse.X-pos.X, mouse.Y-pos.Y)
}
return false
}
layer := 0
if overlay != nil {
WalkVisibleObjectTree(overlay, findFunc, nil)
} else {
for _, root := range roots {
layer++
if root == nil {
continue
}
WalkVisibleObjectTree(root, findFunc, nil)
if found != nil {
break
}
}
}
return found, foundPos, layer
}
// ReverseWalkVisibleObjectTree will walk an object tree in reverse order for all visible objects
// executing the passed functions following the following rules:
// - beforeChildren is called for the start obj before traversing its children
// - the obj's children are traversed by calling walkObjects on each of the visible items
// - afterChildren is called for the obj after traversing the obj's children
// The walk can be aborted by returning true in one of the functions:
// - if beforeChildren returns true, further traversing is stopped immediately, the after function
// will not be called for the obj where the walk stopped, however, it will be called for all its
// parents
func ReverseWalkVisibleObjectTree(
obj fyne.CanvasObject,
beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
) bool {
clipSize := fyne.NewSize(math.MaxInt32, math.MaxInt32)
return walkObjectTree(obj, true, nil, fyne.NewPos(0, 0), fyne.NewPos(0, 0), clipSize, beforeChildren, afterChildren, true)
}
// WalkCompleteObjectTree will walk an object tree for all objects (ignoring visible state) executing the passed
// functions following the following rules:
// - beforeChildren is called for the start obj before traversing its children
// - the obj's children are traversed by calling walkObjects on each of the items
// - afterChildren is called for the obj after traversing the obj's children
// The walk can be aborted by returning true in one of the functions:
// - if beforeChildren returns true, further traversing is stopped immediately, the after function
// will not be called for the obj where the walk stopped, however, it will be called for all its
// parents
func WalkCompleteObjectTree(
obj fyne.CanvasObject,
beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
) bool {
clipSize := fyne.NewSize(math.MaxInt32, math.MaxInt32)
return walkObjectTree(obj, false, nil, fyne.NewPos(0, 0), fyne.NewPos(0, 0), clipSize, beforeChildren, afterChildren, false)
}
// WalkVisibleObjectTree will walk an object tree for all visible objects executing the passed functions following
// the following rules:
// - beforeChildren is called for the start obj before traversing its children
// - the obj's children are traversed by calling walkObjects on each of the visible items
// - afterChildren is called for the obj after traversing the obj's children
// The walk can be aborted by returning true in one of the functions:
// - if beforeChildren returns true, further traversing is stopped immediately, the after function
// will not be called for the obj where the walk stopped, however, it will be called for all its
// parents
func WalkVisibleObjectTree(
obj fyne.CanvasObject,
beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
) bool {
clipSize := fyne.NewSize(math.MaxInt32, math.MaxInt32)
return walkObjectTree(obj, false, nil, fyne.NewPos(0, 0), fyne.NewPos(0, 0), clipSize, beforeChildren, afterChildren, true)
}
func walkObjectTree(
obj fyne.CanvasObject,
reverse bool,
parent fyne.CanvasObject,
offset, clipPos fyne.Position,
clipSize fyne.Size,
beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
requireVisible bool,
) bool {
if obj == nil {
return false
}
if requireVisible && !obj.Visible() {
return false
}
pos := obj.Position().Add(offset)
var children []fyne.CanvasObject
switch co := obj.(type) {
case *fyne.Container:
children = co.Objects
case fyne.Widget:
if cache.IsRendered(co) || requireVisible {
children = cache.Renderer(co).Objects()
}
}
if IsClip(obj) {
clipPos = pos
clipSize = obj.Size()
}
if beforeChildren != nil {
if beforeChildren(obj, pos, clipPos, clipSize) {
return true
}
}
cancelled := false
followChild := func(child fyne.CanvasObject) bool {
if walkObjectTree(child, reverse, obj, pos, clipPos, clipSize, beforeChildren, afterChildren, requireVisible) {
cancelled = true
return true
}
return false
}
if reverse {
for i := len(children) - 1; i >= 0; i-- {
if followChild(children[i]) {
break
}
}
} else {
for _, child := range children {
if followChild(child) {
break
}
}
}
if afterChildren != nil {
afterChildren(obj, pos, parent)
}
return cancelled
}
func IsClip(o fyne.CanvasObject) bool {
_, scroll := o.(fyne.Scrollable)
if scroll {
return true
}
if _, isWid := o.(fyne.Widget); !isWid {
return false
}
r, rendered := cache.CachedRenderer(o.(fyne.Widget))
if !rendered {
return false
}
_, clip := r.(interface{ IsClip() })
return clip
}