adam-gui/vendor/fyne.io/fyne/v2/internal/driver/util.go

203 lines
6.6 KiB
Go
Raw Normal View History

2024-04-29 19:13:50 +02:00
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 _, ok := obj.(fyne.Scrollable); ok {
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
}