Commit Graph

69 Commits

Author SHA1 Message Date
Elias Naur bd7f50438a io/router: account for parent clip areas when scrolling focus into view
Fixes: https://todo.sr.ht/~eliasnaur/gio/389
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-04-02 15:49:41 +02:00
Elias Naur cd0c9dab9f io/router: [API] don't emit Enter and Leave events for touch input
Enter/Leave events make sense for mouse pointers, to track hover
status. It doesn't make sense to track hover for touch input, so
this change stops pointer.Enter and pointer.Leave from being
emitted for pointer.Touch sources.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-31 11:55:48 +02:00
Elias Naur d34544cc22 io/router: merge pointerQueue.deliverScrollEvents and deliverEvent
They're similar except for a bit of special handling for scroll events.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-31 11:52:31 +02:00
Elias Naur 4326fee704 app,io/router: scroll focused widgets into view
A focused widget may be partially or completely off-screen in which case
the user will have difficulty interacting with it. This change attempts to
scroll the focused widget into view by issuing synthetic scroll events.

For https://github.com/tailscale/tailscale/issues/4278, but doesn't completely
solve it because layout.Lists won't layout focusable widgets outside its visible
bounds. A follow-up change deals with that.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-31 11:52:31 +02:00
Elias Naur 6389b1a384 io/router: add ScrollGesture
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-30 22:20:27 +02:00
Elias Naur e72c46f13c io/router: use integer coordinates for bounds
There is no need for floating point coordinates, except for transforming
bounds and hit testing.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-30 22:20:27 +02:00
Elias Naur 3e18a310af io/router: replace cursor stack with area field
There's no need to track cursors separately from areas.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-07 13:19:38 +01:00
Elias Naur 99bb542960 io/router: always choose the topmost cursor among candidates
Fixes: https://todo.sr.ht/~eliasnaur/gio/373
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-07 13:05:59 +01:00
Elias Naur 68544111c1 io/router: ensure root pointer area in deferred calls
Fixes: https://todo.sr.ht/~eliasnaur/gio/372
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-07 12:08:08 +01:00
Egon Elbre cdb288d1f9 app,io/pointer: [API] remove CursorNameOp and rename CursorName -> Cursor
It's now possible to directly user pointer.Cursor to add to the ops.

   pointer.CursorText.Add(gtx.Ops)

This is an API change. Use pointer.Cursor directly instead of CursorNameOp.

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2022-03-01 14:05:46 +01:00
Elias Naur 73eabb352d io/router,app: add support for directional focus moves
Implement support for up/down/right/left directional focus moves
and map Android directional pad keys to focus moves.

Fixes: https://todo.sr.ht/~eliasnaur/gio/195
References: https://github.com/tailscale/tailscale/issues/1611
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-02-27 19:01:32 +01:00
Elias Naur cce0a121e1 io/router: don't panic if AppendSemantics is called without a frame
Fixes: https://todo.sr.ht/~eliasnaur/gio/328
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-12-30 10:23:23 +01:00
Pierre Curto 3db11cbaad io/router: make transfer targets hovering easier to detect
In commit 929e4dc12, the rules to send pointer.{Enter,Leave}
events were relaxed. Unfortunately, to be able to make use
of them was not straight forward as it required the transfer
target op to use the same handle as the hover one.
This patch eases this by allowing any handle for the target
as well as not requiring the hover op to be defined on the same
clip op as the target (then requiring a PassOp though), making
it much easier to use.

Also added a test for pointer.Enter events not being generated
if the target type does not match the source one.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-12-19 13:22:11 +01:00
Pierre Curto 929e4dc120 io/router: deliver enter/leave events to transfer participants
When a drag and drop gesture is ongoing, let the potential target
handlers receive enter/leave events so that they can react to them (e.g.
highlight themselves when the dragged item is over them).

Fixes #321.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-12-14 11:43:23 +01:00
Pierre Curto 294ecfbe9d io/router: avoid extra work when dealing with EnterLeave events
When computing the set of Enter/Leave events to be
delivered to handlers, skip non mouse pointers
right away instead of processing hit events.

Also, remove use of pointer to slice use in opHit.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-12-10 06:25:48 +01:00
Pierre Curto 03016f0c69 widget: add drag and drop support
This patch adds internal Drag and Drop support to app.Windows.

