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  }