1// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved. 2// Use of this source code is governed by a MIT license that can 3// be found in the LICENSE file. 4 5package termui 6 7type gridItemType uint 8 9const ( 10 col gridItemType = 0 11 row gridItemType = 1 12) 13 14type Grid struct { 15 Block 16 Items []*GridItem 17} 18 19// GridItem represents either a Row or Column in a grid. 20// Holds sizing information and either an []GridItems or a widget. 21type GridItem struct { 22 Type gridItemType 23 XRatio float64 24 YRatio float64 25 WidthRatio float64 26 HeightRatio float64 27 Entry interface{} // Entry.type == GridBufferer if IsLeaf else []GridItem 28 IsLeaf bool 29 ratio float64 30} 31 32func NewGrid() *Grid { 33 g := &Grid{ 34 Block: *NewBlock(), 35 } 36 g.Border = false 37 return g 38} 39 40// NewCol takes a height percentage and either a widget or a Row or Column 41func NewCol(ratio float64, i ...interface{}) GridItem { 42 _, ok := i[0].(Drawable) 43 entry := i[0] 44 if !ok { 45 entry = i 46 } 47 return GridItem{ 48 Type: col, 49 Entry: entry, 50 IsLeaf: ok, 51 ratio: ratio, 52 } 53} 54 55// NewRow takes a width percentage and either a widget or a Row or Column 56func NewRow(ratio float64, i ...interface{}) GridItem { 57 _, ok := i[0].(Drawable) 58 entry := i[0] 59 if !ok { 60 entry = i 61 } 62 return GridItem{ 63 Type: row, 64 Entry: entry, 65 IsLeaf: ok, 66 ratio: ratio, 67 } 68} 69 70// Set is used to add Columns and Rows to the grid. 71// It recursively searches the GridItems, adding leaves to the grid and calculating the dimensions of the leaves. 72func (self *Grid) Set(entries ...interface{}) { 73 entry := GridItem{ 74 Type: row, 75 Entry: entries, 76 IsLeaf: false, 77 ratio: 1.0, 78 } 79 self.setHelper(entry, 1.0, 1.0) 80} 81 82func (self *Grid) setHelper(item GridItem, parentWidthRatio, parentHeightRatio float64) { 83 var HeightRatio float64 84 var WidthRatio float64 85 switch item.Type { 86 case col: 87 HeightRatio = 1.0 88 WidthRatio = item.ratio 89 case row: 90 HeightRatio = item.ratio 91 WidthRatio = 1.0 92 } 93 item.WidthRatio = parentWidthRatio * WidthRatio 94 item.HeightRatio = parentHeightRatio * HeightRatio 95 96 if item.IsLeaf { 97 self.Items = append(self.Items, &item) 98 } else { 99 XRatio := 0.0 100 YRatio := 0.0 101 cols := false 102 rows := false 103 104 children := InterfaceSlice(item.Entry) 105 106 for i := 0; i < len(children); i++ { 107 if children[i] == nil { 108 continue 109 } 110 child, _ := children[i].(GridItem) 111 112 child.XRatio = item.XRatio + (item.WidthRatio * XRatio) 113 child.YRatio = item.YRatio + (item.HeightRatio * YRatio) 114 115 switch child.Type { 116 case col: 117 cols = true 118 XRatio += child.ratio 119 if rows { 120 item.HeightRatio /= 2 121 } 122 case row: 123 rows = true 124 YRatio += child.ratio 125 if cols { 126 item.WidthRatio /= 2 127 } 128 } 129 130 self.setHelper(child, item.WidthRatio, item.HeightRatio) 131 } 132 } 133} 134 135func (self *Grid) Draw(buf *Buffer) { 136 width := float64(self.Dx()) + 1 137 height := float64(self.Dy()) + 1 138 139 for _, item := range self.Items { 140 entry, _ := item.Entry.(Drawable) 141 142 x := int(width*item.XRatio) + self.Min.X 143 y := int(height*item.YRatio) + self.Min.Y 144 w := int(width * item.WidthRatio) 145 h := int(height * item.HeightRatio) 146 147 if x+w > self.Dx() { 148 w-- 149 } 150 if y+h > self.Dy() { 151 h-- 152 } 153 154 entry.SetRect(x, y, x+w, y+h) 155 156 entry.Lock() 157 entry.Draw(buf) 158 entry.Unlock() 159 } 160} 161