github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/layout/stack.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package layout 4 5 import ( 6 "image" 7 8 "github.com/gop9/olt/gio/op" 9 ) 10 11 // Stack lays out child elements on top of each other, 12 // according to an alignment direction. 13 type Stack struct { 14 // Alignment is the direction to align children 15 // smaller than the available space. 16 Alignment Direction 17 } 18 19 // StackChild represents a child for a Stack layout. 20 type StackChild struct { 21 expanded bool 22 widget Widget 23 24 // Scratch space. 25 macro op.MacroOp 26 dims Dimensions 27 } 28 29 // Stacked returns a Stack child that laid out with the same maximum 30 // constraints as the Stack. 31 func Stacked(w Widget) StackChild { 32 return StackChild{ 33 widget: w, 34 } 35 } 36 37 // Expanded returns a Stack child that is forced to take up at least 38 // the the space as the largest Stacked. 39 func Expanded(w Widget) StackChild { 40 return StackChild{ 41 expanded: true, 42 widget: w, 43 } 44 } 45 46 // Layout a stack of children. The position of the children are 47 // determined by the specified order, but Stacked children are laid out 48 // before Expanded children. 49 func (s Stack) Layout(gtx *Context, children ...StackChild) { 50 var maxSZ image.Point 51 // First lay out Stacked children. 52 for i, w := range children { 53 if w.expanded { 54 continue 55 } 56 cs := gtx.Constraints 57 cs.Width.Min = 0 58 cs.Height.Min = 0 59 var m op.MacroOp 60 m.Record(gtx.Ops) 61 dims := ctxLayout(gtx, cs, w.widget) 62 m.Stop() 63 if w := dims.Size.X; w > maxSZ.X { 64 maxSZ.X = w 65 } 66 if h := dims.Size.Y; h > maxSZ.Y { 67 maxSZ.Y = h 68 } 69 children[i].macro = m 70 children[i].dims = dims 71 } 72 maxSZ = gtx.Constraints.Constrain(maxSZ) 73 // Then lay out Expanded children. 74 for i, w := range children { 75 if !w.expanded { 76 continue 77 } 78 var m op.MacroOp 79 m.Record(gtx.Ops) 80 cs := Constraints{ 81 Width: Constraint{Min: maxSZ.X, Max: gtx.Constraints.Width.Max}, 82 Height: Constraint{Min: maxSZ.Y, Max: gtx.Constraints.Height.Max}, 83 } 84 dims := ctxLayout(gtx, cs, w.widget) 85 m.Stop() 86 children[i].macro = m 87 children[i].dims = dims 88 } 89 90 var baseline int 91 for _, ch := range children { 92 sz := ch.dims.Size 93 var p image.Point 94 switch s.Alignment { 95 case N, S, Center: 96 p.X = (maxSZ.X - sz.X) / 2 97 case NE, SE, E: 98 p.X = maxSZ.X - sz.X 99 } 100 switch s.Alignment { 101 case W, Center, E: 102 p.Y = (maxSZ.Y - sz.Y) / 2 103 case SW, S, SE: 104 p.Y = maxSZ.Y - sz.Y 105 } 106 var stack op.StackOp 107 stack.Push(gtx.Ops) 108 op.TransformOp{}.Offset(toPointF(p)).Add(gtx.Ops) 109 ch.macro.Add() 110 stack.Pop() 111 if baseline == 0 { 112 if b := ch.dims.Baseline; b != 0 { 113 baseline = b + maxSZ.Y - sz.Y - p.Y 114 } 115 } 116 } 117 gtx.Dimensions = Dimensions{ 118 Size: maxSZ, 119 Baseline: baseline, 120 } 121 }