mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 09:55:40 +00:00
ui/layout: make layout API explicit
With layout.Widget a function instead of an interface, the amount of per-frame garbage can be drastically reduced. The layout code ends up slightly more explicit. As a side benefit, the awkward ordering indexing for Flex and Stack fit nicely into their new explicit Layout methods. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+34
-57
@@ -10,23 +10,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Flex struct {
|
type Flex struct {
|
||||||
|
Constraints Constraints
|
||||||
|
|
||||||
Axis Axis
|
Axis Axis
|
||||||
MainAxisAlignment MainAxisAlignment
|
MainAxisAlignment MainAxisAlignment
|
||||||
CrossAxisAlignment CrossAxisAlignment
|
CrossAxisAlignment CrossAxisAlignment
|
||||||
MainAxisSize MainAxisSize
|
MainAxisSize MainAxisSize
|
||||||
|
|
||||||
ops *ui.Ops
|
|
||||||
cs Constraints
|
|
||||||
|
|
||||||
children []flexChild
|
|
||||||
taken int
|
taken int
|
||||||
maxCross int
|
maxCross int
|
||||||
maxBaseline int
|
maxBaseline int
|
||||||
|
|
||||||
ccache [10]flexChild
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type flexChild struct {
|
type FlexChild struct {
|
||||||
block ui.OpBlock
|
block ui.OpBlock
|
||||||
dims Dimens
|
dims Dimens
|
||||||
}
|
}
|
||||||
@@ -60,29 +56,17 @@ const (
|
|||||||
Stretch
|
Stretch
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f *Flex) Init(ops *ui.Ops, cs Constraints) *Flex {
|
func (f *Flex) Rigid(ops *ui.Ops, w Widget) FlexChild {
|
||||||
f.ops = ops
|
mainc := axisMainConstraint(f.Axis, f.Constraints)
|
||||||
f.cs = cs
|
|
||||||
if f.children == nil {
|
|
||||||
f.children = f.ccache[:0]
|
|
||||||
}
|
|
||||||
f.children = f.children[:0]
|
|
||||||
f.maxCross = 0
|
|
||||||
f.maxBaseline = 0
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Flex) Rigid(w Widget) *Flex {
|
|
||||||
mainc := axisMainConstraint(f.Axis, f.cs)
|
|
||||||
mainMax := mainc.Max
|
mainMax := mainc.Max
|
||||||
if mainc.Max != ui.Inf {
|
if mainc.Max != ui.Inf {
|
||||||
mainMax -= f.taken
|
mainMax -= f.taken
|
||||||
}
|
}
|
||||||
cs := axisConstraints(f.Axis, Constraint{Max: mainMax}, f.crossConstraintChild(f.cs))
|
cs := axisConstraints(f.Axis, Constraint{Max: mainMax}, f.crossConstraintChild(f.Constraints))
|
||||||
f.ops.Begin()
|
ops.Begin()
|
||||||
ui.OpLayer{}.Add(f.ops)
|
ui.OpLayer{}.Add(ops)
|
||||||
dims := w.Layout(f.ops, cs)
|
dims := w(ops, cs)
|
||||||
block := f.ops.End()
|
block := ops.End()
|
||||||
f.taken += axisMain(f.Axis, dims.Size)
|
f.taken += axisMain(f.Axis, dims.Size)
|
||||||
if c := axisCross(f.Axis, dims.Size); c > f.maxCross {
|
if c := axisCross(f.Axis, dims.Size); c > f.maxCross {
|
||||||
f.maxCross = c
|
f.maxCross = c
|
||||||
@@ -90,12 +74,11 @@ func (f *Flex) Rigid(w Widget) *Flex {
|
|||||||
if b := dims.Baseline; b > f.maxBaseline {
|
if b := dims.Baseline; b > f.maxBaseline {
|
||||||
f.maxBaseline = b
|
f.maxBaseline = b
|
||||||
}
|
}
|
||||||
f.children = append(f.children, flexChild{block, dims})
|
return FlexChild{block, dims}
|
||||||
return f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Flex) Flexible(idx int, flex float32, mode FlexMode, w Widget) *Flex {
|
func (f *Flex) Flexible(ops *ui.Ops, flex float32, mode FlexMode, w Widget) FlexChild {
|
||||||
mainc := axisMainConstraint(f.Axis, f.cs)
|
mainc := axisMainConstraint(f.Axis, f.Constraints)
|
||||||
var flexSize int
|
var flexSize int
|
||||||
if mainc.Max != ui.Inf && mainc.Max > f.taken {
|
if mainc.Max != ui.Inf && mainc.Max > f.taken {
|
||||||
flexSize = mainc.Max - f.taken
|
flexSize = mainc.Max - f.taken
|
||||||
@@ -104,11 +87,11 @@ func (f *Flex) Flexible(idx int, flex float32, mode FlexMode, w Widget) *Flex {
|
|||||||
if mode == Fit {
|
if mode == Fit {
|
||||||
submainc.Min = submainc.Max
|
submainc.Min = submainc.Max
|
||||||
}
|
}
|
||||||
cs := axisConstraints(f.Axis, submainc, f.crossConstraintChild(f.cs))
|
cs := axisConstraints(f.Axis, submainc, f.crossConstraintChild(f.Constraints))
|
||||||
f.ops.Begin()
|
ops.Begin()
|
||||||
ui.OpLayer{}.Add(f.ops)
|
ui.OpLayer{}.Add(ops)
|
||||||
dims := w.Layout(f.ops, cs)
|
dims := w(ops, cs)
|
||||||
block := f.ops.End()
|
block := ops.End()
|
||||||
f.taken += axisMain(f.Axis, dims.Size)
|
f.taken += axisMain(f.Axis, dims.Size)
|
||||||
if c := axisCross(f.Axis, dims.Size); c > f.maxCross {
|
if c := axisCross(f.Axis, dims.Size); c > f.maxCross {
|
||||||
f.maxCross = c
|
f.maxCross = c
|
||||||
@@ -116,18 +99,12 @@ func (f *Flex) Flexible(idx int, flex float32, mode FlexMode, w Widget) *Flex {
|
|||||||
if b := dims.Baseline; b > f.maxBaseline {
|
if b := dims.Baseline; b > f.maxBaseline {
|
||||||
f.maxBaseline = b
|
f.maxBaseline = b
|
||||||
}
|
}
|
||||||
if idx < 0 {
|
return FlexChild{block, dims}
|
||||||
idx += len(f.children) + 1
|
|
||||||
}
|
|
||||||
f.children = append(f.children, flexChild{})
|
|
||||||
copy(f.children[idx+1:], f.children[idx:])
|
|
||||||
f.children[idx] = flexChild{block, dims}
|
|
||||||
return f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Flex) Layout() Dimens {
|
func (f *Flex) Layout(ops *ui.Ops, children ...FlexChild) Dimens {
|
||||||
mainc := axisMainConstraint(f.Axis, f.cs)
|
mainc := axisMainConstraint(f.Axis, f.Constraints)
|
||||||
crossSize := axisCrossConstraint(f.Axis, f.cs).Constrain(f.maxCross)
|
crossSize := axisCrossConstraint(f.Axis, f.Constraints).Constrain(f.maxCross)
|
||||||
var space int
|
var space int
|
||||||
if mainc.Max != ui.Inf && f.MainAxisSize == Max {
|
if mainc.Max != ui.Inf && f.MainAxisSize == Max {
|
||||||
if mainc.Max > f.taken {
|
if mainc.Max > f.taken {
|
||||||
@@ -144,11 +121,11 @@ func (f *Flex) Layout() Dimens {
|
|||||||
case End:
|
case End:
|
||||||
mainSize += space
|
mainSize += space
|
||||||
case SpaceEvenly:
|
case SpaceEvenly:
|
||||||
mainSize += space / (1 + len(f.children))
|
mainSize += space / (1 + len(children))
|
||||||
case SpaceAround:
|
case SpaceAround:
|
||||||
mainSize += space / (len(f.children) * 2)
|
mainSize += space / (len(children) * 2)
|
||||||
}
|
}
|
||||||
for _, child := range f.children {
|
for _, child := range children {
|
||||||
dims := child.dims
|
dims := child.dims
|
||||||
b := dims.Baseline
|
b := dims.Baseline
|
||||||
var cross int
|
var cross int
|
||||||
@@ -162,20 +139,20 @@ func (f *Flex) Layout() Dimens {
|
|||||||
cross = f.maxBaseline - b
|
cross = f.maxBaseline - b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.ops.Begin()
|
ops.Begin()
|
||||||
ui.OpTransform{
|
ui.OpTransform{
|
||||||
Transform: ui.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))),
|
Transform: ui.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))),
|
||||||
}.Add(f.ops)
|
}.Add(ops)
|
||||||
child.block.Add(f.ops)
|
child.block.Add(ops)
|
||||||
f.ops.End().Add(f.ops)
|
ops.End().Add(ops)
|
||||||
mainSize += axisMain(f.Axis, dims.Size)
|
mainSize += axisMain(f.Axis, dims.Size)
|
||||||
switch f.MainAxisAlignment {
|
switch f.MainAxisAlignment {
|
||||||
case SpaceEvenly:
|
case SpaceEvenly:
|
||||||
mainSize += space / (1 + len(f.children))
|
mainSize += space / (1 + len(children))
|
||||||
case SpaceAround:
|
case SpaceAround:
|
||||||
mainSize += space / len(f.children)
|
mainSize += space / len(children)
|
||||||
case SpaceBetween:
|
case SpaceBetween:
|
||||||
mainSize += space / (len(f.children) - 1)
|
mainSize += space / (len(children) - 1)
|
||||||
}
|
}
|
||||||
if b != dims.Size.Y {
|
if b != dims.Size.Y {
|
||||||
baseline = b
|
baseline = b
|
||||||
@@ -185,9 +162,9 @@ func (f *Flex) Layout() Dimens {
|
|||||||
case Start:
|
case Start:
|
||||||
mainSize += space
|
mainSize += space
|
||||||
case SpaceEvenly:
|
case SpaceEvenly:
|
||||||
mainSize += space / (1 + len(f.children))
|
mainSize += space / (1 + len(children))
|
||||||
case SpaceAround:
|
case SpaceAround:
|
||||||
mainSize += space / (len(f.children) * 2)
|
mainSize += space / (len(children) * 2)
|
||||||
}
|
}
|
||||||
sz := axisPoint(f.Axis, mainSize, crossSize)
|
sz := axisPoint(f.Axis, mainSize, crossSize)
|
||||||
if baseline == 0 {
|
if baseline == 0 {
|
||||||
|
|||||||
+92
-130
@@ -9,9 +9,7 @@ import (
|
|||||||
"gioui.org/ui"
|
"gioui.org/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Widget interface {
|
type Widget func(ops *ui.Ops, cs Constraints) Dimens
|
||||||
Layout(ops *ui.Ops, cs Constraints) Dimens
|
|
||||||
}
|
|
||||||
|
|
||||||
type Constraints struct {
|
type Constraints struct {
|
||||||
Width Constraint
|
Width Constraint
|
||||||
@@ -29,8 +27,6 @@ type Dimens struct {
|
|||||||
|
|
||||||
type Axis uint8
|
type Axis uint8
|
||||||
|
|
||||||
type F func(ops *ui.Ops, cs Constraints) Dimens
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Horizontal Axis = iota
|
Horizontal Axis = iota
|
||||||
Vertical
|
Vertical
|
||||||
@@ -73,147 +69,113 @@ func ExactConstraints(size image.Point) Constraints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f F) Layout(ops *ui.Ops, cs Constraints) Dimens {
|
type Insets struct {
|
||||||
return f(ops, cs)
|
W Widget
|
||||||
|
|
||||||
|
Top, Right, Bottom, Left float32
|
||||||
}
|
}
|
||||||
|
|
||||||
type Margins struct {
|
func (in Insets) Layout(ops *ui.Ops, cs Constraints) Dimens {
|
||||||
Top, Right, Bottom, Left ui.Value
|
mcs := cs
|
||||||
|
t, r, b, l := int(math.Round(float64(in.Top))), int(math.Round(float64(in.Right))), int(math.Round(float64(in.Bottom))), int(math.Round(float64(in.Left)))
|
||||||
|
if mcs.Width.Max != ui.Inf {
|
||||||
|
mcs.Width.Min -= l + r
|
||||||
|
mcs.Width.Max -= l + r
|
||||||
|
if mcs.Width.Min < 0 {
|
||||||
|
mcs.Width.Min = 0
|
||||||
|
}
|
||||||
|
if mcs.Width.Max < mcs.Width.Min {
|
||||||
|
mcs.Width.Max = mcs.Width.Min
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mcs.Height.Max != ui.Inf {
|
||||||
|
mcs.Height.Min -= t + b
|
||||||
|
mcs.Height.Max -= t + b
|
||||||
|
if mcs.Height.Min < 0 {
|
||||||
|
mcs.Height.Min = 0
|
||||||
|
}
|
||||||
|
if mcs.Height.Max < mcs.Height.Min {
|
||||||
|
mcs.Height.Max = mcs.Height.Min
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ops.Begin()
|
||||||
|
ui.OpTransform{Transform: ui.Offset(toPointF(image.Point{X: l, Y: t}))}.Add(ops)
|
||||||
|
dims := in.W(ops, mcs)
|
||||||
|
ops.End().Add(ops)
|
||||||
|
return Dimens{
|
||||||
|
Size: cs.Constrain(dims.Size.Add(image.Point{X: r + l, Y: t + b})),
|
||||||
|
Baseline: dims.Baseline + t,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Margin(c *ui.Config, m Margins, w Widget) Widget {
|
func EqualInsets(v float32, w Widget) Insets {
|
||||||
return F(func(ops *ui.Ops, cs Constraints) Dimens {
|
return Insets{W: w, Top: v, Right: v, Bottom: v, Left: v}
|
||||||
mcs := cs
|
|
||||||
t, r, b, l := int(c.Pixels(m.Top)+0.5), int(c.Pixels(m.Right)+0.5), int(c.Pixels(m.Bottom)+0.5), int(c.Pixels(m.Left)+0.5)
|
|
||||||
if mcs.Width.Max != ui.Inf {
|
|
||||||
mcs.Width.Min -= l + r
|
|
||||||
mcs.Width.Max -= l + r
|
|
||||||
if mcs.Width.Min < 0 {
|
|
||||||
mcs.Width.Min = 0
|
|
||||||
}
|
|
||||||
if mcs.Width.Max < mcs.Width.Min {
|
|
||||||
mcs.Width.Max = mcs.Width.Min
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if mcs.Height.Max != ui.Inf {
|
|
||||||
mcs.Height.Min -= t + b
|
|
||||||
mcs.Height.Max -= t + b
|
|
||||||
if mcs.Height.Min < 0 {
|
|
||||||
mcs.Height.Min = 0
|
|
||||||
}
|
|
||||||
if mcs.Height.Max < mcs.Height.Min {
|
|
||||||
mcs.Height.Max = mcs.Height.Min
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ops.Begin()
|
|
||||||
ui.OpTransform{Transform: ui.Offset(toPointF(image.Point{X: l, Y: t}))}.Add(ops)
|
|
||||||
dims := w.Layout(ops, mcs)
|
|
||||||
ops.End().Add(ops)
|
|
||||||
return Dimens{
|
|
||||||
Size: cs.Constrain(dims.Size.Add(image.Point{X: r + l, Y: t + b})),
|
|
||||||
Baseline: dims.Baseline + t,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func EqualMargins(v ui.Value) Margins {
|
|
||||||
return Margins{Top: v, Right: v, Bottom: v, Left: v}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isInf(v ui.Value) bool {
|
func isInf(v ui.Value) bool {
|
||||||
return math.IsInf(float64(v.V), 1)
|
return math.IsInf(float64(v.V), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Capped(c *ui.Config, maxWidth, maxHeight ui.Value, wt Widget) Widget {
|
type Sized struct {
|
||||||
return F(func(ops *ui.Ops, cs Constraints) Dimens {
|
W Widget
|
||||||
if !isInf(maxWidth) {
|
Width, Height float32
|
||||||
mw := int(c.Pixels(maxWidth) + .5)
|
|
||||||
if mw < cs.Width.Min {
|
|
||||||
mw = cs.Width.Min
|
|
||||||
}
|
|
||||||
if mw < cs.Width.Max {
|
|
||||||
cs.Width.Max = mw
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !isInf(maxHeight) {
|
|
||||||
mh := int(c.Pixels(maxHeight) + 0.5)
|
|
||||||
if mh < cs.Height.Min {
|
|
||||||
mh = cs.Height.Min
|
|
||||||
}
|
|
||||||
if mh < cs.Height.Max {
|
|
||||||
cs.Height.Max = mh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wt.Layout(ops, cs)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Sized(c *ui.Config, width, height ui.Value, wt Widget) Widget {
|
func (s Sized) Layout(ops *ui.Ops, cs Constraints) Dimens {
|
||||||
return F(func(ops *ui.Ops, cs Constraints) Dimens {
|
if h := int(s.Height + 0.5); h != 0 {
|
||||||
if h := int(c.Pixels(height) + 0.5); h != 0 {
|
if cs.Height.Min < h {
|
||||||
if cs.Height.Min < h {
|
cs.Height.Min = h
|
||||||
cs.Height.Min = h
|
|
||||||
}
|
|
||||||
if h < cs.Height.Max {
|
|
||||||
cs.Height.Max = h
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if w := int(c.Pixels(width) + .5); w != 0 {
|
if h < cs.Height.Max {
|
||||||
if cs.Width.Min < w {
|
cs.Height.Max = h
|
||||||
cs.Width.Min = w
|
|
||||||
}
|
|
||||||
if w < cs.Width.Max {
|
|
||||||
cs.Width.Max = w
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return wt.Layout(ops, cs)
|
}
|
||||||
})
|
if w := int(s.Width + .5); w != 0 {
|
||||||
|
if cs.Width.Min < w {
|
||||||
|
cs.Width.Min = w
|
||||||
|
}
|
||||||
|
if w < cs.Width.Max {
|
||||||
|
cs.Width.Max = w
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.W(ops, cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Expand(w Widget) Widget {
|
type Align struct {
|
||||||
return F(func(ops *ui.Ops, cs Constraints) Dimens {
|
W Widget
|
||||||
if cs.Height.Max != ui.Inf {
|
Alignment Direction
|
||||||
cs.Height.Min = cs.Height.Max
|
|
||||||
}
|
|
||||||
if cs.Width.Max != ui.Inf {
|
|
||||||
cs.Width.Min = cs.Width.Max
|
|
||||||
}
|
|
||||||
return w.Layout(ops, cs)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Align(alignment Direction, w Widget) Widget {
|
func (a Align) Layout(ops *ui.Ops, cs Constraints) Dimens {
|
||||||
return F(func(ops *ui.Ops, cs Constraints) Dimens {
|
ops.Begin()
|
||||||
ops.Begin()
|
dims := a.W(ops, cs.Loose())
|
||||||
dims := w.Layout(ops, cs.Loose())
|
block := ops.End()
|
||||||
block := ops.End()
|
sz := dims.Size
|
||||||
sz := dims.Size
|
if cs.Width.Max != ui.Inf {
|
||||||
if cs.Width.Max != ui.Inf {
|
sz.X = cs.Width.Max
|
||||||
sz.X = cs.Width.Max
|
}
|
||||||
}
|
if cs.Height.Max != ui.Inf {
|
||||||
if cs.Height.Max != ui.Inf {
|
sz.Y = cs.Height.Max
|
||||||
sz.Y = cs.Height.Max
|
}
|
||||||
}
|
var p image.Point
|
||||||
var p image.Point
|
switch a.Alignment {
|
||||||
switch alignment {
|
case N, S, Center:
|
||||||
case N, S, Center:
|
p.X = (sz.X - dims.Size.X) / 2
|
||||||
p.X = (sz.X - dims.Size.X) / 2
|
case NE, SE, E:
|
||||||
case NE, SE, E:
|
p.X = sz.X - dims.Size.X
|
||||||
p.X = sz.X - dims.Size.X
|
}
|
||||||
}
|
switch a.Alignment {
|
||||||
switch alignment {
|
case W, Center, E:
|
||||||
case W, Center, E:
|
p.Y = (sz.Y - dims.Size.Y) / 2
|
||||||
p.Y = (sz.Y - dims.Size.Y) / 2
|
case SW, S, SE:
|
||||||
case SW, S, SE:
|
p.Y = sz.Y - dims.Size.Y
|
||||||
p.Y = sz.Y - dims.Size.Y
|
}
|
||||||
}
|
ops.Begin()
|
||||||
ops.Begin()
|
ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(ops)
|
||||||
ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(ops)
|
block.Add(ops)
|
||||||
block.Add(ops)
|
ops.End().Add(ops)
|
||||||
ops.End().Add(ops)
|
return Dimens{
|
||||||
return Dimens{
|
Size: sz,
|
||||||
Size: sz,
|
Baseline: dims.Baseline,
|
||||||
Baseline: dims.Baseline,
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-23
@@ -35,9 +35,9 @@ type List struct {
|
|||||||
cs Constraints
|
cs Constraints
|
||||||
len int
|
len int
|
||||||
|
|
||||||
maxSize int
|
maxSize int
|
||||||
children []scrollChild
|
children []scrollChild
|
||||||
elem func(w Widget)
|
elemForward bool
|
||||||
|
|
||||||
size image.Point
|
size image.Point
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,6 @@ func (l *List) Init(ops *ui.Ops, cs Constraints, len int) (int, bool) {
|
|||||||
l.ops = ops
|
l.ops = ops
|
||||||
l.cs = cs
|
l.cs = cs
|
||||||
l.len = len
|
l.len = len
|
||||||
l.elem = nil
|
|
||||||
if l.first > len {
|
if l.first > len {
|
||||||
l.first = len
|
l.first = len
|
||||||
}
|
}
|
||||||
@@ -88,7 +87,7 @@ func (l *List) next() (int, bool) {
|
|||||||
mainc := axisMainConstraint(l.Axis, l.cs)
|
mainc := axisMainConstraint(l.Axis, l.cs)
|
||||||
if l.offset <= 0 {
|
if l.offset <= 0 {
|
||||||
if l.first > 0 {
|
if l.first > 0 {
|
||||||
l.elem = l.backward
|
l.elemForward = false
|
||||||
return l.first - 1, true
|
return l.first - 1, true
|
||||||
}
|
}
|
||||||
l.offset = 0
|
l.offset = 0
|
||||||
@@ -96,7 +95,7 @@ func (l *List) next() (int, bool) {
|
|||||||
if l.maxSize-l.offset < mainc.Max {
|
if l.maxSize-l.offset < mainc.Max {
|
||||||
i := l.first + len(l.children)
|
i := l.first + len(l.children)
|
||||||
if i < l.len {
|
if i < l.len {
|
||||||
l.elem = l.forward
|
l.elemForward = true
|
||||||
return i, true
|
return i, true
|
||||||
}
|
}
|
||||||
missing := mainc.Max - (l.maxSize - l.offset)
|
missing := mainc.Max - (l.maxSize - l.offset)
|
||||||
@@ -109,30 +108,25 @@ func (l *List) next() (int, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *List) Elem(w Widget) {
|
func (l *List) Elem(w Widget) {
|
||||||
l.elem(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *List) backward(w Widget) {
|
|
||||||
l.first--
|
|
||||||
child := l.add(w)
|
child := l.add(w)
|
||||||
mainSize := axisMain(l.Axis, child.size)
|
if l.elemForward {
|
||||||
l.offset += mainSize
|
mainSize := axisMain(l.Axis, child.size)
|
||||||
l.maxSize += mainSize
|
l.maxSize += mainSize
|
||||||
l.children = append([]scrollChild{child}, l.children...)
|
l.children = append(l.children, child)
|
||||||
}
|
} else {
|
||||||
|
l.first--
|
||||||
func (l *List) forward(w Widget) {
|
mainSize := axisMain(l.Axis, child.size)
|
||||||
child := l.add(w)
|
l.offset += mainSize
|
||||||
mainSize := axisMain(l.Axis, child.size)
|
l.maxSize += mainSize
|
||||||
l.maxSize += mainSize
|
l.children = append([]scrollChild{child}, l.children...)
|
||||||
l.children = append(l.children, child)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *List) add(w Widget) scrollChild {
|
func (l *List) add(w Widget) scrollChild {
|
||||||
subcs := axisConstraints(l.Axis, Constraint{Max: ui.Inf}, l.crossConstraintChild(l.cs))
|
subcs := axisConstraints(l.Axis, Constraint{Max: ui.Inf}, l.crossConstraintChild(l.cs))
|
||||||
l.ops.Begin()
|
l.ops.Begin()
|
||||||
ui.OpLayer{}.Add(l.ops)
|
ui.OpLayer{}.Add(l.ops)
|
||||||
dims := w.Layout(l.ops, subcs)
|
dims := w(l.ops, subcs)
|
||||||
block := l.ops.End()
|
block := l.ops.End()
|
||||||
return scrollChild{dims.Size, block}
|
return scrollChild{dims.Size, block}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-44
@@ -9,18 +9,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Stack struct {
|
type Stack struct {
|
||||||
Alignment Direction
|
Alignment Direction
|
||||||
|
Constraints Constraints
|
||||||
|
|
||||||
ops *ui.Ops
|
|
||||||
cs Constraints
|
|
||||||
children []stackChild
|
|
||||||
maxSZ image.Point
|
maxSZ image.Point
|
||||||
baseline int
|
baseline int
|
||||||
|
|
||||||
ccache [10]stackChild
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type stackChild struct {
|
type StackChild struct {
|
||||||
block ui.OpBlock
|
block ui.OpBlock
|
||||||
dims Dimens
|
dims Dimens
|
||||||
}
|
}
|
||||||
@@ -38,23 +34,11 @@ const (
|
|||||||
W
|
W
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Stack) Init(ops *ui.Ops, cs Constraints) *Stack {
|
func (s *Stack) Rigid(ops *ui.Ops, w Widget) StackChild {
|
||||||
if s.children == nil {
|
ops.Begin()
|
||||||
s.children = s.ccache[:0]
|
ui.OpLayer{}.Add(ops)
|
||||||
}
|
dims := w(ops, s.Constraints)
|
||||||
s.children = s.children[:0]
|
b := ops.End()
|
||||||
s.maxSZ = image.Point{}
|
|
||||||
s.baseline = 0
|
|
||||||
s.ops = ops
|
|
||||||
s.cs = cs
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack) Rigid(w Widget) *Stack {
|
|
||||||
s.ops.Begin()
|
|
||||||
ui.OpLayer{}.Add(s.ops)
|
|
||||||
dims := w.Layout(s.ops, s.cs)
|
|
||||||
b := s.ops.End()
|
|
||||||
if w := dims.Size.X; w > s.maxSZ.X {
|
if w := dims.Size.X; w > s.maxSZ.X {
|
||||||
s.maxSZ.X = w
|
s.maxSZ.X = w
|
||||||
}
|
}
|
||||||
@@ -62,27 +46,20 @@ func (s *Stack) Rigid(w Widget) *Stack {
|
|||||||
s.maxSZ.Y = h
|
s.maxSZ.Y = h
|
||||||
}
|
}
|
||||||
s.addjustBaseline(dims)
|
s.addjustBaseline(dims)
|
||||||
s.children = append(s.children, stackChild{b, dims})
|
return StackChild{b, dims}
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) Expand(idx int, w Widget) *Stack {
|
func (s *Stack) Expand(ops *ui.Ops, w Widget) StackChild {
|
||||||
cs := Constraints{
|
cs := Constraints{
|
||||||
Width: Constraint{Min: s.maxSZ.X, Max: s.maxSZ.X},
|
Width: Constraint{Min: s.maxSZ.X, Max: s.maxSZ.X},
|
||||||
Height: Constraint{Min: s.maxSZ.Y, Max: s.maxSZ.Y},
|
Height: Constraint{Min: s.maxSZ.Y, Max: s.maxSZ.Y},
|
||||||
}
|
}
|
||||||
s.ops.Begin()
|
ops.Begin()
|
||||||
ui.OpLayer{}.Add(s.ops)
|
ui.OpLayer{}.Add(ops)
|
||||||
dims := w.Layout(s.ops, cs)
|
dims := w(ops, cs)
|
||||||
b := s.ops.End()
|
b := ops.End()
|
||||||
s.addjustBaseline(dims)
|
s.addjustBaseline(dims)
|
||||||
if idx < 0 {
|
return StackChild{b, dims}
|
||||||
idx += len(s.children) + 1
|
|
||||||
}
|
|
||||||
s.children = append(s.children, stackChild{})
|
|
||||||
copy(s.children[idx+1:], s.children[idx:])
|
|
||||||
s.children[idx] = stackChild{b, dims}
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) addjustBaseline(dims Dimens) {
|
func (s *Stack) addjustBaseline(dims Dimens) {
|
||||||
@@ -93,8 +70,8 @@ func (s *Stack) addjustBaseline(dims Dimens) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) Layout() Dimens {
|
func (s *Stack) Layout(ops *ui.Ops, children ...StackChild) Dimens {
|
||||||
for _, ch := range s.children {
|
for _, ch := range children {
|
||||||
sz := ch.dims.Size
|
sz := ch.dims.Size
|
||||||
var p image.Point
|
var p image.Point
|
||||||
switch s.Alignment {
|
switch s.Alignment {
|
||||||
@@ -109,10 +86,10 @@ func (s *Stack) Layout() Dimens {
|
|||||||
case SW, S, SE:
|
case SW, S, SE:
|
||||||
p.Y = s.maxSZ.Y - sz.Y
|
p.Y = s.maxSZ.Y - sz.Y
|
||||||
}
|
}
|
||||||
s.ops.Begin()
|
ops.Begin()
|
||||||
ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(s.ops)
|
ui.OpTransform{Transform: ui.Offset(toPointF(p))}.Add(ops)
|
||||||
ch.block.Add(s.ops)
|
ch.block.Add(ops)
|
||||||
s.ops.End().Add(s.ops)
|
ops.End().Add(ops)
|
||||||
}
|
}
|
||||||
b := s.baseline
|
b := s.baseline
|
||||||
if b == 0 {
|
if b == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user