wraplist.go raw

   1  package gel
   2  
   3  import (
   4  	l "github.com/p9c/gio/layout"
   5  	"golang.org/x/exp/shiny/text"
   6  )
   7  
   8  // WrapList is a generalised layout for creating lists from widgets lined up in one axis and wrapped into lines across
   9  // a given axis. It can be used for an icon view, for a text console cell grid, for laying out selectable text.
  10  type WrapList struct {
  11  	*Window
  12  	list    *List
  13  	widgets []l.Widget
  14  	axis    l.Axis
  15  	dir     text.Direction
  16  }
  17  
  18  // WrapList creates a new WrapList
  19  func (w *Window) WrapList() *WrapList {
  20  	return &WrapList{
  21  		Window: w,
  22  		list:   w.WidgetPool.GetList(),
  23  	}
  24  }
  25  
  26  // Axis sets the axis that will be scrollable
  27  func (w *WrapList) Axis(axis l.Axis) *WrapList {
  28  	w.axis = axis
  29  	return w
  30  }
  31  
  32  // Direction sets the direction across the axis, for vertical, text.Forwards means left to right, text.Backwards means
  33  // right to left, and for horizontal, text.Forwards means top to bottom, text.Backwards means bottom to top
  34  func (w *WrapList) Direction(dir text.Direction) *WrapList {
  35  	w.dir = dir
  36  	return w
  37  }
  38  
  39  // Widgets loads a set of widgets into the WrapList
  40  func (w *WrapList) Widgets(widgets []l.Widget) *WrapList {
  41  	w.widgets = widgets
  42  	return w
  43  }
  44  
  45  // Fn renders the WrapList in the current context
  46  // todo: this needs to be cached and have a hook in the WrapList.Widgets method to trigger generation
  47  func (w *WrapList) Fn(gtx l.Context) l.Dimensions {
  48  	// first get the dimensions of the widget list
  49  	if len(w.widgets) > 0 {
  50  		le := func(gtx l.Context, index int) l.Dimensions {
  51  			dims := w.widgets[index](gtx)
  52  			return dims
  53  		}
  54  		gtx1 := CopyContextDimensionsWithMaxAxis(gtx, w.axis)
  55  		// generate the dimensions for all the list elements
  56  		allDims := GetDimensionList(gtx1, len(w.widgets), le)
  57  		var out = [][]l.Widget{{}}
  58  		cursor := 0
  59  		runningTotal := 0
  60  		_, width := axisCrossConstraint(w.axis, gtx.Constraints)
  61  		for i := range allDims {
  62  			runningTotal += axisCross(w.axis, allDims[i].Size)
  63  			if runningTotal > width {
  64  				cursor++
  65  				runningTotal = 0
  66  				out = append(out, []l.Widget{})
  67  			}
  68  			out[cursor] = append(out[cursor], w.widgets[i])
  69  		}
  70  		le2 := func(gtx l.Context, index int) l.Dimensions {
  71  			o := w.Flex().AlignStart()
  72  			if w.axis == l.Horizontal {
  73  				o = w.VFlex().AlignStart()
  74  			}
  75  			// for _, y := range out {
  76  			y := out[index]
  77  			var outRow []l.Widget
  78  			for j, x := range y {
  79  				if w.dir == text.Forwards {
  80  					outRow = append(outRow, x)
  81  				} else {
  82  					outRow = append(outRow, y[len(y)-1-j])
  83  				}
  84  			}
  85  			for i := range outRow {
  86  				o.Rigid(outRow[i])
  87  			}
  88  			// }
  89  			return o.Fn(gtx)
  90  		}
  91  		return w.list.Vertical().Length(len(out)).ListElement(le2).Fn(gtx)
  92  	} else {
  93  		return l.Dimensions{}
  94  	}
  95  }
  96