The new package io/transfer adds the ability to
define draggable and droppable targets, which
are leveraged by the new widget.Draggable type.

The API is generic and could handle future use
cases, such as external Drag and Drop.

Updates gio#153

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-12-07 12:45:53 +01:00
Elias Naur 8a90074d04 io/semantic: add package for adding semantic descriptions to UI components
Software such as screen readers require semantic descriptions of user
interfaces to effectively present and interact with them. Package
semantic, combined with the existing package clip provide the operations
for Gio programs to describe themselves.

This change implements the semantic package and the routing changes for
accessing semantic trees; follow-ups add semantic information to widgets
and implement mapping semantic tree to platform representations.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-12-01 17:23:54 +01:00
Elias Naur 48a96305c8 io/router: move transform state tracking from pointerCollector to Router
We're going to need transform tracking for the upcoming meta ops.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-12-01 17:23:54 +01:00
Pierre Curto 858e9930c4 io/router: cleanup
Remove unused function and func argument.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-11-26 22:27:10 +01:00
Elias Naur 29cea1db49 io/pointer,io/router: replace AreaOp with clip.Op
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>
2021-11-03 14:12:31 +01:00
Elias Naur 8cafbd309f io/pointer,io/router: make PassOp apply to InputOps, not areas
We're about to make clip.Ops act as pointer areas, in which case we'd
like to contain the effect of PassOp to just pointer InputOps.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-26 12:13:11 +02:00
Elias Naur 60846d112b io/router: introduce pointerCollector to avoid an ops decode
The router package decodes the entire ops list thrice: once for pointer
ops, once for key ops, once for other ops. This change removes one
decode round by merging other ops and pointer ops decoding.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-21 18:16:12 +02:00
Elias Naur a4626d9304 io/router: make the zero value collectState the reset state
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-20 11:31:00 +02:00
Pierre Curto 6b0e00b9aa io/pointer: change Type to uint
This is to allow for future new Types.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-20 10:09:58 +02:00
Pierre Curto e6ed25bb1f io/router: deduplicate pointer handlers
When the same handler is added several times
and that handler sets pointer.Grabbed, it gets lost.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-19 15:00:29 +02:00
Pierre Curto e5d8a4b8d0 io/router: reuse scratch space in pointerQueue.Frame
This removes the allocation needed to drop all handlers except one.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-18 11:47:49 +02:00
Pierre Curto 9be171190e io/router: convert pointerQueue.dropHandlers to pointerQueue.dropHandler
dropHandlers is mainly used for single tag removal except in one instance.
In that case, simply use a loop.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-18 11:47:36 +02:00
Elias Naur 960f3068a1 io/pointer: re-introduce PassOp
A previous change merged PassOp with AreaOp under the assumption that
the pass mode would be set on a particular area. That assumption turns
out not to hold, so this change brings back PassOp as an independent
stack operation.

This is an API change: replace AreaOp{Pass: true} with a separate
pointer.PassOp operation.

Fixes gio#288

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-09 16:31:54 +02:00
Elias Naur 391725b9d0 op: move Ops internal methods and state to internal package ops
Merge package opconsts into ops as well; it only existed to break
import cycles.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-08 17:21:56 +02:00
Elias Naur 936c266b03 all: [API] split operation stack into per-state stacks
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>
2021-10-08 17:21:56 +02:00
Elias Naur 6f80b94b4a io/pointer,io/router: [API] make pass-through a property of AreaOp
We're about to make operation scopes explicit, which would result in
both AreaOp and PassOp be scoped. However, PassOp seems to light to have
its separate stack, so this change instead makes pass-through a property
of an area. We're assuming that clients that want pass-through are also
aware of the affected hit area.

API change: replace PassOps with the AreaOp.PassThrough field.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-08 15:54:50 +02:00
Elias Naur cccb8d2c2b io/router: remove redundant state field
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-07 15:01:17 +02:00
Pierre Curto bfd1e76b78 io/router: refactor pointer.Push for clearer flow
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-03 17:38:39 +02:00
Pierre Curto 5860818537 io/router: merge cancelHandlers and dropHandlers
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-03 17:32:00 +02:00
pierre 5e1a662b94 io/pointer: support nested scrollables
Fixes #185.

