shiny/widget: let a Flow shrink as well as expand.
This will be needed for scrollable Sheets, where the parent (the Sheet)
should be laid out at a smaller size than its child.
Change-Id: Iacf69c90f263f24f9fd149f3864d23737c1593a8
Reviewed-on: https://go-review.googlesource.com/28345
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/shiny/example/layout/main.go b/shiny/example/layout/main.go
index fcf1a3c..b5cac9d 100644
--- a/shiny/example/layout/main.go
+++ b/shiny/example/layout/main.go
@@ -46,17 +46,17 @@
widget.NewLabel("Cyan:"),
widget.WithLayoutData(
colorPatch(color.RGBA{0x00, 0x7f, 0x7f, 0xff}, px(0), px(20)),
- widget.FlowLayoutData{ExpandAlongWeight: 1},
+ widget.FlowLayoutData{AlongWeight: 1, ExpandAlong: true},
),
widget.NewLabel("Magenta:"),
widget.WithLayoutData(
colorPatch(color.RGBA{0x7f, 0x00, 0x7f, 0xff}, px(0), px(30)),
- widget.FlowLayoutData{ExpandAlongWeight: 2},
+ widget.FlowLayoutData{AlongWeight: 2, ExpandAlong: true},
),
widget.NewLabel("Yellow:"),
widget.WithLayoutData(
colorPatch(color.RGBA{0x7f, 0x7f, 0x00, 0xff}, px(0), px(40)),
- widget.FlowLayoutData{ExpandAlongWeight: 3},
+ widget.FlowLayoutData{AlongWeight: 3, ExpandAlong: true},
),
)
diff --git a/shiny/example/textedit/main.go b/shiny/example/textedit/main.go
index de8929a..b47ba17 100644
--- a/shiny/example/textedit/main.go
+++ b/shiny/example/textedit/main.go
@@ -25,10 +25,13 @@
"golang.org/x/exp/shiny/widget/theme"
)
-func expand(n node.Node, expandAlongWeight int) node.Node {
+func stretch(n node.Node, alongWeight int) node.Node {
return widget.WithLayoutData(n, widget.FlowLayoutData{
- ExpandAcross: true,
- ExpandAlongWeight: expandAlongWeight,
+ AlongWeight: alongWeight,
+ ExpandAlong: true,
+ ShrinkAlong: true,
+ ExpandAcross: true,
+ ShrinkAcross: true,
})
}
@@ -39,7 +42,7 @@
widget.NewPadder(widget.AxisBoth, unit.Ems(0.5),
widget.NewFlow(widget.AxisHorizontal,
widget.NewLabel("TODO: status"),
- expand(widget.NewSpace(), 1),
+ stretch(widget.NewSpace(), 1),
widget.NewLabel("TODO: Menu"),
),
),
@@ -50,10 +53,10 @@
body := widget.NewText(prideAndPrejudice)
w := widget.NewFlow(widget.AxisVertical,
- expand(widget.NewSheet(header), 0),
- expand(widget.NewSheet(divider), 0),
+ stretch(widget.NewSheet(header), 0),
+ stretch(widget.NewSheet(divider), 0),
// TODO: make the body's sheet scrollable.
- expand(widget.NewSheet(body), 1),
+ stretch(widget.NewSheet(body), 1),
)
if err := widget.RunWindow(s, w, nil); err != nil {
diff --git a/shiny/widget/flow.go b/shiny/widget/flow.go
index 29c85d1..9dcc5a2 100644
--- a/shiny/widget/flow.go
+++ b/shiny/widget/flow.go
@@ -71,46 +71,73 @@
return
}
- eaExtra, eaWeight := 0, 0
+ extra, totalExpandWeight, totalShrinkWeight := 0, 0, 0
if w.Axis == AxisHorizontal {
- eaExtra = w.Rect.Dx()
+ extra = w.Rect.Dx()
} else {
- eaExtra = w.Rect.Dy()
+ extra = w.Rect.Dy()
}
for c := w.FirstChild; c != nil; c = c.NextSibling {
- if d, ok := c.LayoutData.(FlowLayoutData); ok && d.ExpandAlongWeight > 0 {
- eaWeight += d.ExpandAlongWeight
+ if d, ok := c.LayoutData.(FlowLayoutData); ok && d.AlongWeight > 0 {
+ if d.AlongWeight <= 0 {
+ continue
+ }
+ if d.ExpandAlong {
+ totalExpandWeight += d.AlongWeight
+ }
+ if d.ShrinkAlong {
+ totalShrinkWeight += d.AlongWeight
+ }
}
if w.Axis == AxisHorizontal {
- eaExtra -= c.MeasuredSize.X
+ extra -= c.MeasuredSize.X
} else {
- eaExtra -= c.MeasuredSize.Y
+ extra -= c.MeasuredSize.Y
}
}
- if eaExtra < 0 {
- eaExtra = 0
+ expand, shrink, totalWeight := extra > 0, extra < 0, 0
+ if expand {
+ if totalExpandWeight == 0 {
+ expand = false
+ } else {
+ totalWeight = totalExpandWeight
+ }
+ }
+ if shrink {
+ if totalShrinkWeight == 0 {
+ shrink = false
+ } else {
+ totalWeight = totalShrinkWeight
+ }
}
p := image.Point{}
for c := w.FirstChild; c != nil; c = c.NextSibling {
q := p.Add(c.MeasuredSize)
if d, ok := c.LayoutData.(FlowLayoutData); ok {
- if d.ExpandAlongWeight > 0 {
- delta := eaExtra * d.ExpandAlongWeight / eaWeight
- eaExtra -= delta
- eaWeight -= d.ExpandAlongWeight
- if w.Axis == AxisHorizontal {
- q.X += delta
- } else {
- q.Y += delta
+ if d.AlongWeight > 0 {
+ if (expand && d.ExpandAlong) || (shrink && d.ShrinkAlong) {
+ delta := extra * d.AlongWeight / totalWeight
+ extra -= delta
+ totalWeight -= d.AlongWeight
+ if w.Axis == AxisHorizontal {
+ q.X += delta
+ if q.X < p.X {
+ q.X = p.X
+ }
+ } else {
+ q.Y += delta
+ if q.Y < p.Y {
+ q.Y = p.Y
+ }
+ }
}
}
- if d.ExpandAcross {
- if w.Axis == AxisHorizontal {
- q.Y = max(q.Y, w.Rect.Dy())
- } else {
- q.X = max(q.X, w.Rect.Dx())
- }
+
+ if w.Axis == AxisHorizontal {
+ q.Y = stretchAcross(q.Y, w.Rect.Dy(), d.ExpandAcross, d.ShrinkAcross)
+ } else {
+ q.X = stretchAcross(q.X, w.Rect.Dx(), d.ExpandAcross, d.ShrinkAcross)
}
}
c.Rect = image.Rectangle{
@@ -126,19 +153,55 @@
}
}
+func stretchAcross(child, parent int, expand, shrink bool) int {
+ if (expand && child < parent) || (shrink && child > parent) {
+ return parent
+ }
+ return child
+}
+
// FlowLayoutData is the node LayoutData type for a Flow's children.
type FlowLayoutData struct {
- // ExpandAlongWeight is the relative weight for distributing any excess
- // space along the Flow's axis. For example, if an AxisHorizontal Flow's
+ // AlongWeight is the relative weight for distributing any space surplus or
+ // deficit along the Flow's axis. For example, if an AxisHorizontal Flow's
// Rect width was 100 pixels greater than the sum of its children's natural
- // widths, and three children had non-zero FlowLayoutData.ExpandAlongWeight
- // values 6, 3 and 1, then those children's laid out widths would be larger
- // than their natural widths by 60, 30 and 10 pixels.
- ExpandAlongWeight int
+ // widths, and three children had non-zero FlowLayoutData.AlongWeight
+ // values 6, 3 and 1 (and their FlowLayoutData.ExpandAlong values were
+ // true) then those children's laid out widths would be larger than their
+ // natural widths by 60, 30 and 10 pixels.
+ //
+ // A negative AlongWeight is equivalent to zero.
+ AlongWeight int
- // ExpandAcross is whether the child's laid out size should expand to fill
- // the Flow's cross-axis. For example, if an AxisHorizontal Flow's Rect
- // height was 80 pixels, any child whose FlowLayoutData.ExpandAcross was
- // true would also be laid out with at least an 80 pixel height.
+ // ExpandAlong is whether the child's laid out size should increase along
+ // the Flow's axis, based on AlongWeight, if there is a space surplus (the
+ // children's measured size total less than the parent's size). To allow
+ // size decreases as well as increases, set ShrinkAlong.
+ ExpandAlong bool
+
+ // ShrinkAlong is whether the child's laid out size should decrease along
+ // the Flow's axis, based on AlongWeight, if there is a space deficit (the
+ // children's measured size total more than the parent's size). To allow
+ // size increases as well as decreases, set ExpandAlong.
+ ShrinkAlong bool
+
+ // ExpandAcross is whether the child's laid out size should increase along
+ // the Flow's cross-axis if there is a space surplus (the child's measured
+ // size is less than the parent's size). To allow size decreases as well as
+ // increases, set ShrinkAcross.
+ //
+ // For example, if an AxisHorizontal Flow's Rect height was 80 pixels, any
+ // child whose FlowLayoutData.ExpandAcross was true would also be laid out
+ // with at least an 80 pixel height.
ExpandAcross bool
+
+ // ShrinkAcross is whether the child's laid out size should decrease along
+ // the Flow's cross-axis if there is a space deficit (the child's measured
+ // size is more than the parent's size). To allow size increases as well as
+ // decreases, set ExpandAcross.
+ //
+ // For example, if an AxisHorizontal Flow's Rect height was 80 pixels, any
+ // child whose FlowLayoutData.ShrinkAcross was true would also be laid out
+ // with at most an 80 pixel height.
+ ShrinkAcross bool
}
diff --git a/shiny/widget/widget.go b/shiny/widget/widget.go
index d45108d..0dcbf63 100644
--- a/shiny/widget/widget.go
+++ b/shiny/widget/widget.go
@@ -22,13 +22,6 @@
"golang.org/x/mobile/event/size"
)
-func max(x, y int) int {
- if x > y {
- return x
- }
- return y
-}
-
// Axis is zero, one or both of the horizontal and vertical axes. For example,
// a widget may be scrollable in one of the four AxisXxx values.
type Axis uint8