clip.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package internal
  2. import "fyne.io/fyne/v2"
  3. // ClipStack keeps track of the areas that should be clipped when drawing a canvas.
  4. // If no clips are present then adding one will be added as-is.
  5. // Subsequent items pushed will be completely within the previous clip.
  6. type ClipStack struct {
  7. clips []*ClipItem
  8. }
  9. // Pop removes the current top clip and returns it.
  10. func (c *ClipStack) Pop() *ClipItem {
  11. if len(c.clips) == 0 {
  12. return nil
  13. }
  14. ret := c.clips[len(c.clips)-1]
  15. c.clips = c.clips[:len(c.clips)-1]
  16. return ret
  17. }
  18. // Length returns the number of items in this clip stack. 0 means no clip.
  19. func (c *ClipStack) Length() int {
  20. return len(c.clips)
  21. }
  22. // Push a new clip onto this stack at position and size specified.
  23. // The returned clip item is the result of calculating the intersection of the requested clip and it's parent.
  24. func (c *ClipStack) Push(p fyne.Position, s fyne.Size) *ClipItem {
  25. outer := c.Top()
  26. inner := outer.Intersect(p, s)
  27. c.clips = append(c.clips, inner)
  28. return inner
  29. }
  30. // Top returns the current clip item - it will always be within the bounds of any parent clips.
  31. func (c *ClipStack) Top() *ClipItem {
  32. if len(c.clips) == 0 {
  33. return nil
  34. }
  35. return c.clips[len(c.clips)-1]
  36. }
  37. // ClipItem represents a single clip in a clip stack, denoted by a size and position.
  38. type ClipItem struct {
  39. pos fyne.Position
  40. size fyne.Size
  41. }
  42. // Rect returns the position and size parameters of the clip.
  43. func (i *ClipItem) Rect() (fyne.Position, fyne.Size) {
  44. return i.pos, i.size
  45. }
  46. // Intersect returns a new clip item that is the intersection of the requested parameters and this clip.
  47. func (i *ClipItem) Intersect(p fyne.Position, s fyne.Size) *ClipItem {
  48. ret := &ClipItem{p, s}
  49. if i == nil {
  50. return ret
  51. }
  52. if ret.pos.X < i.pos.X {
  53. ret.pos.X = i.pos.X
  54. ret.size.Width -= i.pos.X - p.X
  55. }
  56. if ret.pos.Y < i.pos.Y {
  57. ret.pos.Y = i.pos.Y
  58. ret.size.Height -= i.pos.Y - p.Y
  59. }
  60. if p.X+s.Width > i.pos.X+i.size.Width {
  61. ret.size.Width = (i.pos.X + i.size.Width) - ret.pos.X
  62. }
  63. if p.Y+s.Height > i.pos.Y+i.size.Height {
  64. ret.size.Height = (i.pos.Y + i.size.Height) - ret.pos.Y
  65. }
  66. if ret.size.Width < 0 || ret.size.Height < 0 {
  67. ret.size = fyne.NewSize(0, 0)
  68. return ret
  69. }
  70. return ret
  71. }