util.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package driver
  2. import (
  3. "math"
  4. "fyne.io/fyne/v2"
  5. "fyne.io/fyne/v2/internal/cache"
  6. )
  7. // AbsolutePositionForObject returns the absolute position of an object in a set of object trees.
  8. // If the object is not part of any of the trees, the position (0,0) is returned.
  9. func AbsolutePositionForObject(object fyne.CanvasObject, trees []fyne.CanvasObject) fyne.Position {
  10. var pos fyne.Position
  11. findPos := func(o fyne.CanvasObject, p fyne.Position, _ fyne.Position, _ fyne.Size) bool {
  12. if o == object {
  13. pos = p
  14. return true
  15. }
  16. return false
  17. }
  18. for _, tree := range trees {
  19. if WalkVisibleObjectTree(tree, findPos, nil) {
  20. break
  21. }
  22. }
  23. return pos
  24. }
  25. // FindObjectAtPositionMatching is used to find an object in a canvas at the specified position.
  26. // The matches function determines of the type of object that is found at this position is of a suitable type.
  27. // The various canvas roots and overlays that can be searched are also passed in.
  28. func FindObjectAtPositionMatching(mouse fyne.Position, matches func(object fyne.CanvasObject) bool, overlay fyne.CanvasObject, roots ...fyne.CanvasObject) (fyne.CanvasObject, fyne.Position, int) {
  29. var found fyne.CanvasObject
  30. var foundPos fyne.Position
  31. findFunc := func(walked fyne.CanvasObject, pos fyne.Position, clipPos fyne.Position, clipSize fyne.Size) bool {
  32. if !walked.Visible() {
  33. return false
  34. }
  35. if mouse.X < clipPos.X || mouse.Y < clipPos.Y {
  36. return false
  37. }
  38. if mouse.X >= clipPos.X+clipSize.Width || mouse.Y >= clipPos.Y+clipSize.Height {
  39. return false
  40. }
  41. if mouse.X < pos.X || mouse.Y < pos.Y {
  42. return false
  43. }
  44. if mouse.X >= pos.X+walked.Size().Width || mouse.Y >= pos.Y+walked.Size().Height {
  45. return false
  46. }
  47. if matches(walked) {
  48. found = walked
  49. foundPos = fyne.NewPos(mouse.X-pos.X, mouse.Y-pos.Y)
  50. }
  51. return false
  52. }
  53. layer := 0
  54. if overlay != nil {
  55. WalkVisibleObjectTree(overlay, findFunc, nil)
  56. } else {
  57. for _, root := range roots {
  58. layer++
  59. if root == nil {
  60. continue
  61. }
  62. WalkVisibleObjectTree(root, findFunc, nil)
  63. if found != nil {
  64. break
  65. }
  66. }
  67. }
  68. return found, foundPos, layer
  69. }
  70. // ReverseWalkVisibleObjectTree will walk an object tree in reverse order for all visible objects
  71. // executing the passed functions following the following rules:
  72. // - beforeChildren is called for the start obj before traversing its children
  73. // - the obj's children are traversed by calling walkObjects on each of the visible items
  74. // - afterChildren is called for the obj after traversing the obj's children
  75. // The walk can be aborted by returning true in one of the functions:
  76. // - if beforeChildren returns true, further traversing is stopped immediately, the after function
  77. // will not be called for the obj where the walk stopped, however, it will be called for all its
  78. // parents
  79. func ReverseWalkVisibleObjectTree(
  80. obj fyne.CanvasObject,
  81. beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
  82. afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
  83. ) bool {
  84. clipSize := fyne.NewSize(math.MaxInt32, math.MaxInt32)
  85. return walkObjectTree(obj, true, nil, fyne.NewPos(0, 0), fyne.NewPos(0, 0), clipSize, beforeChildren, afterChildren, true)
  86. }
  87. // WalkCompleteObjectTree will walk an object tree for all objects (ignoring visible state) executing the passed
  88. // functions following the following rules:
  89. // - beforeChildren is called for the start obj before traversing its children
  90. // - the obj's children are traversed by calling walkObjects on each of the items
  91. // - afterChildren is called for the obj after traversing the obj's children
  92. // The walk can be aborted by returning true in one of the functions:
  93. // - if beforeChildren returns true, further traversing is stopped immediately, the after function
  94. // will not be called for the obj where the walk stopped, however, it will be called for all its
  95. // parents
  96. func WalkCompleteObjectTree(
  97. obj fyne.CanvasObject,
  98. beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
  99. afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
  100. ) bool {
  101. clipSize := fyne.NewSize(math.MaxInt32, math.MaxInt32)
  102. return walkObjectTree(obj, false, nil, fyne.NewPos(0, 0), fyne.NewPos(0, 0), clipSize, beforeChildren, afterChildren, false)
  103. }
  104. // WalkVisibleObjectTree will walk an object tree for all visible objects executing the passed functions following
  105. // the following rules:
  106. // - beforeChildren is called for the start obj before traversing its children
  107. // - the obj's children are traversed by calling walkObjects on each of the visible items
  108. // - afterChildren is called for the obj after traversing the obj's children
  109. // The walk can be aborted by returning true in one of the functions:
  110. // - if beforeChildren returns true, further traversing is stopped immediately, the after function
  111. // will not be called for the obj where the walk stopped, however, it will be called for all its
  112. // parents
  113. func WalkVisibleObjectTree(
  114. obj fyne.CanvasObject,
  115. beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
  116. afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
  117. ) bool {
  118. clipSize := fyne.NewSize(math.MaxInt32, math.MaxInt32)
  119. return walkObjectTree(obj, false, nil, fyne.NewPos(0, 0), fyne.NewPos(0, 0), clipSize, beforeChildren, afterChildren, true)
  120. }
  121. func walkObjectTree(
  122. obj fyne.CanvasObject,
  123. reverse bool,
  124. parent fyne.CanvasObject,
  125. offset, clipPos fyne.Position,
  126. clipSize fyne.Size,
  127. beforeChildren func(fyne.CanvasObject, fyne.Position, fyne.Position, fyne.Size) bool,
  128. afterChildren func(fyne.CanvasObject, fyne.Position, fyne.CanvasObject),
  129. requireVisible bool,
  130. ) bool {
  131. if obj == nil {
  132. return false
  133. }
  134. if requireVisible && !obj.Visible() {
  135. return false
  136. }
  137. pos := obj.Position().Add(offset)
  138. var children []fyne.CanvasObject
  139. switch co := obj.(type) {
  140. case *fyne.Container:
  141. children = co.Objects
  142. case fyne.Widget:
  143. if cache.IsRendered(co) || requireVisible {
  144. children = cache.Renderer(co).Objects()
  145. }
  146. }
  147. if _, ok := obj.(fyne.Scrollable); ok {
  148. clipPos = pos
  149. clipSize = obj.Size()
  150. }
  151. if beforeChildren != nil {
  152. if beforeChildren(obj, pos, clipPos, clipSize) {
  153. return true
  154. }
  155. }
  156. cancelled := false
  157. followChild := func(child fyne.CanvasObject) bool {
  158. if walkObjectTree(child, reverse, obj, pos, clipPos, clipSize, beforeChildren, afterChildren, requireVisible) {
  159. cancelled = true
  160. return true
  161. }
  162. return false
  163. }
  164. if reverse {
  165. for i := len(children) - 1; i >= 0; i-- {
  166. if followChild(children[i]) {
  167. break
  168. }
  169. }
  170. } else {
  171. for _, child := range children {
  172. if followChild(child) {
  173. break
  174. }
  175. }
  176. }
  177. if afterChildren != nil {
  178. afterChildren(obj, pos, parent)
  179. }
  180. return cancelled
  181. }