User interface toolkit for Go with support for SDL2 and HTML Canvas render targets.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

100 lines
2.5 KiB

  1. package ui
  2. import (
  3. "git.kirsle.net/go/render"
  4. )
  5. // Place provides configuration fields for Frame.Place().
  6. type Place struct {
  7. // X and Y coordinates for explicit location of widget within its parent.
  8. // This placement option trumps all others.
  9. Point render.Point
  10. // Place relative to an edge of the window. The widget will stick to the
  11. // edge of the window even as it resizes. Options are ignored if Point
  12. // is set.
  13. Top int
  14. Left int
  15. Right int
  16. Bottom int
  17. Center bool
  18. Middle bool
  19. }
  20. // Strategy returns the placement strategy for a Place config struct.
  21. // Returns 'Point' if a render.Point is used (even if zero, zero)
  22. // Returns 'Side' if the side values are set.
  23. func (p Place) Strategy() string {
  24. if p.Top != 0 || p.Left != 0 || p.Right != 0 || p.Bottom != 0 || p.Center || p.Middle {
  25. return "Side"
  26. }
  27. return "Point"
  28. }
  29. // placedWidget holds the data for a widget placed in a frame.
  30. type placedWidget struct {
  31. widget Widget
  32. place Place
  33. }
  34. // Place a widget into the frame.
  35. func (w *Frame) Place(child Widget, config Place) {
  36. w.placed = append(w.placed, placedWidget{
  37. widget: child,
  38. place: config,
  39. })
  40. w.Add(child)
  41. // Adopt the child widget so it can access the Frame.
  42. child.SetParent(w)
  43. }
  44. // computePlaced processes all the Place layout widgets in the Frame,
  45. // determining their X,Y location and whether they need to change.
  46. func (w *Frame) computePlaced(e render.Engine) {
  47. var (
  48. frameSize = w.BoxSize()
  49. )
  50. for _, row := range w.placed {
  51. // X,Y placement takes priority.
  52. switch row.place.Strategy() {
  53. case "Point":
  54. row.widget.MoveTo(row.place.Point)
  55. row.widget.Compute(e)
  56. case "Side":
  57. var moveTo render.Point
  58. // Compute the initial X,Y based on Top, Left, Right, Bottom.
  59. if row.place.Left > 0 {
  60. moveTo.X = row.place.Left
  61. }
  62. if row.place.Top > 0 {
  63. moveTo.Y = row.place.Top
  64. }
  65. if row.place.Right > 0 {
  66. moveTo.X = frameSize.W - row.widget.Size().W - row.place.Right
  67. }
  68. if row.place.Bottom > 0 {
  69. moveTo.Y = frameSize.H - row.widget.Size().H - row.place.Bottom
  70. }
  71. // Center and Middle aligned values override Left/Right, Top/Bottom
  72. // settings respectively.
  73. if row.place.Center {
  74. moveTo.X = frameSize.W - (w.Size().W / 2) - (row.widget.Size().W / 2)
  75. }
  76. if row.place.Middle {
  77. moveTo.Y = frameSize.H - (w.Size().H / 2) - (row.widget.Size().H / 2)
  78. }
  79. row.widget.MoveTo(moveTo)
  80. row.widget.Compute(e)
  81. }
  82. // If this widget itself has placed widgets, call its function too.
  83. if frame, ok := row.widget.(*Frame); ok {
  84. frame.computePlaced(e)
  85. }
  86. }
  87. }