Add most of the common cursors defined by different systems.
Normalize cursor names to match CSS.
This is API change: some cursor names have changed, and the
underlying type is no longer a string.
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
A recorded macro is prefixed with an internal macro op that stores
the end of the macro. The end is used to efficiently skip the macro
when not calling it. The call a macro, the CallOp stores the start
position of the macro.
To support seamless wrapping of Ops lists, this change removes the
dependency on the macro op prefix from CallOp. Internal code can
now call an Ops like this:
var ops op.Ops
var wrapper op.Ops
ops.AddCall(&wrapper.Internal, &ops.Internal, ops.PC{}, ops.PCFor(&ops.Internal))
References: https://todo.sr.ht/~eliasnaur/gio/318
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Remove unnecessary fill when starting a recording in op.Record.
Have the exact number of possible stack kinds in ops.Ops.
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
Multiple operations Op, such as clip.Path, cannot
be interleaved with other ops. This patch adds a
mechanism to ensure that is the case by starting
multi ops with ops.BeginMulti and ending them with
ops.EndMulti while operations are written to op.Ops
with ops.WriteMulti.
This mechanism is applied to clip.Path.
Fixes: https://todo.sr.ht/~eliasnaur/gio/336
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
A Path initialized with Begin should be ready to use with its pen at (0,
0). Make it so.
Updates gio#311
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
Useful when drawing ellipses with Stroke.
Also, this makes it consistent with the other clip operations.
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
When the rectangle used in an Ellipse has no width
or height, the path would panic with "path not closed".
Use an empty rectangle path in that case instead.
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
Useful when drawing non-rounded rectangles with Stroke.
Also, this makes it consistent with RRect and Circle which
also have a Path method.
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
Pointer hit areas and paint clip areas are separate concepts, but
similar enough to warrant merging. This change replaces pointer hit
areas with clip areas, so Gio is left with just one area concept (in
package op/clip).
The reason for separating the concepts in the original Gio release was
because of my being unsure general path/stroke hit areas would ever be
implemented, let alone efficient.
This change represents a change of mind, in the sense that it's better
to have an incomplete API than two separate area concepts.
Leave the deprecated pointer.Rect, pointer.Ellipse for temporary
backwards compatibility.
This is an API change. Most existing programs should continue to build
with this change, but may have to adjust to having all clip.Ops participate
in InputOp hit areas.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
op.Save, op.SaveStack were compatibility stop-gaps.
API change. Most op.Save/Loads can safely be removed altogether, or
replaced with
trans := op.Offset(f32.Pt(0, 0).Push(gtx.Ops)
...
trans.Pop()
cl := clip.Rect(image.Rect(-1e6, -1e6, 1e6, 1e6)).Push(gtx.Ops)
...
cl.Pop()
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The Add method was a compatibility stop-gap.
API change. Use clip.Op.Push and Pop the return value to explicitly mark
the region affected by the clip operation.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Ops is in the internal package ops, but external clients can reach its
method through op.Ops.Internal. Hide them by converting them to internal
package functions.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
In a discussion with Raph Levien, the author of our compute renderer
implementation, it became clear to me that it's not at all certain that
complex strokes will ever be efficiently supported by a GPU renderer.
At the same time, the machinery for converting a complex stroke to a
GPU-friendly outline has a significant maintenance cost. Further, it is
surprising to users that complex strokes are significantly slower and
allocate memory.
This change removes support for complex strokes, leaving only
round-capped, round-joined strokes supported by the compute renderer.
The default renderer still converts all strokes to outline, but it also
caches the result.
This is an API change. The complex stroke conversion code has been moved
to the external gioui.org/x/stroke package, with a similar API.
Updats gio#282 (Inkeliz brought up the allocation issue)
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The op.Save and Load methods exist to support the need for
transformation, clip, pointer area state to behave as stacks. For
example, layout needs to apply an offset to its children but not
subsequent operations.
Before this change, op.Save and Load were used to save and restore the
state:
ops := new(op.Ops)
// Save state.
state := op.Save(ops)
// Apply offset.
op.Offset(...).Add(ops)
// Draw with offset applied.
draw(ops)
// Restore state.
state.Load()
A drawback with the op.Save mechanism is that there is no direct
connection between the state change and the saving and loading of state.
This causes confusion as to when a Save/Load is needed and who is
responsible for performing them, which leads to subtle bugs and over-use
of Save/Loads.
This change gets rid of the general state stack and replaces it with
per-state stacks. There is now a stack for transformation, clip, pointer
areas, and they can only be restored by the code pushing state to them.
The example above now becomes:
ops := new(op.Ops)
// Push offset to the transformation stack.
stack := op.Offset(...).Push(ops)
// Draw with offset applied.
draw(ops)
// Restore state.
stack.Pop()
For convenience, transformation also be Add'ed if the stack operation is
not required.
Simple state such as the current material no longer has a way to be
restored; it is assumed the client of a PaintOp adds their desired
material operation before it.
API change: replace op.Save/Load with explicit Push/Pop scopes for
op.TransformOps, pointer.AreaOps, clip.Ops.
To ease porting, this change retains a version of op.Save/Load that
saves and restores the transformation and clip stacks. It also retains
an Add method for clip.Op.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
There's no meaningful reason to have them separate. The intention was to
enable rendering concurrent with other processing, but that's gaining
framerate at the expense of input latency and complicating ImageOp
semantics.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The hash of the clipping paths that affect drawing operations are computed
and used to quickly determine that two operations are not equal, the
most likely outcome of a comparison.
However, for paths that are constructed once and cached computing the
hash at every frame is wasteful. This is especially true for text, which
is both cached and also among the largest paths in a frame.
This change moves the hashing to op/clip.Path construction time, and
stores the hash in the ops list so it won't be re-computed at every use.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The current renderer transforms and processes paths before sending them
to the GPU. It can compute bounds during processing.
The new renderer passes paths verbatim to the GPU, but needs the bounds
for constructing clip bounds.
This change computes the bounds during construction, so it is available
at use. As a bonus for storing the bounds with the path, path caches
(such as for storing text fragments) automatically reuse the bounds
calculations as well.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Before this change, the two renderers both had special case code for
approximating strokes they don't support natively. This change moves
that conversion to clip.Op.Add, for several reasons:
- The compute renderer no longer need fallback logic and caches for
strokes it doesn't support.
- The approximation logic is slow. Moving it to clip.Op.Add will not
speed it up, but will make the cost easier to spot in profiles. Until all
strokes are supported natively, users can use macros to cache
expensive strokes.
- Reduced garbage: Op.Add takes an op.Ops anyway, and can use that for
storing the approximated stroke outline.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
To avoid an import cycle in a future change, internal/stroke can no
longer import op/clip. Move required op/clip functionality to
internal/stroke and duplicate the remaining types.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Both Path.Arc and the internal stroke package needs to support arcs;
this change isolates the approximation computation into a function we
can move to internal/stroke in a follow-up.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The fill mode is now controlled by a SetFillMode command, not by flags
on each path segment and fill command.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Border can be expressed in-terms of clip.Stroke:
clip.Stroke{
Path: clip.UniformRRect(r, rr).Ops(ops),
Style: clip.StrokeStyle{Width: width},
}.Add(ops)
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
Floating point error may accumulate and the round rect may not
necessarily close up entirely. Add an additional "Close" to ensure
it's properly closed.
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
There's an argument that rounded caps and joins are the simplest stroke,
in that it can be defined to cover all pixels within lineWidth distance
from the supporting path.
However, the more important reason is that the compute renderer natively
supports this stroke style (without dashes), and users that don't care
(much) about the particular stroke style should get the efficient
implementation. A good example is op/clip.Border that strokes a closed
path, where the StrokeCap is irrelevant.
This is a (subtle) API change. If you have code that relies on the
default values of clip.StrokeStyle you may want to set Cap and Join
explicitly. See the test changes for examples. On the other hand, you
will get much better performance from the default Cap and Join values
once the compute renderer becomes the default.
Disablethe TestPaintClippedBorder test; dashes round-capped,
round-joined strokes doesn't seem to work correctly.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Since clip.Path now encodes paths in the format expected by
elements.comp, use that data directly instead of a roundtrip through
drawOps.buildVerts.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We're about to let clip.Path use more of the compute renderer features
(lines, cubic béziers). This change prepares the gpu package for reading
one of several commands types, not just the quadratic béziers of before.
The old Quad type is still the basis for the stroking algorithms, but
this change moves it into package gpu which is the only user.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The check for path segments in gpu is redundant; clip.Op.Add doesn't add
the Path op if there were no segments.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Outline represents a clipping operations that clips all drawing outside
a closed path. Before this change, paths not closed we're patched up by
adding an implicit line from the endpoint to the beginning.
These fixups are inefficient for a rare case, but acceptable because the
old renderer post-processes all paths anyway. However, the new compute
renderer don't need post-processing in most cases, making fixups too
expensive.
Given that clipping to an open path is fundamentally undefined and that
implicit fixup with a closing line segment is merely a way to force the
clip to be well-defined, this change adds a panic to Outline for Paths
that are not closed.
Signed-off-by: Elias Naur <mail@eliasnaur.com>