container.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. package fyne
  2. import "sync"
  3. // Declare conformity to CanvasObject
  4. var _ CanvasObject = (*Container)(nil)
  5. // Container is a CanvasObject that contains a collection of child objects.
  6. // The layout of the children is set by the specified Layout.
  7. type Container struct {
  8. size Size // The current size of the Container
  9. position Position // The current position of the Container
  10. Hidden bool // Is this Container hidden
  11. Layout Layout // The Layout algorithm for arranging child CanvasObjects
  12. lock sync.Mutex
  13. Objects []CanvasObject // The set of CanvasObjects this container holds
  14. }
  15. // NewContainer returns a new Container instance holding the specified CanvasObjects.
  16. //
  17. // Deprecated: Use container.NewWithoutLayout() to create a container that uses manual layout.
  18. func NewContainer(objects ...CanvasObject) *Container {
  19. return NewContainerWithoutLayout(objects...)
  20. }
  21. // NewContainerWithoutLayout returns a new Container instance holding the specified
  22. // CanvasObjects that are manually arranged.
  23. //
  24. // Deprecated: Use container.NewWithoutLayout() instead
  25. func NewContainerWithoutLayout(objects ...CanvasObject) *Container {
  26. ret := &Container{
  27. Objects: objects,
  28. }
  29. ret.size = ret.MinSize()
  30. return ret
  31. }
  32. // NewContainerWithLayout returns a new Container instance holding the specified
  33. // CanvasObjects which will be laid out according to the specified Layout.
  34. //
  35. // Deprecated: Use container.New() instead
  36. func NewContainerWithLayout(layout Layout, objects ...CanvasObject) *Container {
  37. ret := &Container{
  38. Objects: objects,
  39. Layout: layout,
  40. }
  41. ret.size = layout.MinSize(objects)
  42. ret.layout()
  43. return ret
  44. }
  45. // Add appends the specified object to the items this container manages.
  46. //
  47. // Since: 1.4
  48. func (c *Container) Add(add CanvasObject) {
  49. if add == nil {
  50. return
  51. }
  52. c.lock.Lock()
  53. defer c.lock.Unlock()
  54. c.Objects = append(c.Objects, add)
  55. c.layout()
  56. }
  57. // AddObject adds another CanvasObject to the set this Container holds.
  58. //
  59. // Deprecated: Use replacement Add() function
  60. func (c *Container) AddObject(o CanvasObject) {
  61. c.Add(o)
  62. }
  63. // Hide sets this container, and all its children, to be not visible.
  64. func (c *Container) Hide() {
  65. if c.Hidden {
  66. return
  67. }
  68. c.Hidden = true
  69. repaint(c)
  70. }
  71. // MinSize calculates the minimum size of a Container.
  72. // This is delegated to the Layout, if specified, otherwise it will mimic MaxLayout.
  73. func (c *Container) MinSize() Size {
  74. if c.Layout != nil {
  75. return c.Layout.MinSize(c.Objects)
  76. }
  77. minSize := NewSize(1, 1)
  78. for _, child := range c.Objects {
  79. minSize = minSize.Max(child.MinSize())
  80. }
  81. return minSize
  82. }
  83. // Move the container (and all its children) to a new position, relative to its parent.
  84. func (c *Container) Move(pos Position) {
  85. c.position = pos
  86. repaint(c)
  87. }
  88. // Position gets the current position of this Container, relative to its parent.
  89. func (c *Container) Position() Position {
  90. return c.position
  91. }
  92. // Refresh causes this object to be redrawn in it's current state
  93. func (c *Container) Refresh() {
  94. c.layout()
  95. for _, child := range c.Objects {
  96. child.Refresh()
  97. }
  98. // this is basically just canvas.Refresh(c) without the package loop
  99. o := CurrentApp().Driver().CanvasForObject(c)
  100. if o == nil {
  101. return
  102. }
  103. o.Refresh(c)
  104. }
  105. // Remove updates the contents of this container to no longer include the specified object.
  106. // This method is not intended to be used inside a loop, to remove all the elements.
  107. // It is much more efficient to call RemoveAll() instead.
  108. func (c *Container) Remove(rem CanvasObject) {
  109. if len(c.Objects) == 0 {
  110. return
  111. }
  112. c.lock.Lock()
  113. defer c.lock.Unlock()
  114. for i, o := range c.Objects {
  115. if o != rem {
  116. continue
  117. }
  118. removed := make([]CanvasObject, len(c.Objects)-1)
  119. copy(removed, c.Objects[:i])
  120. copy(removed[i:], c.Objects[i+1:])
  121. c.Objects = removed
  122. c.layout()
  123. return
  124. }
  125. }
  126. // RemoveAll updates the contents of this container to no longer include any objects.
  127. //
  128. // Since: 2.2
  129. func (c *Container) RemoveAll() {
  130. c.Objects = nil
  131. c.layout()
  132. }
  133. // Resize sets a new size for the Container.
  134. func (c *Container) Resize(size Size) {
  135. if c.size == size {
  136. return
  137. }
  138. c.size = size
  139. c.layout()
  140. }
  141. // Show sets this container, and all its children, to be visible.
  142. func (c *Container) Show() {
  143. if !c.Hidden {
  144. return
  145. }
  146. c.Hidden = false
  147. }
  148. // Size returns the current size of this container.
  149. func (c *Container) Size() Size {
  150. return c.size
  151. }
  152. // Visible returns true if the container is currently visible, false otherwise.
  153. func (c *Container) Visible() bool {
  154. return !c.Hidden
  155. }
  156. func (c *Container) layout() {
  157. if c.Layout == nil {
  158. return
  159. }
  160. c.Layout.Layout(c.Objects, c.size)
  161. }
  162. // repaint instructs the containing canvas to redraw, even if nothing changed.
  163. // This method is a duplicate of what is in `canvas/canvas.go` to avoid a dependency loop or public API.
  164. func repaint(obj *Container) {
  165. if CurrentApp() == nil || CurrentApp().Driver() == nil {
  166. return
  167. }
  168. c := CurrentApp().Driver().CanvasForObject(obj)
  169. if c != nil {
  170. if paint, ok := c.(interface{ SetDirty() }); ok {
  171. paint.SetDirty()
  172. }
  173. }
  174. }