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>
This commit is contained in:
Родитель
da927ba5e2
Коммит
14f0c66cee
|
@ -46,17 +46,17 @@ func main() {
|
||||||
widget.NewLabel("Cyan:"),
|
widget.NewLabel("Cyan:"),
|
||||||
widget.WithLayoutData(
|
widget.WithLayoutData(
|
||||||
colorPatch(color.RGBA{0x00, 0x7f, 0x7f, 0xff}, px(0), px(20)),
|
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.NewLabel("Magenta:"),
|
||||||
widget.WithLayoutData(
|
widget.WithLayoutData(
|
||||||
colorPatch(color.RGBA{0x7f, 0x00, 0x7f, 0xff}, px(0), px(30)),
|
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.NewLabel("Yellow:"),
|
||||||
widget.WithLayoutData(
|
widget.WithLayoutData(
|
||||||
colorPatch(color.RGBA{0x7f, 0x7f, 0x00, 0xff}, px(0), px(40)),
|
colorPatch(color.RGBA{0x7f, 0x7f, 0x00, 0xff}, px(0), px(40)),
|
||||||
widget.FlowLayoutData{ExpandAlongWeight: 3},
|
widget.FlowLayoutData{AlongWeight: 3, ExpandAlong: true},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,13 @@ import (
|
||||||
"golang.org/x/exp/shiny/widget/theme"
|
"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{
|
return widget.WithLayoutData(n, widget.FlowLayoutData{
|
||||||
ExpandAcross: true,
|
AlongWeight: alongWeight,
|
||||||
ExpandAlongWeight: expandAlongWeight,
|
ExpandAlong: true,
|
||||||
|
ShrinkAlong: true,
|
||||||
|
ExpandAcross: true,
|
||||||
|
ShrinkAcross: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +42,7 @@ func main() {
|
||||||
widget.NewPadder(widget.AxisBoth, unit.Ems(0.5),
|
widget.NewPadder(widget.AxisBoth, unit.Ems(0.5),
|
||||||
widget.NewFlow(widget.AxisHorizontal,
|
widget.NewFlow(widget.AxisHorizontal,
|
||||||
widget.NewLabel("TODO: status"),
|
widget.NewLabel("TODO: status"),
|
||||||
expand(widget.NewSpace(), 1),
|
stretch(widget.NewSpace(), 1),
|
||||||
widget.NewLabel("TODO: Menu"),
|
widget.NewLabel("TODO: Menu"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -50,10 +53,10 @@ func main() {
|
||||||
body := widget.NewText(prideAndPrejudice)
|
body := widget.NewText(prideAndPrejudice)
|
||||||
|
|
||||||
w := widget.NewFlow(widget.AxisVertical,
|
w := widget.NewFlow(widget.AxisVertical,
|
||||||
expand(widget.NewSheet(header), 0),
|
stretch(widget.NewSheet(header), 0),
|
||||||
expand(widget.NewSheet(divider), 0),
|
stretch(widget.NewSheet(divider), 0),
|
||||||
// TODO: make the body's sheet scrollable.
|
// 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 {
|
if err := widget.RunWindow(s, w, nil); err != nil {
|
||||||
|
|
|
@ -71,46 +71,73 @@ func (w *Flow) Layout(t *theme.Theme) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
eaExtra, eaWeight := 0, 0
|
extra, totalExpandWeight, totalShrinkWeight := 0, 0, 0
|
||||||
if w.Axis == AxisHorizontal {
|
if w.Axis == AxisHorizontal {
|
||||||
eaExtra = w.Rect.Dx()
|
extra = w.Rect.Dx()
|
||||||
} else {
|
} else {
|
||||||
eaExtra = w.Rect.Dy()
|
extra = w.Rect.Dy()
|
||||||
}
|
}
|
||||||
for c := w.FirstChild; c != nil; c = c.NextSibling {
|
for c := w.FirstChild; c != nil; c = c.NextSibling {
|
||||||
if d, ok := c.LayoutData.(FlowLayoutData); ok && d.ExpandAlongWeight > 0 {
|
if d, ok := c.LayoutData.(FlowLayoutData); ok && d.AlongWeight > 0 {
|
||||||
eaWeight += d.ExpandAlongWeight
|
if d.AlongWeight <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.ExpandAlong {
|
||||||
|
totalExpandWeight += d.AlongWeight
|
||||||
|
}
|
||||||
|
if d.ShrinkAlong {
|
||||||
|
totalShrinkWeight += d.AlongWeight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if w.Axis == AxisHorizontal {
|
if w.Axis == AxisHorizontal {
|
||||||
eaExtra -= c.MeasuredSize.X
|
extra -= c.MeasuredSize.X
|
||||||
} else {
|
} else {
|
||||||
eaExtra -= c.MeasuredSize.Y
|
extra -= c.MeasuredSize.Y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if eaExtra < 0 {
|
expand, shrink, totalWeight := extra > 0, extra < 0, 0
|
||||||
eaExtra = 0
|
if expand {
|
||||||
|
if totalExpandWeight == 0 {
|
||||||
|
expand = false
|
||||||
|
} else {
|
||||||
|
totalWeight = totalExpandWeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if shrink {
|
||||||
|
if totalShrinkWeight == 0 {
|
||||||
|
shrink = false
|
||||||
|
} else {
|
||||||
|
totalWeight = totalShrinkWeight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p := image.Point{}
|
p := image.Point{}
|
||||||
for c := w.FirstChild; c != nil; c = c.NextSibling {
|
for c := w.FirstChild; c != nil; c = c.NextSibling {
|
||||||
q := p.Add(c.MeasuredSize)
|
q := p.Add(c.MeasuredSize)
|
||||||
if d, ok := c.LayoutData.(FlowLayoutData); ok {
|
if d, ok := c.LayoutData.(FlowLayoutData); ok {
|
||||||
if d.ExpandAlongWeight > 0 {
|
if d.AlongWeight > 0 {
|
||||||
delta := eaExtra * d.ExpandAlongWeight / eaWeight
|
if (expand && d.ExpandAlong) || (shrink && d.ShrinkAlong) {
|
||||||
eaExtra -= delta
|
delta := extra * d.AlongWeight / totalWeight
|
||||||
eaWeight -= d.ExpandAlongWeight
|
extra -= delta
|
||||||
if w.Axis == AxisHorizontal {
|
totalWeight -= d.AlongWeight
|
||||||
q.X += delta
|
if w.Axis == AxisHorizontal {
|
||||||
} else {
|
q.X += delta
|
||||||
q.Y += 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 {
|
if w.Axis == AxisHorizontal {
|
||||||
q.Y = max(q.Y, w.Rect.Dy())
|
q.Y = stretchAcross(q.Y, w.Rect.Dy(), d.ExpandAcross, d.ShrinkAcross)
|
||||||
} else {
|
} else {
|
||||||
q.X = max(q.X, w.Rect.Dx())
|
q.X = stretchAcross(q.X, w.Rect.Dx(), d.ExpandAcross, d.ShrinkAcross)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Rect = image.Rectangle{
|
c.Rect = image.Rectangle{
|
||||||
|
@ -126,19 +153,55 @@ func (w *Flow) Layout(t *theme.Theme) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
// FlowLayoutData is the node LayoutData type for a Flow's children.
|
||||||
type FlowLayoutData struct {
|
type FlowLayoutData struct {
|
||||||
// ExpandAlongWeight is the relative weight for distributing any excess
|
// AlongWeight is the relative weight for distributing any space surplus or
|
||||||
// space along the Flow's axis. For example, if an AxisHorizontal Flow's
|
// 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
|
// Rect width was 100 pixels greater than the sum of its children's natural
|
||||||
// widths, and three children had non-zero FlowLayoutData.ExpandAlongWeight
|
// widths, and three children had non-zero FlowLayoutData.AlongWeight
|
||||||
// values 6, 3 and 1, then those children's laid out widths would be larger
|
// values 6, 3 and 1 (and their FlowLayoutData.ExpandAlong values were
|
||||||
// than their natural widths by 60, 30 and 10 pixels.
|
// true) then those children's laid out widths would be larger than their
|
||||||
ExpandAlongWeight int
|
// 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
|
// ExpandAlong is whether the child's laid out size should increase along
|
||||||
// the Flow's cross-axis. For example, if an AxisHorizontal Flow's Rect
|
// the Flow's axis, based on AlongWeight, if there is a space surplus (the
|
||||||
// height was 80 pixels, any child whose FlowLayoutData.ExpandAcross was
|
// children's measured size total less than the parent's size). To allow
|
||||||
// true would also be laid out with at least an 80 pixel height.
|
// 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
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,6 @@ import (
|
||||||
"golang.org/x/mobile/event/size"
|
"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,
|
// 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.
|
// a widget may be scrollable in one of the four AxisXxx values.
|
||||||
type Axis uint8
|
type Axis uint8
|
||||||
|
|
Загрузка…
Ссылка в новой задаче