forked from joejulian/gio
layout: change Widget to take explicit Context and return explicit Dimensions
Change the definition of Widget from the implicit
type Widget func()
to the explicit functional
type Widget func(gtx layout.Context) layout.Dimensions
The advantages are numerous:
- Clearer connection between the incoming context and the output dimensions.
- Returning the Dimensions are impossible to omit.
- Contexts passed by value, so its fields can be exported
and freely mutated by the program.
The only disadvantage is the longer function literals and the many "returns".
What tipped the scales in favour of the explicit Widget variant is that type
aliases can dramatically shorten the literals:
type (
C = layout.Context
D = layout.Dimensions
)
widget := func(gtx C) D {
...
}
Note that the aliases are not part of the Gio API and it is up to each user
whether they want to use them.
Finally the Go proposal for lightweight function literals,
https://github.com/golang/go/issues/21498, may remove the disadvantage
completely in future.
Context becomes a plain struct with only public fields, and its Reset is
replaced by a NewContext convenience constructor.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+28
-37
@@ -20,63 +20,54 @@ type Context struct {
|
||||
// Constraints track the constraints for the active widget or
|
||||
// layout.
|
||||
Constraints Constraints
|
||||
// Dimensions track the result of the most recent layout
|
||||
// operation.
|
||||
Dimensions Dimensions
|
||||
|
||||
cfg system.Config
|
||||
queue event.Queue
|
||||
Config system.Config
|
||||
Queue event.Queue
|
||||
*op.Ops
|
||||
}
|
||||
|
||||
// layout a widget with a set of constraints and return its
|
||||
// dimensions. The widget dimensions are constrained and the previous
|
||||
// constraints are restored after layout.
|
||||
func ctxLayout(gtx *Context, cs Constraints, w Widget) Dimensions {
|
||||
saved := gtx.Constraints
|
||||
gtx.Constraints = cs
|
||||
gtx.Dimensions = Dimensions{}
|
||||
w()
|
||||
gtx.Dimensions.Size = cs.Constrain(gtx.Dimensions.Size)
|
||||
gtx.Constraints = saved
|
||||
return gtx.Dimensions
|
||||
}
|
||||
|
||||
// Reset the context. The constraints' minimum and maximum values are
|
||||
// set to the size.
|
||||
func (c *Context) Reset(q event.Queue, cfg system.Config, size image.Point) {
|
||||
c.Constraints = Constraints{Min: size, Max: size}
|
||||
c.Dimensions = Dimensions{}
|
||||
c.cfg = cfg
|
||||
c.queue = q
|
||||
if c.Ops == nil {
|
||||
c.Ops = new(op.Ops)
|
||||
// NewContext is a shorthand for
|
||||
//
|
||||
// Context{
|
||||
// Ops: ops,
|
||||
// Queue: q,
|
||||
// Config: cfg,
|
||||
// Constraints: Exact(size),
|
||||
// }
|
||||
//
|
||||
// NewContext calls ops.Reset.
|
||||
func NewContext(ops *op.Ops, q event.Queue, cfg system.Config, size image.Point) Context {
|
||||
ops.Reset()
|
||||
return Context{
|
||||
Ops: ops,
|
||||
Queue: q,
|
||||
Config: cfg,
|
||||
Constraints: Exact(size),
|
||||
}
|
||||
c.Ops.Reset()
|
||||
}
|
||||
|
||||
// Now returns the configuration time or the zero time.
|
||||
func (c *Context) Now() time.Time {
|
||||
if c.cfg == nil {
|
||||
func (c Context) Now() time.Time {
|
||||
if c.Config == nil {
|
||||
return time.Time{}
|
||||
}
|
||||
return c.cfg.Now()
|
||||
return c.Config.Now()
|
||||
}
|
||||
|
||||
// Px maps the value to pixels. If no configuration is set,
|
||||
// Px returns the rounded value of v.
|
||||
func (c *Context) Px(v unit.Value) int {
|
||||
if c.cfg == nil {
|
||||
func (c Context) Px(v unit.Value) int {
|
||||
if c.Config == nil {
|
||||
return int(math.Round(float64(v.V)))
|
||||
}
|
||||
return c.cfg.Px(v)
|
||||
return c.Config.Px(v)
|
||||
}
|
||||
|
||||
// Events returns the events available for the key. If no
|
||||
// queue is configured, Events returns nil.
|
||||
func (c *Context) Events(k event.Tag) []event.Event {
|
||||
if c.queue == nil {
|
||||
func (c Context) Events(k event.Tag) []event.Event {
|
||||
if c.Queue == nil {
|
||||
return nil
|
||||
}
|
||||
return c.queue.Events(k)
|
||||
return c.Queue.Events(k)
|
||||
}
|
||||
|
||||
+7
-8
@@ -13,17 +13,16 @@ in an implicit Context to keep the Widget declaration short.
|
||||
|
||||
For example, to add space above a widget:
|
||||
|
||||
gtx := new(layout.Context)
|
||||
gtx.Reset(...)
|
||||
var gtx layout.Context
|
||||
|
||||
// Configure a top inset.
|
||||
inset := layout.Inset{Top: unit.Dp(8), ...}
|
||||
// Use the inset to lay out a widget.
|
||||
inset.Layout(gtx, func() {
|
||||
// Lay out widget and determine its size given the constraints.
|
||||
// Lay out widget and determine its size given the constraints
|
||||
// in gtx.Constraints.
|
||||
...
|
||||
dims := layout.Dimensions{...}
|
||||
gtx.Dimensions = dims
|
||||
return layout.Dimensions{...}
|
||||
})
|
||||
|
||||
Note that the example does not generate any garbage even though the
|
||||
@@ -37,10 +36,10 @@ be created from a few generic layouts.
|
||||
This example both aligns and insets a child:
|
||||
|
||||
inset := layout.Inset{...}
|
||||
inset.Layout(gtx, func() {
|
||||
inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
align := layout.Align(...)
|
||||
align.Layout(gtx, func() {
|
||||
widget.Layout(gtx, ...)
|
||||
return align.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
return widget.Layout(gtx, ...)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
+51
-34
@@ -5,24 +5,29 @@ import (
|
||||
"image"
|
||||
|
||||
"gioui.org/layout"
|
||||
"gioui.org/op"
|
||||
"gioui.org/unit"
|
||||
)
|
||||
|
||||
func ExampleInset() {
|
||||
gtx := new(layout.Context)
|
||||
gtx.Reset(nil, nil, image.Point{X: 100, Y: 100})
|
||||
// Loose constraints with no minimal size.
|
||||
gtx.Constraints.Min = image.Point{}
|
||||
gtx := layout.Context{
|
||||
Ops: new(op.Ops),
|
||||
// Loose constraints with no minimal size.
|
||||
Constraints: layout.Constraints{
|
||||
Max: image.Point{X: 100, Y: 100},
|
||||
},
|
||||
}
|
||||
|
||||
// Inset all edges by 10.
|
||||
inset := layout.UniformInset(unit.Dp(10))
|
||||
inset.Layout(gtx, func() {
|
||||
dims := inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
// Lay out a 50x50 sized widget.
|
||||
layoutWidget(gtx, 50, 50)
|
||||
fmt.Println(gtx.Dimensions.Size)
|
||||
dims := layoutWidget(gtx, 50, 50)
|
||||
fmt.Println(dims.Size)
|
||||
return dims
|
||||
})
|
||||
|
||||
fmt.Println(gtx.Dimensions.Size)
|
||||
fmt.Println(dims.Size)
|
||||
|
||||
// Output:
|
||||
// (50,50)
|
||||
@@ -30,17 +35,20 @@ func ExampleInset() {
|
||||
}
|
||||
|
||||
func ExampleDirection() {
|
||||
gtx := new(layout.Context)
|
||||
// Rigid constraints with both minimum and maximum set.
|
||||
gtx.Reset(nil, nil, image.Point{X: 100, Y: 100})
|
||||
gtx := layout.Context{
|
||||
Ops: new(op.Ops),
|
||||
// Rigid constraints with both minimum and maximum set.
|
||||
Constraints: layout.Exact(image.Point{X: 100, Y: 100}),
|
||||
}
|
||||
|
||||
layout.Center.Layout(gtx, func() {
|
||||
dims := layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
// Lay out a 50x50 sized widget.
|
||||
layoutWidget(gtx, 50, 50)
|
||||
fmt.Println(gtx.Dimensions.Size)
|
||||
dims := layoutWidget(gtx, 50, 50)
|
||||
fmt.Println(dims.Size)
|
||||
return dims
|
||||
})
|
||||
|
||||
fmt.Println(gtx.Dimensions.Size)
|
||||
fmt.Println(dims.Size)
|
||||
|
||||
// Output:
|
||||
// (50,50)
|
||||
@@ -48,19 +56,22 @@ func ExampleDirection() {
|
||||
}
|
||||
|
||||
func ExampleFlex() {
|
||||
gtx := new(layout.Context)
|
||||
gtx.Reset(nil, nil, image.Point{X: 100, Y: 100})
|
||||
gtx := layout.Context{
|
||||
Ops: new(op.Ops),
|
||||
// Rigid constraints with both minimum and maximum set.
|
||||
Constraints: layout.Exact(image.Point{X: 100, Y: 100}),
|
||||
}
|
||||
|
||||
layout.Flex{}.Layout(gtx,
|
||||
// Rigid 10x10 widget.
|
||||
layout.Rigid(func() {
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
fmt.Printf("Rigid: %v\n", gtx.Constraints)
|
||||
layoutWidget(gtx, 10, 10)
|
||||
return layoutWidget(gtx, 10, 10)
|
||||
}),
|
||||
// Child with 50% space allowance.
|
||||
layout.Flexed(0.5, func() {
|
||||
layout.Flexed(0.5, func(gtx layout.Context) layout.Dimensions {
|
||||
fmt.Printf("50%%: %v\n", gtx.Constraints)
|
||||
layoutWidget(gtx, 10, 10)
|
||||
return layoutWidget(gtx, 10, 10)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -70,19 +81,22 @@ func ExampleFlex() {
|
||||
}
|
||||
|
||||
func ExampleStack() {
|
||||
gtx := new(layout.Context)
|
||||
gtx.Reset(nil, nil, image.Point{X: 100, Y: 100})
|
||||
gtx.Constraints.Min = image.Point{}
|
||||
gtx := layout.Context{
|
||||
Ops: new(op.Ops),
|
||||
Constraints: layout.Constraints{
|
||||
Max: image.Point{X: 100, Y: 100},
|
||||
},
|
||||
}
|
||||
|
||||
layout.Stack{}.Layout(gtx,
|
||||
// Force widget to the same size as the second.
|
||||
layout.Expanded(func() {
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
fmt.Printf("Expand: %v\n", gtx.Constraints)
|
||||
layoutWidget(gtx, 10, 10)
|
||||
return layoutWidget(gtx, 10, 10)
|
||||
}),
|
||||
// Rigid 50x50 widget.
|
||||
layout.Stacked(func() {
|
||||
layoutWidget(gtx, 50, 50)
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
return layoutWidget(gtx, 50, 50)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -91,17 +105,20 @@ func ExampleStack() {
|
||||
}
|
||||
|
||||
func ExampleList() {
|
||||
gtx := new(layout.Context)
|
||||
gtx.Reset(nil, nil, image.Point{X: 100, Y: 100})
|
||||
gtx := layout.Context{
|
||||
Ops: new(op.Ops),
|
||||
// Rigid constraints with both minimum and maximum set.
|
||||
Constraints: layout.Exact(image.Point{X: 100, Y: 100}),
|
||||
}
|
||||
|
||||
// The list is 1e6 elements, but only 5 fit the constraints.
|
||||
const listLen = 1e6
|
||||
|
||||
var list layout.List
|
||||
count := 0
|
||||
list.Layout(gtx, listLen, func(i int) {
|
||||
list.Layout(gtx, listLen, func(gtx layout.Context, i int) layout.Dimensions {
|
||||
count++
|
||||
layoutWidget(gtx, 20, 20)
|
||||
return layoutWidget(gtx, 20, 20)
|
||||
})
|
||||
|
||||
fmt.Println(count)
|
||||
@@ -110,8 +127,8 @@ func ExampleList() {
|
||||
// 5
|
||||
}
|
||||
|
||||
func layoutWidget(ctx *layout.Context, width, height int) {
|
||||
ctx.Dimensions = layout.Dimensions{
|
||||
func layoutWidget(ctx layout.Context, width, height int) layout.Dimensions {
|
||||
return layout.Dimensions{
|
||||
Size: image.Point{
|
||||
X: width,
|
||||
Y: height,
|
||||
|
||||
+8
-4
@@ -74,7 +74,7 @@ func Flexed(weight float32, widget Widget) FlexChild {
|
||||
// Layout a list of children. The position of the children are
|
||||
// determined by the specified order, but Rigid children are laid out
|
||||
// before Flexed children.
|
||||
func (f Flex) Layout(gtx *Context, children ...FlexChild) {
|
||||
func (f Flex) Layout(gtx Context, children ...FlexChild) Dimensions {
|
||||
size := 0
|
||||
// Lay out Rigid children.
|
||||
for i, child := range children {
|
||||
@@ -91,7 +91,9 @@ func (f Flex) Layout(gtx *Context, children ...FlexChild) {
|
||||
cs = axisConstraints(f.Axis, 0, mainMax, crossMin, crossMax)
|
||||
var m op.MacroOp
|
||||
m.Record(gtx.Ops)
|
||||
dims := ctxLayout(gtx, cs, child.widget)
|
||||
gtx := gtx
|
||||
gtx.Constraints = cs
|
||||
dims := child.widget(gtx)
|
||||
m.Stop()
|
||||
sz := axisMain(f.Axis, dims.Size)
|
||||
size += sz
|
||||
@@ -124,7 +126,9 @@ func (f Flex) Layout(gtx *Context, children ...FlexChild) {
|
||||
cs = axisConstraints(f.Axis, flexSize, flexSize, crossMin, crossMax)
|
||||
var m op.MacroOp
|
||||
m.Record(gtx.Ops)
|
||||
dims := ctxLayout(gtx, cs, child.widget)
|
||||
gtx := gtx
|
||||
gtx.Constraints = cs
|
||||
dims := child.widget(gtx)
|
||||
m.Stop()
|
||||
sz := axisMain(f.Axis, dims.Size)
|
||||
size += sz
|
||||
@@ -200,7 +204,7 @@ func (f Flex) Layout(gtx *Context, children ...FlexChild) {
|
||||
mainSize += space / (len(children) * 2)
|
||||
}
|
||||
sz := axisPoint(f.Axis, mainSize, maxCross)
|
||||
gtx.Dimensions = Dimensions{Size: sz, Baseline: sz.Y - maxBaseline}
|
||||
return Dimensions{Size: sz, Baseline: sz.Y - maxBaseline}
|
||||
}
|
||||
|
||||
func axisPoint(a Axis, main, cross int) image.Point {
|
||||
|
||||
+9
-9
@@ -40,7 +40,7 @@ type Direction uint8
|
||||
|
||||
// Widget is a function scope for drawing, processing events and
|
||||
// computing dimensions for a user interface element.
|
||||
type Widget func()
|
||||
type Widget func(gtx Context) Dimensions
|
||||
|
||||
const (
|
||||
Start Alignment = iota
|
||||
@@ -111,7 +111,7 @@ type Inset struct {
|
||||
}
|
||||
|
||||
// Layout a widget.
|
||||
func (in Inset) Layout(gtx *Context, w Widget) {
|
||||
func (in Inset) Layout(gtx Context, w Widget) Dimensions {
|
||||
top := gtx.Px(in.Top)
|
||||
right := gtx.Px(in.Right)
|
||||
bottom := gtx.Px(in.Bottom)
|
||||
@@ -138,9 +138,10 @@ func (in Inset) Layout(gtx *Context, w Widget) {
|
||||
var stack op.StackOp
|
||||
stack.Push(gtx.Ops)
|
||||
op.TransformOp{}.Offset(FPt(image.Point{X: left, Y: top})).Add(gtx.Ops)
|
||||
dims := ctxLayout(gtx, mcs, w)
|
||||
gtx.Constraints = mcs
|
||||
dims := w(gtx)
|
||||
stack.Pop()
|
||||
gtx.Dimensions = Dimensions{
|
||||
return Dimensions{
|
||||
Size: dims.Size.Add(image.Point{X: right + left, Y: top + bottom}),
|
||||
Baseline: dims.Baseline + bottom,
|
||||
}
|
||||
@@ -153,13 +154,12 @@ func UniformInset(v unit.Value) Inset {
|
||||
}
|
||||
|
||||
// Layout a widget according to the direction.
|
||||
func (a Direction) Layout(gtx *Context, w Widget) {
|
||||
func (a Direction) Layout(gtx Context, w Widget) Dimensions {
|
||||
var macro op.MacroOp
|
||||
macro.Record(gtx.Ops)
|
||||
cs := gtx.Constraints
|
||||
mcs := cs
|
||||
mcs.Min = image.Point{}
|
||||
dims := ctxLayout(gtx, mcs, w)
|
||||
gtx.Constraints.Min = image.Point{}
|
||||
dims := w(gtx)
|
||||
macro.Stop()
|
||||
sz := dims.Size
|
||||
if sz.X < cs.Min.X {
|
||||
@@ -186,7 +186,7 @@ func (a Direction) Layout(gtx *Context, w Widget) {
|
||||
op.TransformOp{}.Offset(FPt(p)).Add(gtx.Ops)
|
||||
macro.Add()
|
||||
stack.Pop()
|
||||
gtx.Dimensions = Dimensions{
|
||||
return Dimensions{
|
||||
Size: sz,
|
||||
Baseline: dims.Baseline + sz.Y - dims.Size.Y - p.Y,
|
||||
}
|
||||
|
||||
+7
-8
@@ -29,7 +29,7 @@ type List struct {
|
||||
// Alignment is the cross axis alignment of list elements.
|
||||
Alignment Alignment
|
||||
|
||||
ctx *Context
|
||||
ctx Context
|
||||
macro op.MacroOp
|
||||
child op.MacroOp
|
||||
scroll gesture.Scroll
|
||||
@@ -51,7 +51,7 @@ type List struct {
|
||||
|
||||
// ListElement is a function that computes the dimensions of
|
||||
// a list element.
|
||||
type ListElement func(index int)
|
||||
type ListElement func(gtx Context, index int) Dimensions
|
||||
|
||||
type iterationDir uint8
|
||||
|
||||
@@ -82,7 +82,7 @@ const (
|
||||
const inf = 1e6
|
||||
|
||||
// init prepares the list for iterating through its children with next.
|
||||
func (l *List) init(gtx *Context, len int) {
|
||||
func (l *List) init(gtx Context, len int) {
|
||||
if l.more() {
|
||||
panic("unfinished child")
|
||||
}
|
||||
@@ -100,16 +100,15 @@ func (l *List) init(gtx *Context, len int) {
|
||||
}
|
||||
|
||||
// Layout the List.
|
||||
func (l *List) Layout(gtx *Context, len int, w ListElement) {
|
||||
func (l *List) Layout(gtx Context, len int, w ListElement) Dimensions {
|
||||
for l.init(gtx, len); l.more(); l.next() {
|
||||
crossMin, crossMax := axisCrossConstraint(l.Axis, l.ctx.Constraints)
|
||||
cs := axisConstraints(l.Axis, 0, inf, crossMin, crossMax)
|
||||
i := l.index()
|
||||
l.end(ctxLayout(gtx, cs, func() {
|
||||
w(i)
|
||||
}))
|
||||
gtx.Constraints = cs
|
||||
l.end(w(gtx, i))
|
||||
}
|
||||
gtx.Dimensions = l.layout()
|
||||
return l.layout()
|
||||
}
|
||||
|
||||
func (l *List) scrollToEnd() bool {
|
||||
|
||||
+8
-7
@@ -47,18 +47,18 @@ func Expanded(w Widget) StackChild {
|
||||
// Layout a stack of children. The position of the children are
|
||||
// determined by the specified order, but Stacked children are laid out
|
||||
// before Expanded children.
|
||||
func (s Stack) Layout(gtx *Context, children ...StackChild) {
|
||||
func (s Stack) Layout(gtx Context, children ...StackChild) Dimensions {
|
||||
var maxSZ image.Point
|
||||
// First lay out Stacked children.
|
||||
for i, w := range children {
|
||||
if w.expanded {
|
||||
continue
|
||||
}
|
||||
cs := gtx.Constraints
|
||||
cs.Min = image.Pt(0, 0)
|
||||
var m op.MacroOp
|
||||
m.Record(gtx.Ops)
|
||||
dims := ctxLayout(gtx, cs, w.widget)
|
||||
gtx := gtx
|
||||
gtx.Constraints.Min = image.Pt(0, 0)
|
||||
dims := w.widget(gtx)
|
||||
m.Stop()
|
||||
if w := dims.Size.X; w > maxSZ.X {
|
||||
maxSZ.X = w
|
||||
@@ -76,10 +76,11 @@ func (s Stack) Layout(gtx *Context, children ...StackChild) {
|
||||
}
|
||||
var m op.MacroOp
|
||||
m.Record(gtx.Ops)
|
||||
cs := Constraints{
|
||||
gtx := gtx
|
||||
gtx.Constraints = Constraints{
|
||||
Min: maxSZ, Max: gtx.Constraints.Max,
|
||||
}
|
||||
dims := ctxLayout(gtx, cs, w.widget)
|
||||
dims := w.widget(gtx)
|
||||
m.Stop()
|
||||
if w := dims.Size.X; w > maxSZ.X {
|
||||
maxSZ.X = w
|
||||
@@ -119,7 +120,7 @@ func (s Stack) Layout(gtx *Context, children ...StackChild) {
|
||||
}
|
||||
}
|
||||
}
|
||||
gtx.Dimensions = Dimensions{
|
||||
return Dimensions{
|
||||
Size: maxSZ,
|
||||
Baseline: baseline,
|
||||
}
|
||||
|
||||
+14
-9
@@ -5,22 +5,27 @@ package layout
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
|
||||
"gioui.org/op"
|
||||
)
|
||||
|
||||
func TestStack(t *testing.T) {
|
||||
var gtx Context
|
||||
gtx.Reset(nil, nil, image.Point{X: 100, Y: 100})
|
||||
gtx.Constraints.Min = image.Point{}
|
||||
gtx := Context{
|
||||
Ops: new(op.Ops),
|
||||
Constraints: Constraints{
|
||||
Max: image.Pt(100, 100),
|
||||
},
|
||||
}
|
||||
exp := image.Point{X: 60, Y: 70}
|
||||
Stack{Alignment: Center}.Layout(>x,
|
||||
Expanded(func() {
|
||||
gtx.Dimensions.Size = exp
|
||||
dims := Stack{Alignment: Center}.Layout(gtx,
|
||||
Expanded(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: exp}
|
||||
}),
|
||||
Stacked(func() {
|
||||
gtx.Dimensions.Size = image.Point{X: 50, Y: 50}
|
||||
Stacked(func(gtx Context) Dimensions {
|
||||
return Dimensions{Size: image.Point{X: 50, Y: 50}}
|
||||
}),
|
||||
)
|
||||
if got := gtx.Dimensions.Size; got != exp {
|
||||
if got := dims.Size; got != exp {
|
||||
t.Errorf("Stack ignored Expanded size, got %v expected %v", got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ type Bool struct {
|
||||
|
||||
// Update the checked state according to incoming events,
|
||||
// and reports whether Value changed.
|
||||
func (b *Bool) Update(gtx *layout.Context) bool {
|
||||
func (b *Bool) Update(gtx layout.Context) bool {
|
||||
was := b.Value
|
||||
for _, e := range b.gesture.Events(gtx) {
|
||||
switch e.Type {
|
||||
@@ -31,6 +31,6 @@ func (b *Bool) Update(gtx *layout.Context) bool {
|
||||
return b.Value != was
|
||||
}
|
||||
|
||||
func (b *Bool) Layout(gtx *layout.Context) {
|
||||
func (b *Bool) Layout(gtx layout.Context) {
|
||||
b.gesture.Add(gtx.Ops)
|
||||
}
|
||||
|
||||
+4
-3
@@ -30,7 +30,7 @@ type Click struct {
|
||||
// Clicked calls Update and reports whether the button was
|
||||
// clicked since the last call. Multiple clicks result in Clicked
|
||||
// returning true once per click.
|
||||
func (b *Clickable) Clicked(gtx *layout.Context) bool {
|
||||
func (b *Clickable) Clicked(gtx layout.Context) bool {
|
||||
b.Update(gtx)
|
||||
if b.clicks > 0 {
|
||||
b.clicks--
|
||||
@@ -49,7 +49,7 @@ func (b *Clickable) History() []Click {
|
||||
return b.history
|
||||
}
|
||||
|
||||
func (b *Clickable) Layout(gtx *layout.Context) {
|
||||
func (b *Clickable) Layout(gtx layout.Context) layout.Dimensions {
|
||||
// Flush clicks from before the previous frame.
|
||||
b.Update(gtx)
|
||||
var st op.StackOp
|
||||
@@ -65,11 +65,12 @@ func (b *Clickable) Layout(gtx *layout.Context) {
|
||||
n := copy(b.history, b.history[1:])
|
||||
b.history = b.history[:n]
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}
|
||||
|
||||
// Update the button state by processing events. The underlying
|
||||
// gesture events are returned for use beyond what Clicked offers.
|
||||
func (b *Clickable) Update(gtx *layout.Context) []gesture.ClickEvent {
|
||||
func (b *Clickable) Update(gtx layout.Context) []gesture.ClickEvent {
|
||||
evts := b.click.Events(gtx)
|
||||
for _, e := range evts {
|
||||
switch e.Type {
|
||||
|
||||
+10
-10
@@ -89,7 +89,7 @@ const (
|
||||
)
|
||||
|
||||
// Events returns available editor events.
|
||||
func (e *Editor) Events(gtx *layout.Context) []EditorEvent {
|
||||
func (e *Editor) Events(gtx layout.Context) []EditorEvent {
|
||||
e.processEvents(gtx)
|
||||
events := e.events
|
||||
e.events = nil
|
||||
@@ -97,7 +97,7 @@ func (e *Editor) Events(gtx *layout.Context) []EditorEvent {
|
||||
return events
|
||||
}
|
||||
|
||||
func (e *Editor) processEvents(gtx *layout.Context) {
|
||||
func (e *Editor) processEvents(gtx layout.Context) {
|
||||
if e.shaper == nil {
|
||||
// Can't process events without a shaper.
|
||||
return
|
||||
@@ -114,7 +114,7 @@ func (e *Editor) makeValid() {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Editor) processPointer(gtx *layout.Context) {
|
||||
func (e *Editor) processPointer(gtx layout.Context) {
|
||||
sbounds := e.scrollBounds()
|
||||
var smin, smax int
|
||||
var axis gesture.Axis
|
||||
@@ -154,7 +154,7 @@ func (e *Editor) processPointer(gtx *layout.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Editor) processKey(gtx *layout.Context) {
|
||||
func (e *Editor) processKey(gtx layout.Context) {
|
||||
if e.rr.Changed() {
|
||||
e.events = append(e.events, ChangeEvent{})
|
||||
}
|
||||
@@ -233,7 +233,7 @@ func (e *Editor) Focused() bool {
|
||||
}
|
||||
|
||||
// Layout lays out the editor.
|
||||
func (e *Editor) Layout(gtx *layout.Context, sh text.Shaper, font text.Font, size unit.Value) {
|
||||
func (e *Editor) Layout(gtx layout.Context, sh text.Shaper, font text.Font, size unit.Value) layout.Dimensions {
|
||||
// Flush events from before the previous frame.
|
||||
copy(e.events, e.events[e.prevEvents:])
|
||||
e.events = e.events[:len(e.events)-e.prevEvents]
|
||||
@@ -258,10 +258,10 @@ func (e *Editor) Layout(gtx *layout.Context, sh text.Shaper, font text.Font, siz
|
||||
}
|
||||
|
||||
e.processEvents(gtx)
|
||||
e.layout(gtx)
|
||||
return e.layout(gtx)
|
||||
}
|
||||
|
||||
func (e *Editor) layout(gtx *layout.Context) {
|
||||
func (e *Editor) layout(gtx layout.Context) layout.Dimensions {
|
||||
e.makeValid()
|
||||
|
||||
e.viewSize = gtx.Constraints.Constrain(e.dims.Size)
|
||||
@@ -321,10 +321,10 @@ func (e *Editor) layout(gtx *layout.Context) {
|
||||
e.caretOn = e.focused && (!blinking || dt%timePerBlink < timePerBlink/2)
|
||||
}
|
||||
|
||||
gtx.Dimensions = layout.Dimensions{Size: e.viewSize, Baseline: e.dims.Baseline}
|
||||
return layout.Dimensions{Size: e.viewSize, Baseline: e.dims.Baseline}
|
||||
}
|
||||
|
||||
func (e *Editor) PaintText(gtx *layout.Context) {
|
||||
func (e *Editor) PaintText(gtx layout.Context) {
|
||||
clip := textPadding(e.lines)
|
||||
clip.Max = clip.Max.Add(e.viewSize)
|
||||
for _, shape := range e.shapes {
|
||||
@@ -337,7 +337,7 @@ func (e *Editor) PaintText(gtx *layout.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Editor) PaintCaret(gtx *layout.Context) {
|
||||
func (e *Editor) PaintCaret(gtx layout.Context) {
|
||||
if !e.caretOn {
|
||||
return
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ func index(vs []string, t string) int {
|
||||
|
||||
// Update the Value according to incoming events, and
|
||||
// reports whether Value changed.
|
||||
func (e *Enum) Update(gtx *layout.Context) bool {
|
||||
func (e *Enum) Update(gtx layout.Context) bool {
|
||||
was := e.Value
|
||||
for i := range e.clicks {
|
||||
for _, ev := range e.clicks[i].Events(gtx) {
|
||||
@@ -37,7 +37,7 @@ func (e *Enum) Update(gtx *layout.Context) bool {
|
||||
}
|
||||
|
||||
// Layout adds the event handler for key.
|
||||
func (e *Enum) Layout(gtx *layout.Context, key string) {
|
||||
func (e *Enum) Layout(gtx layout.Context, key string) {
|
||||
if index(e.values, key) == -1 {
|
||||
e.values = append(e.values, key)
|
||||
e.clicks = append(e.clicks, gesture.Click{})
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ func NewIcon(data []byte) (*Icon, error) {
|
||||
return &Icon{src: data, Color: color.RGBA{A: 0xff}}, nil
|
||||
}
|
||||
|
||||
func (ic *Icon) Layout(gtx *layout.Context, sz unit.Value) {
|
||||
func (ic *Icon) Layout(gtx layout.Context, sz unit.Value) layout.Dimensions {
|
||||
ico := ic.image(gtx.Px(sz))
|
||||
ico.Add(gtx.Ops)
|
||||
paint.PaintOp{
|
||||
@@ -40,7 +40,7 @@ func (ic *Icon) Layout(gtx *layout.Context, sz unit.Value) {
|
||||
Max: layout.FPt(ico.Size()),
|
||||
},
|
||||
}.Add(gtx.Ops)
|
||||
gtx.Dimensions = layout.Dimensions{
|
||||
return layout.Dimensions{
|
||||
Size: ico.Size(),
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ type Image struct {
|
||||
Scale float32
|
||||
}
|
||||
|
||||
func (im Image) Layout(gtx *layout.Context) {
|
||||
func (im Image) Layout(gtx layout.Context) layout.Dimensions {
|
||||
scale := im.Scale
|
||||
if scale == 0 {
|
||||
scale = 160.0 / 72.0
|
||||
@@ -39,5 +39,5 @@ func (im Image) Layout(gtx *layout.Context) {
|
||||
im.Src.Add(gtx.Ops)
|
||||
paint.PaintOp{Rect: f32.Rectangle{Max: f32.Point{X: float32(w), Y: float32(h)}}}.Add(gtx.Ops)
|
||||
s.Pop()
|
||||
gtx.Dimensions = layout.Dimensions{Size: d}
|
||||
return layout.Dimensions{Size: d}
|
||||
}
|
||||
|
||||
+2
-2
@@ -84,7 +84,7 @@ func (l *lineIterator) Next() (int, int, []text.Glyph, f32.Point, bool) {
|
||||
return 0, 0, nil, f32.Point{}, false
|
||||
}
|
||||
|
||||
func (l Label) Layout(gtx *layout.Context, s text.Shaper, font text.Font, size unit.Value, txt string) {
|
||||
func (l Label) Layout(gtx layout.Context, s text.Shaper, font text.Font, size unit.Value, txt string) layout.Dimensions {
|
||||
cs := gtx.Constraints
|
||||
textSize := fixed.I(gtx.Px(size))
|
||||
lines := s.LayoutString(font, textSize, cs.Max.X, txt)
|
||||
@@ -115,7 +115,7 @@ func (l Label) Layout(gtx *layout.Context, s text.Shaper, font text.Font, size u
|
||||
paint.PaintOp{Rect: lclip}.Add(gtx.Ops)
|
||||
stack.Pop()
|
||||
}
|
||||
gtx.Dimensions = dims
|
||||
return dims
|
||||
}
|
||||
|
||||
func textPadding(lines []text.Line) (padding image.Rectangle) {
|
||||
|
||||
+29
-32
@@ -80,12 +80,10 @@ func IconButton(th *Theme, icon *widget.Icon) IconButtonStyle {
|
||||
|
||||
// Clickable lays out a rectangular clickable widget without further
|
||||
// decoration.
|
||||
func Clickable(gtx *layout.Context, button *widget.Clickable, w layout.Widget) {
|
||||
layout.Stack{}.Layout(gtx,
|
||||
layout.Expanded(func() {
|
||||
button.Layout(gtx)
|
||||
}),
|
||||
layout.Expanded(func() {
|
||||
func Clickable(gtx layout.Context, button *widget.Clickable, w layout.Widget) layout.Dimensions {
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Expanded(button.Layout),
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
clip.Rect{
|
||||
Rect: f32.Rectangle{Max: f32.Point{
|
||||
X: float32(gtx.Constraints.Min.X),
|
||||
@@ -95,26 +93,27 @@ func Clickable(gtx *layout.Context, button *widget.Clickable, w layout.Widget) {
|
||||
for _, c := range button.History() {
|
||||
drawInk(gtx, c)
|
||||
}
|
||||
return layout.Dimensions{Size: gtx.Constraints.Min}
|
||||
}),
|
||||
layout.Stacked(w),
|
||||
)
|
||||
}
|
||||
|
||||
func (b ButtonStyle) Layout(gtx *layout.Context, button *widget.Clickable) {
|
||||
ButtonLayoutStyle{
|
||||
func (b ButtonStyle) Layout(gtx layout.Context, button *widget.Clickable) layout.Dimensions {
|
||||
return ButtonLayoutStyle{
|
||||
Background: b.Background,
|
||||
CornerRadius: b.CornerRadius,
|
||||
Inset: b.Inset,
|
||||
}.Layout(gtx, button, func() {
|
||||
}.Layout(gtx, button, func(gtx layout.Context) layout.Dimensions {
|
||||
paint.ColorOp{Color: b.Color}.Add(gtx.Ops)
|
||||
widget.Label{Alignment: text.Middle}.Layout(gtx, b.shaper, b.Font, b.TextSize, b.Text)
|
||||
return widget.Label{Alignment: text.Middle}.Layout(gtx, b.shaper, b.Font, b.TextSize, b.Text)
|
||||
})
|
||||
}
|
||||
|
||||
func (b ButtonLayoutStyle) Layout(gtx *layout.Context, button *widget.Clickable, w layout.Widget) {
|
||||
func (b ButtonLayoutStyle) Layout(gtx layout.Context, button *widget.Clickable, w layout.Widget) layout.Dimensions {
|
||||
min := gtx.Constraints.Min
|
||||
layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
layout.Expanded(func() {
|
||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
rr := float32(gtx.Px(b.CornerRadius))
|
||||
clip.Rect{
|
||||
Rect: f32.Rectangle{Max: f32.Point{
|
||||
@@ -123,28 +122,25 @@ func (b ButtonLayoutStyle) Layout(gtx *layout.Context, button *widget.Clickable,
|
||||
}},
|
||||
NE: rr, NW: rr, SE: rr, SW: rr,
|
||||
}.Op(gtx.Ops).Add(gtx.Ops)
|
||||
fill(gtx, b.Background)
|
||||
dims := fill(gtx, b.Background)
|
||||
for _, c := range button.History() {
|
||||
drawInk(gtx, c)
|
||||
}
|
||||
return dims
|
||||
}),
|
||||
layout.Stacked(func() {
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
gtx.Constraints.Min = min
|
||||
layout.Center.Layout(gtx, func() {
|
||||
b.Inset.Layout(gtx, func() {
|
||||
w()
|
||||
})
|
||||
return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
return b.Inset.Layout(gtx, w)
|
||||
})
|
||||
}),
|
||||
layout.Expanded(func() {
|
||||
button.Layout(gtx)
|
||||
}),
|
||||
layout.Expanded(button.Layout),
|
||||
)
|
||||
}
|
||||
|
||||
func (b IconButtonStyle) Layout(gtx *layout.Context, button *widget.Clickable) {
|
||||
layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
layout.Expanded(func() {
|
||||
func (b IconButtonStyle) Layout(gtx layout.Context, button *widget.Clickable) layout.Dimensions {
|
||||
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
size := gtx.Constraints.Min.X
|
||||
sizef := float32(size)
|
||||
rr := sizef * .5
|
||||
@@ -152,31 +148,32 @@ func (b IconButtonStyle) Layout(gtx *layout.Context, button *widget.Clickable) {
|
||||
Rect: f32.Rectangle{Max: f32.Point{X: sizef, Y: sizef}},
|
||||
NE: rr, NW: rr, SE: rr, SW: rr,
|
||||
}.Op(gtx.Ops).Add(gtx.Ops)
|
||||
fill(gtx, b.Background)
|
||||
dims := fill(gtx, b.Background)
|
||||
for _, c := range button.History() {
|
||||
drawInk(gtx, c)
|
||||
}
|
||||
return dims
|
||||
}),
|
||||
layout.Stacked(func() {
|
||||
b.Inset.Layout(gtx, func() {
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
return b.Inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
size := gtx.Px(b.Size)
|
||||
if b.Icon != nil {
|
||||
b.Icon.Color = b.Color
|
||||
b.Icon.Layout(gtx, unit.Px(float32(size)))
|
||||
}
|
||||
gtx.Dimensions = layout.Dimensions{
|
||||
return layout.Dimensions{
|
||||
Size: image.Point{X: size, Y: size},
|
||||
}
|
||||
})
|
||||
}),
|
||||
layout.Expanded(func() {
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
pointer.Ellipse(image.Rectangle{Max: gtx.Constraints.Min}).Add(gtx.Ops)
|
||||
button.Layout(gtx)
|
||||
return button.Layout(gtx)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func drawInk(gtx *layout.Context, c widget.Click) {
|
||||
func drawInk(gtx layout.Context, c widget.Click) {
|
||||
d := gtx.Now().Sub(c.Time)
|
||||
t := float32(d.Seconds())
|
||||
const duration = 0.5
|
||||
|
||||
@@ -26,7 +26,7 @@ type checkable struct {
|
||||
uncheckedStateIcon *widget.Icon
|
||||
}
|
||||
|
||||
func (c *checkable) layout(gtx *layout.Context, checked bool) {
|
||||
func (c *checkable) layout(gtx layout.Context, checked bool) layout.Dimensions {
|
||||
var icon *widget.Icon
|
||||
if checked {
|
||||
icon = c.checkedStateIcon
|
||||
@@ -35,29 +35,30 @@ func (c *checkable) layout(gtx *layout.Context, checked bool) {
|
||||
}
|
||||
|
||||
min := gtx.Constraints.Min
|
||||
layout.Flex{Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func() {
|
||||
layout.Center.Layout(gtx, func() {
|
||||
layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
|
||||
dims := layout.Flex{Alignment: layout.Middle}.Layout(gtx,
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
size := gtx.Px(c.Size)
|
||||
icon.Color = c.IconColor
|
||||
icon.Layout(gtx, unit.Px(float32(size)))
|
||||
gtx.Dimensions = layout.Dimensions{
|
||||
return layout.Dimensions{
|
||||
Size: image.Point{X: size, Y: size},
|
||||
}
|
||||
})
|
||||
})
|
||||
}),
|
||||
|
||||
layout.Rigid(func() {
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
gtx.Constraints.Min = min
|
||||
layout.W.Layout(gtx, func() {
|
||||
layout.UniformInset(unit.Dp(2)).Layout(gtx, func() {
|
||||
return layout.W.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.UniformInset(unit.Dp(2)).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
paint.ColorOp{Color: c.Color}.Add(gtx.Ops)
|
||||
widget.Label{}.Layout(gtx, c.shaper, c.Font, c.TextSize, c.Label)
|
||||
return widget.Label{}.Layout(gtx, c.shaper, c.Font, c.TextSize, c.Label)
|
||||
})
|
||||
})
|
||||
}),
|
||||
)
|
||||
pointer.Rect(image.Rectangle{Max: gtx.Dimensions.Size}).Add(gtx.Ops)
|
||||
pointer.Rect(image.Rectangle{Max: dims.Size}).Add(gtx.Ops)
|
||||
return dims
|
||||
}
|
||||
|
||||
@@ -28,8 +28,9 @@ func CheckBox(th *Theme, label string) CheckBoxStyle {
|
||||
}
|
||||
|
||||
// Layout updates the checkBox and displays it.
|
||||
func (c CheckBoxStyle) Layout(gtx *layout.Context, checkBox *widget.Bool) {
|
||||
func (c CheckBoxStyle) Layout(gtx layout.Context, checkBox *widget.Bool) layout.Dimensions {
|
||||
checkBox.Update(gtx)
|
||||
c.layout(gtx, checkBox.Value)
|
||||
dims := c.layout(gtx, checkBox.Value)
|
||||
checkBox.Layout(gtx)
|
||||
return dims
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//
|
||||
// This snippet defines a button that prints a message when clicked:
|
||||
//
|
||||
// var gtx *layout.Context
|
||||
// var gtx layout.Context
|
||||
// button := new(widget.Clickable)
|
||||
//
|
||||
// for button.Clicked(gtx) {
|
||||
@@ -43,7 +43,7 @@
|
||||
//
|
||||
// btn := material.Button(theme, "Click me!")
|
||||
// btn.Font.Style = text.Italic
|
||||
// btn.Layout(gtx)
|
||||
// btn.Layout(gtx, button)
|
||||
//
|
||||
// Widget variants: A widget can have several distinct representations even
|
||||
// though the underlying state is the same. A widget.Clickable can be drawn as a
|
||||
|
||||
@@ -36,22 +36,22 @@ func Editor(th *Theme, hint string) EditorStyle {
|
||||
}
|
||||
}
|
||||
|
||||
func (e EditorStyle) Layout(gtx *layout.Context, editor *widget.Editor) {
|
||||
func (e EditorStyle) Layout(gtx layout.Context, editor *widget.Editor) layout.Dimensions {
|
||||
var stack op.StackOp
|
||||
stack.Push(gtx.Ops)
|
||||
var macro op.MacroOp
|
||||
macro.Record(gtx.Ops)
|
||||
paint.ColorOp{Color: e.HintColor}.Add(gtx.Ops)
|
||||
tl := widget.Label{Alignment: editor.Alignment}
|
||||
tl.Layout(gtx, e.shaper, e.Font, e.TextSize, e.Hint)
|
||||
dims := tl.Layout(gtx, e.shaper, e.Font, e.TextSize, e.Hint)
|
||||
macro.Stop()
|
||||
if w := gtx.Dimensions.Size.X; gtx.Constraints.Min.X < w {
|
||||
if w := dims.Size.X; gtx.Constraints.Min.X < w {
|
||||
gtx.Constraints.Min.X = w
|
||||
}
|
||||
if h := gtx.Dimensions.Size.Y; gtx.Constraints.Min.Y < h {
|
||||
if h := dims.Size.Y; gtx.Constraints.Min.Y < h {
|
||||
gtx.Constraints.Min.Y = h
|
||||
}
|
||||
editor.Layout(gtx, e.shaper, e.Font, e.TextSize)
|
||||
dims = editor.Layout(gtx, e.shaper, e.Font, e.TextSize)
|
||||
if editor.Len() > 0 {
|
||||
paint.ColorOp{Color: e.Color}.Add(gtx.Ops)
|
||||
editor.PaintText(gtx)
|
||||
@@ -61,4 +61,5 @@ func (e EditorStyle) Layout(gtx *layout.Context, editor *widget.Editor) {
|
||||
paint.ColorOp{Color: e.Color}.Add(gtx.Ops)
|
||||
editor.PaintCaret(gtx)
|
||||
stack.Pop()
|
||||
return dims
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ func Label(th *Theme, size unit.Value, txt string) LabelStyle {
|
||||
}
|
||||
}
|
||||
|
||||
func (l LabelStyle) Layout(gtx *layout.Context) {
|
||||
func (l LabelStyle) Layout(gtx layout.Context) layout.Dimensions {
|
||||
paint.ColorOp{Color: l.Color}.Add(gtx.Ops)
|
||||
tl := widget.Label{Alignment: l.Alignment, MaxLines: l.MaxLines}
|
||||
tl.Layout(gtx, l.shaper, l.Font, l.TextSize, l.Text)
|
||||
return tl.Layout(gtx, l.shaper, l.Font, l.TextSize, l.Text)
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ func ProgressBar(th *Theme) ProgressBarStyle {
|
||||
}
|
||||
}
|
||||
|
||||
func (b ProgressBarStyle) Layout(gtx *layout.Context, progress int) {
|
||||
shader := func(width float32, color color.RGBA) {
|
||||
func (p ProgressBarStyle) Layout(gtx layout.Context, progress int) layout.Dimensions {
|
||||
shader := func(width float32, color color.RGBA) layout.Dimensions {
|
||||
maxHeight := unit.Dp(4)
|
||||
rr := float32(gtx.Px(unit.Dp(2)))
|
||||
|
||||
@@ -41,7 +41,7 @@ func (b ProgressBarStyle) Layout(gtx *layout.Context, progress int) {
|
||||
paint.ColorOp{Color: color}.Add(gtx.Ops)
|
||||
paint.PaintOp{Rect: dr}.Add(gtx.Ops)
|
||||
|
||||
gtx.Dimensions = layout.Dimensions{Size: d}
|
||||
return layout.Dimensions{Size: d}
|
||||
}
|
||||
|
||||
if progress > 100 {
|
||||
@@ -52,16 +52,16 @@ func (b ProgressBarStyle) Layout(gtx *layout.Context, progress int) {
|
||||
|
||||
progressBarWidth := float32(gtx.Constraints.Max.X)
|
||||
|
||||
layout.Stack{Alignment: layout.W}.Layout(gtx,
|
||||
layout.Stacked(func() {
|
||||
return layout.Stack{Alignment: layout.W}.Layout(gtx,
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
// Use a transparent equivalent of progress color.
|
||||
bgCol := mulAlpha(b.Color, 150)
|
||||
bgCol := mulAlpha(p.Color, 150)
|
||||
|
||||
shader(progressBarWidth, bgCol)
|
||||
return shader(progressBarWidth, bgCol)
|
||||
}),
|
||||
layout.Stacked(func() {
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
fillWidth := (progressBarWidth / 100) * float32(progress)
|
||||
shader(fillWidth, b.Color)
|
||||
return shader(fillWidth, p.Color)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -33,8 +33,9 @@ func RadioButton(th *Theme, key, label string) RadioButtonStyle {
|
||||
}
|
||||
|
||||
// Layout updates enum and displays the radio button.
|
||||
func (r RadioButtonStyle) Layout(gtx *layout.Context, enum *widget.Enum) {
|
||||
func (r RadioButtonStyle) Layout(gtx layout.Context, enum *widget.Enum) layout.Dimensions {
|
||||
enum.Update(gtx)
|
||||
r.layout(gtx, enum.Value == r.Key)
|
||||
dims := r.layout(gtx, enum.Value == r.Key)
|
||||
enum.Layout(gtx, r.Key)
|
||||
return dims
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func Switch(th *Theme) SwitchStyle {
|
||||
}
|
||||
|
||||
// Layout updates the checkBox and displays it.
|
||||
func (s SwitchStyle) Layout(gtx *layout.Context, swtch *widget.Bool) {
|
||||
func (s SwitchStyle) Layout(gtx layout.Context, swtch *widget.Bool) layout.Dimensions {
|
||||
swtch.Update(gtx)
|
||||
|
||||
trackWidth := gtx.Px(unit.Dp(36))
|
||||
@@ -112,7 +112,7 @@ func (s SwitchStyle) Layout(gtx *layout.Context, swtch *widget.Bool) {
|
||||
swtch.Layout(gtx)
|
||||
stack.Pop()
|
||||
|
||||
gtx.Dimensions = layout.Dimensions{
|
||||
return layout.Dimensions{
|
||||
Size: image.Point{X: trackWidth, Y: trackHeight},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func argb(c uint32) color.RGBA {
|
||||
return color.RGBA{A: uint8(c >> 24), R: uint8(c >> 16), G: uint8(c >> 8), B: uint8(c)}
|
||||
}
|
||||
|
||||
func fill(gtx *layout.Context, col color.RGBA) {
|
||||
func fill(gtx layout.Context, col color.RGBA) layout.Dimensions {
|
||||
cs := gtx.Constraints
|
||||
d := cs.Min
|
||||
dr := f32.Rectangle{
|
||||
@@ -71,5 +71,5 @@ func fill(gtx *layout.Context, col color.RGBA) {
|
||||
}
|
||||
paint.ColorOp{Color: col}.Add(gtx.Ops)
|
||||
paint.PaintOp{Rect: dr}.Add(gtx.Ops)
|
||||
gtx.Dimensions = layout.Dimensions{Size: d}
|
||||
return layout.Dimensions{Size: d}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user