gioui.org/ui@v0.0.0-20190926171558-ce74bc0cbaea/layout/stack.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package layout 4 5 import ( 6 "image" 7 8 "gioui.org/ui" 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 macro ui.MacroOp 19 constrained bool 20 ctx *Context 21 maxSZ image.Point 22 baseline int 23 } 24 25 // StackChild is the layout result of a call to End. 26 type StackChild struct { 27 macro ui.MacroOp 28 dims Dimensions 29 } 30 31 // Init a stack before calling Rigid or Expand. 32 func (s *Stack) Init(gtx *Context) *Stack { 33 s.ctx = gtx 34 s.constrained = true 35 s.maxSZ = image.Point{} 36 s.baseline = 0 37 return s 38 } 39 40 func (s *Stack) begin() { 41 if !s.constrained { 42 panic("must Init before adding a child") 43 } 44 s.macro.Record(s.ctx.Ops) 45 } 46 47 // Rigid lays out a widget with the same constraints that were 48 // passed to Init. 49 func (s *Stack) Rigid(w Widget) StackChild { 50 s.begin() 51 dims := s.ctx.Layout(s.ctx.Constraints, w) 52 return s.end(dims) 53 } 54 55 // Expand lays out a widget with constraints that exactly match 56 // the biggest child previously added. 57 func (s *Stack) Expand(w Widget) StackChild { 58 s.begin() 59 cs := Constraints{ 60 Width: Constraint{Min: s.maxSZ.X, Max: s.maxSZ.X}, 61 Height: Constraint{Min: s.maxSZ.Y, Max: s.maxSZ.Y}, 62 } 63 dims := s.ctx.Layout(cs, w) 64 return s.end(dims) 65 } 66 67 // End a child by specifying its dimensions. 68 func (s *Stack) end(dims Dimensions) StackChild { 69 s.macro.Stop() 70 if w := dims.Size.X; w > s.maxSZ.X { 71 s.maxSZ.X = w 72 } 73 if h := dims.Size.Y; h > s.maxSZ.Y { 74 s.maxSZ.Y = h 75 } 76 if s.baseline == 0 { 77 if b := dims.Baseline; b != dims.Size.Y { 78 s.baseline = b 79 } 80 } 81 return StackChild{s.macro, dims} 82 } 83 84 // Layout a list of children. The order of the children determines their laid 85 // out order. 86 func (s *Stack) Layout(children ...StackChild) { 87 for _, ch := range children { 88 sz := ch.dims.Size 89 var p image.Point 90 switch s.Alignment { 91 case N, S, Center: 92 p.X = (s.maxSZ.X - sz.X) / 2 93 case NE, SE, E: 94 p.X = s.maxSZ.X - sz.X 95 } 96 switch s.Alignment { 97 case W, Center, E: 98 p.Y = (s.maxSZ.Y - sz.Y) / 2 99 case SW, S, SE: 100 p.Y = s.maxSZ.Y - sz.Y 101 } 102 var stack ui.StackOp 103 stack.Push(s.ctx.Ops) 104 ui.TransformOp{}.Offset(toPointF(p)).Add(s.ctx.Ops) 105 ch.macro.Add(s.ctx.Ops) 106 stack.Pop() 107 } 108 b := s.baseline 109 if b == 0 { 110 b = s.maxSZ.Y 111 } 112 s.ctx.Dimensions = Dimensions{ 113 Size: s.maxSZ, 114 Baseline: b, 115 } 116 }