Almost every layout and widget need the ui.Config for its environment,
an ui.Ops to store operations. Stateful widgets need an input.Queue
for events.
Add all these common objects to Context, greatly simplifying the
function signatures for Gio programs.
Fixes gio#33
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Context keeps the current Constraints and Dimensions so the layout
function scopes don't have to.
With
ctx := new(layout.Context)
a label with margins and alignment goes from
return al.Layout(ops, cs, func(cs layout.Constraints) layout.Dimensions {
in := layout.Inset{...}
return in.Layout(c, ops, cs, func(cs layout.Constraints) layout.Dimensions {
return text.Label{...}.Layout(ops, cs)
})
})
to
al.Layout(ops, ctx, func() {
in := layout.Inset{...}
in.Layout(c, ops, ctx, func() {
text.Label{...}.Layout(ops, ctx)
})
})
It was a difficult trade-off between the verbose functional approach
and the shorter but more complex Context.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before this change, layout objects followed a pattern where a
begin method would set up the layout and return a tweaked set
of constraints, and a end method would take the widget dimensions
and return the tweaked dimensions.
As has been pointed out, this process is error prone, because the
scope of the layout objects are not clear and because it is easy
to swap two begins or two ends.
It turns out that it is possible to implement layout with function
scopes in garbage free way. A typical layout changes from
al := layout.Align{Alignment: layout.NE}
cs = al.Begin(ops, cs)
in := layout.Inset{Top: ui.Dp(16)}
cs = in.Begin(c, ops, cs)
txt := fmt.Sprintf("m: %d %s", mallocs, u.profile.Timings)
dims := text.Label{Material: theme.text, Face: u.face(fonts.mono, 10), Text: txt}.Layout(ops, cs)
dims = in.End(dims)
return al.End(dims)
to
al := layout.Align{Alignment: layout.NE}
return al.Layout(ops, cs, func(cs layout.Constraints) layout.Dimensions {
in := layout.Inset{Top: ui.Dp(16)}
return in.Layout(c, ops, cs, func(cs layout.Constraints) layout.Dimensions {
txt := fmt.Sprintf("m: %d %s", mallocs, u.profile.Timings)
return text.Label{Material: theme.text, Face: u.face(fonts.mono, 10), Text: txt}.Layout(ops, cs)
})
})
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Distance was meant to be used for implementing nested scrollers, but
I don't think the API is right. For example, Distance doesn't report
residual fling scrolling.
Delete the field while we wait for a better approach.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Inverted lists used to behave as if its top and bottom edges were
flipped. That was easy but also wrong: when the underlying children
changed size, they would move relative to the top edge of the list.
As illustrated by issue gio#34, Invert should only do two things:
- End lign lists smaller than the containing area.
- Scroll to end, but only as long as the user hasn't scrolled away.
List also had a bug where it didn't handle shrinking lists, so
this change rewrites List to fix that bug, fix Invert behaviour and
hopefully be a little simpler.
Fixes gio#34
Rename MainAxisAlignment to Spacing and CrossAxisAlignment to just
Alignment.
Drop the untyped Start, End, Center values and add them as Spacing
and Direction values. Center is both a Direction and Alignment, so
use the synonym "Middle" for the alignment.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
I too often forget to initialize widgets' config and queue. Moving
them from fields to parameters fix that. The change results in a
little more verbosity but cleaner code.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before this change, there was no guarantee that a PopOp matched
the intended PushOp. With a single stack operation, the client is
forced to match pop with the right push.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Move the Record and Stop methods from Ops to MacroOp itself.
Before this change, Ops.Stop stopped the recording of the most
recent macro, which could be a different macro than intended.
After this change, there is no such confusion.
As a bonus, the Ops API becomes less cluttered.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Rename Insets to the verb Inset for consistency with Align.
Uniform is a better description than Equal for the result of
UniformInset.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Exact was too special and can be expressed with RigidConstraints.
RigidConstraints is a better name ("rigid" was in the comment!)
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before this change, the weight applied to the space left, not the
total space available after rigid children.
While here, ensure that weight sums > 1 are capped to the available
space.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The type and argument to Flex.Flexible does not carry its weight;
It is just as easy to expand the constraint directly.
While we're here, rename the flex argument to weight which is clearer.
With this change, a List l can be iterated with
for l.Init(...); l.More(); l.Next() {
l.Elem(..., l.Constraints(), l.Index())
}
instead of
l.Init(...)
for {
i, cs, ok := l.Next()
if !ok {
break
}
l.End(..., cs, i))
}
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Let the caller decide whether the constraints should be stretched.
Also unexport Constraint (not Constraints) methods, they weren't
pulling their weight.
Finally, don't force cross axis constraint minimum to 0 in List.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Now that the pass through mode is moved into its own PassOp op,
it doesn't make sense to collect all area types into one exported
type.
Add RectAreaOp and EllipseAreaOp for clients; the internal
representation is still a single op. It can be changed later without
breaking clients.
Signed-off-by: Elias Naur <mail@eliasnaur.com>