gridlayout.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gui
  5. type GridLayout struct {
  6. columns int
  7. }
  8. type GridLayoutParams struct {
  9. Row int // grid layout row number from 0
  10. Col int // grid layout column number from 0
  11. ColSpan int // number of additional columns to ocuppy to the right
  12. AlignH Align // vertical alignment
  13. AlignV Align // horizontal alignment
  14. }
  15. // NewGridLayout creates and returns a pointer of a new grid layout
  16. func NewGridLayout() *GridLayout {
  17. g := new(GridLayout)
  18. return g
  19. }
  20. func (g *GridLayout) Recalc(ipan IPanel) {
  21. type element struct {
  22. panel *Panel
  23. params *GridLayoutParams
  24. }
  25. rows := 0
  26. cols := 0
  27. items := []element{}
  28. pan := ipan.GetPanel()
  29. for _, obj := range pan.Children() {
  30. // Get child panel
  31. child := obj.(IPanel).GetPanel()
  32. // Ignore if not visible
  33. if !child.Visible() {
  34. continue
  35. }
  36. // Ignore if no layout params
  37. if child.layoutParams == nil {
  38. continue
  39. }
  40. // Checks layout params
  41. params, ok := child.layoutParams.(*GridLayoutParams)
  42. if !ok {
  43. panic("layoutParams is not GridLayoutParams")
  44. }
  45. if params.Row >= rows {
  46. rows = params.Row + 1
  47. }
  48. if params.Col >= cols {
  49. cols = params.Col + 1
  50. }
  51. items = append(items, element{child, params})
  52. }
  53. // Check limits
  54. if rows > 100 {
  55. panic("Element row outsize limits")
  56. }
  57. if cols > 100 {
  58. panic("Element column outsize limits")
  59. }
  60. // Determine row and column maximum sizes
  61. colSizes := make([]int, cols)
  62. rowSizes := make([]int, rows)
  63. for _, el := range items {
  64. width := el.panel.Width()
  65. height := el.panel.Height()
  66. if int(width) > colSizes[el.params.Col] {
  67. colSizes[el.params.Col] = int(width)
  68. }
  69. if int(height) > rowSizes[el.params.Row] {
  70. rowSizes[el.params.Row] = int(height)
  71. }
  72. }
  73. // Determine row and column starting positions
  74. colStart := make([]int, cols)
  75. rowStart := make([]int, rows)
  76. for i := 1; i < len(colSizes); i++ {
  77. colStart[i] = colStart[i-1] + colSizes[i-1]
  78. }
  79. for i := 1; i < len(rowSizes); i++ {
  80. rowStart[i] = rowStart[i-1] + rowSizes[i-1]
  81. }
  82. // Position the elements
  83. for _, el := range items {
  84. row := el.params.Row
  85. col := el.params.Col
  86. cellHeight := rowSizes[row]
  87. // Current cell width
  88. cellWidth := 0
  89. for c := 0; c <= el.params.ColSpan; c++ {
  90. pos := col + c
  91. if pos >= len(colSizes) {
  92. break
  93. }
  94. cellWidth += colSizes[pos]
  95. }
  96. rstart := float32(rowStart[row])
  97. cstart := float32(colStart[col])
  98. // Horizontal alignment
  99. var dx float32 = 0
  100. switch el.params.AlignH {
  101. case AlignNone:
  102. case AlignLeft:
  103. case AlignRight:
  104. dx = float32(cellWidth) - el.panel.width
  105. case AlignCenter:
  106. dx = (float32(cellWidth) - el.panel.width) / 2
  107. default:
  108. panic("Invalid horizontal alignment")
  109. }
  110. // Vertical alignment
  111. var dy float32 = 0
  112. switch el.params.AlignV {
  113. case AlignNone:
  114. case AlignTop:
  115. case AlignBottom:
  116. dy = float32(cellHeight) - el.panel.height
  117. case AlignCenter:
  118. dy = (float32(cellHeight) - el.panel.height) / 2
  119. default:
  120. panic("Invalid vertical alignment")
  121. }
  122. el.panel.SetPosition(cstart+dx, rstart+dy)
  123. }
  124. }