Signed-off-by: pierre <pierre.curto@gmail.com>
2021-03-31 09:57:13 +02:00
Elias Naur 17ba8e28af io/router: drop the correct handlers when a pointer grab is requested
Fixes gio#208

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-27 13:18:30 +01:00
pierre 3e525a0393 io/router: move static conditions out of the loop
Signed-off-by: pierre <pierre.curto@gmail.com>
2021-03-25 11:11:30 +01:00
Egon Elbre e66979a8c0 io/router: fix negative areas
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2021-02-24 17:12:36 +01:00
pierre cfb16083a2 io/router: improve areaOp methods performance
name             old time/op  new time/op  delta
AreaOp_Decode-8  10.5ns ± 2%   6.2ns ± 3%  -41.50%  (p=0.000 n=10+10)
AreaOp_Hit-8     4.44ns ± 4%  3.57ns ± 2%  -19.59%  (p=0.000 n=10+10)

Signed-off-by: pierre <pierre.curto@gmail.com>
2021-02-24 12:42:34 +01:00
pierre 60d48014d4 io/router: avoid event copy for filtered events in pointerQueue
Signed-off-by: pierre <pierre.curto@gmail.com>
2021-02-24 12:32:01 +01:00
pierre b698c8ed82 io/router: only calculate position if event is delivered in Router
Signed-off-by: pierre <pierre.curto@gmail.com>
2021-01-27 22:21:31 +01:00
pierre 1100e03c1e io/router: support cursor changes on Frame events
Add support to Router so that the cursor can be changed with CursorNameOp without any mouse movement.
Enter and Leave events are also delivered as areas change.

Signed-off-by: pierre <pierre.curto@gmail.com>
2021-01-27 22:21:27 +01:00
pierre c3346680f4 io/router: merge cursor and delivery of Enter/Leave events in Router
Cursor and Enter/Leave events should follow the same rules, specifically:
when pointerInfo.pressed is true, Enter/Leave processing ignores
pointer.Areas not hit during the pointer.Press event.

Signed-off-by: pierre <pierre.curto@gmail.com>
2021-01-27 22:21:24 +01:00
pierre b11fd6ee8e io/router: fix default cursor in Router
Do not update the cursor was reset upon receiving Cancel events. Added more tests.

Signed-off-by: pierre <pierre.curto@gmail.com>
2021-01-25 17:41:47 +01:00
Elias Naur cc63a3aeb7 io/router: don't send pointer.Cancel events to disappearing handlers
As a follow-up to gioui.org/commit/24f69bf4, this change makes it so
that merely adding a pointer.InputOp doesn't trigger redraws when
the pointer is hovered over its area.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-23 12:00:50 +01:00
Elias Naur 24f69bf4bb io/router: don't trigger redraw for handler reset events
key.InputOp and pointer.InputOp handlers are reset on first registration
through a key.FocusEvent{false} or pointer.Cancel, respectively.

However, the mere act of registering a handle shouldn't result in a
redraw. This is particularly true for misconfigured handlers where a new
tag is supplied every frame, resulting in continously redrawing.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-22 16:34:51 +01:00
Elias Naur d6886737a5 op: change Defer to only restore transformation state
It turns out restoring all operation state from the moment Defer
is executed is too much; for example, a right-click pop-up needs
the transformation, but not the current clip.

Change Defer to only restore the transformation, and reset all
other state.

Other combinations may be needed in future; we'll deal with them then,
possibly by exposing the load state mask.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-19 20:04:30 +01:00
Elias Naur f7902f299b op: implement StackOp in terms of general save/load of state
Push/Pop only allows saving and restoring operation state in a
stack-like manner. We're going to need restoring arbitrary state
for implementing deferred operations.

Generalize state save/restore and implement Push and Pop on top of
that.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-12 20:53:25 +01:00
pierre 578c226278 io/pointer: CursorNameOp no longer needs an InputOp with Leave and Enter events
Signed-off-by: pierre <pierre.curto@gmail.com>
2020-12-15 18:11:48 +01:00
pierre 7c5bcd3db8 io/pointer: added CursorNameOp
The cursor can now be customized for a given area.

Signed-off-by: pierre <pierre.curto@gmail.com>
2020-12-09 09:38:31 +01:00