| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- 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
- }
|