User interface toolkit for Go with support for SDL2 and HTML Canvas render targets.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

191 linhas
4.5 KiB

  1. package ui
  2. import (
  3. "errors"
  4. "fmt"
  5. "git.kirsle.net/go/render"
  6. )
  7. /*
  8. window_manager.go holds data types and Supervisor methods related to the
  9. management of ui.Window widgets.
  10. */
  11. // Window button options. OR these together in a call to Window.SetButtons().
  12. const (
  13. CloseButton = 0x01
  14. // NOTICE: MaximizeButton behavior is currently buggy, window doesn't
  15. // redraw itself at the new size properly.
  16. MaximizeButton = 0x02
  17. // Minimize button has no default behavior attached; you can bind it with
  18. // window.Handle(MinimizeWindow) to set your own event handler.
  19. MinimizeButton = 0x04
  20. )
  21. // FocusedWindow is a doubly-linked list of recently focused Windows, with
  22. // the current and most-recently focused on top. TODO make not exported.
  23. type FocusedWindow struct {
  24. window *Window
  25. prev *FocusedWindow
  26. next *FocusedWindow
  27. }
  28. // String of the FocusedWindow returns the underlying Window's String().
  29. func (fw FocusedWindow) String() string {
  30. return fw.window.String()
  31. }
  32. // Print the structure of the linked list from top to bottom.
  33. func (fw *FocusedWindow) Print() {
  34. var (
  35. node = fw
  36. i = 0
  37. )
  38. for node != nil {
  39. fmt.Printf("[%d] window=%s prev=%s next=%s\n",
  40. i, node.window, node.prev, node.next,
  41. )
  42. node = node.next
  43. i++
  44. }
  45. }
  46. // addWindow installs a Window into the supervisor to be managed. It is called
  47. // by ui.Window.Supervise() and the newly added window becomes the focused
  48. // one by default at the top of the linked list.
  49. func (s *Supervisor) addWindow(win *Window) {
  50. // Record in the window that it is managed by Supervisor, useful to control
  51. // event propagation to non-focused windows.
  52. win.managed = true
  53. if s.winFocus == nil {
  54. // First window added.
  55. s.winFocus = &FocusedWindow{
  56. window: win,
  57. }
  58. s.winTop = s.winFocus
  59. s.winBottom = s.winFocus
  60. win.SetFocus(true)
  61. } else {
  62. // New window, make it the top one.
  63. oldTop := s.winFocus
  64. s.winFocus = &FocusedWindow{
  65. window: win,
  66. next: oldTop,
  67. }
  68. oldTop.prev = s.winFocus
  69. oldTop.window.SetFocus(false)
  70. win.SetFocus(true)
  71. }
  72. }
  73. // FocusWindow brings the given window to the top of the supervisor's focus.
  74. //
  75. // The window must have previously been added to the supervisor's Window Manager
  76. // by calling the Supervise() method of the window.
  77. func (s *Supervisor) FocusWindow(win *Window) error {
  78. if s.winFocus == nil {
  79. return errors.New("no windows managed by supervisor")
  80. }
  81. // If the top window is already the target, return.
  82. if s.winFocus.window == win {
  83. return nil
  84. }
  85. // Find the window in the linked list.
  86. var (
  87. item = s.winFocus // item as we iterate the list
  88. oldTop = s.winFocus // original first item in the list
  89. target *FocusedWindow // identified target window to raise
  90. newBottom *FocusedWindow // if the target was the bottom, this is new bottom
  91. i = 0
  92. )
  93. for item != nil {
  94. if item.window == win {
  95. // Found it!
  96. target = item
  97. // Is it the last window in the list? Record the new bottom node.
  98. if item.next == nil && item.prev != nil {
  99. newBottom = item.prev
  100. }
  101. // Remove it from its position in the linked list. Join its
  102. // previous and next nodes to bridge the gap.
  103. if item.next != nil {
  104. item.next.prev = item.prev
  105. }
  106. if item.prev != nil {
  107. item.prev.next = item.next
  108. }
  109. break
  110. }
  111. item = item.next
  112. i++
  113. }
  114. // Found it?
  115. if target != nil {
  116. // Put the target at the top of the list, pointing to the old top.
  117. target.next = oldTop
  118. target.prev = nil
  119. oldTop.prev = target
  120. s.winFocus = target
  121. // Fix the top and bottom pointers.
  122. s.winTop = s.winFocus
  123. if newBottom != nil {
  124. s.winBottom = newBottom
  125. }
  126. // Toggle the focus states.
  127. oldTop.window.SetFocus(false)
  128. target.window.SetFocus(true)
  129. }
  130. return nil
  131. }
  132. // IsPointInWindow returns whether the given Point overlaps with a window managed
  133. // by the Supervisor.
  134. func (s *Supervisor) IsPointInWindow(point render.Point) bool {
  135. node := s.winFocus
  136. for node != nil {
  137. if point.Inside(AbsoluteRect(node.window)) && !node.window.hidden {
  138. return true
  139. }
  140. node = node.next
  141. }
  142. return false
  143. }
  144. // CloseAllWindows closes all open windows being managed by supervisor.
  145. // Returns the number of windows closed.
  146. func (s *Supervisor) CloseAllWindows() int {
  147. var (
  148. node = s.winFocus
  149. i = 0
  150. )
  151. for node != nil {
  152. i++
  153. node.window.Hide()
  154. node = node.next
  155. }
  156. return i
  157. }
  158. // presentWindows draws the windows from bottom to top.
  159. func (s *Supervisor) presentWindows(e render.Engine) {
  160. item := s.winBottom
  161. for item != nil {
  162. item.window.Compute(e)
  163. item.window.Present(e, item.window.Point())
  164. item = item.prev
  165. }
  166. }