The method no longer returns anything, and thus does not actually report
whether any events matched a handler.
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
Widgets have themselves as tags, by convention, and so it's possible to
replace the per-widget Focused methods with a general-purpose Source.
Focused query.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The empty key.Filter.Name now means matching every key name. This is a
replacement for the previous special case where the top-level key.InputOp
handler would get all unmatched events.
Add special case for system events such as focus switch shortcuts.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
New handlers receive reset events the first time Source.Event is called.
However, in case the filter doesn't match a reset event it shouldn't be
reported.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
It's semantically problematic that a zero Kind matches Cancel, and
outweighs the downside of having to explicitly mention Cancel in filters.
For example, GrabCmd was always deferred because the resulting Cancel
events always match the processed filters.
Remove Frame from a few tests now that GrabCmd can be executed
immediately.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Replace the key.Filter.Target field with a Focus field that matches only
of the specified tag has focus. This has the advantage of simpler event
delivery and for lower latency in delivering key events to new handlers.
For example, consider a UI where a button is activated by a key press,
which is turn displays a dialog with another button activated by the
same key. This change allows two button press(+releases) in the same frame
to arrive at the intended targets: one key press(+release) for each
button.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Until now, every event has had a particular target. We're about to simplify
key event delivery to match the first matching filter, so there is no
longer a global meaning to the tag argument to Source.Event.
Add fields to filters to specify their target tags.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
If the client asks for the focus to be set to a tag, allow it. There is a
check at the end of Router.Frame that clears the focus if the tag turns
out to fail the requirements (visible and has asked for FocusEvents).
The change simplifies the logic for determining whether a command can
be executed immediately.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Processing one event at a time allows a widget to execute commands after
the event that triggered it, instead of after all matching events.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Change the semantics of commands to execute immediately. In cases where
execution of a command introduces a inconsistency, freeze event routing
and defer the command as well as queued events to the next frame.
Rename Source.Queue to Source.Execute to better fit the new command
semantics.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Refactor the pointer and key filter unions into the handler state struct.
This is a preparation for replacing calls to filtersMatches with queries
to the filter union.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We're about to need per-handler state related to neither pointer nor
key input. This change merges the pointer and key handler state into one
state struct, tracked in the Router.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This change defers event routing from the time the event is queued until
the time Events is called. This allows a future change to execute
commands immediately and to react to event order changes during a frame.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Replace the per-event event queues with a single queue of events, each
marked with the target tag. This change is a prerequisite for lazy event
delivery.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We're about the refactor this quite subtle code, and the optimization
doesn't seem to carry its weight in complexity.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Refactor delivery of reset events to be resolved and delivered as part of
Source.Events. This is a preparation for changing event handling to be
lazy.
Reset events are delivered to event handlers that are either new or
haven't been active in the previous frame for a particular event type
(pointer or key events), to ensure the handler state is reset.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
We're about to replace key.InputOp with a filter; this change separates
the input hint into its own operation.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Instead of having to supply the predicates for event filtering at the
time of layout, the new Filter type allows widgets to filter at the time
of calling Source.Events. There is then only the need for a single input
op type, in package event.
Filters most importantly allow the use of one tag for several event types,
and we can define that a widget w has &w as its primary tag, by convention.
This allows the replacement of per-widget Focus methods with direct uses
of FocusCmd{&w}, and the later addition of Source.Focused(&w) queries.
Note that the TestCursor test needed restructuring to avoid its use of
InputOps.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
Modeling focus change as an operation is awkward, because focus changes
logically happen during event processing, not layout. In particular, you
want to apply focus changes even if a widget is subsequently never laid
out.
Now that input.Source is concrete, it's much more straightforward to
offer focus changes as a command which can be queued through the
Source. A future change may similarly offer a command for directional
focus changes.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This change gets rid of the event.Queue interface by replacing it with
input.Source values. Source provides the interface to Router necessary
to implement interface widgets.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
In the early days of Gio, FrameEvent was part of package app. It was
moved to package system to enable layout.NewContext be a convenient
short-hand for constructing a layout.
However, it seems the better design to leave FrameEvent (and Insets) in
package app, and move layout.NewContext there as well. More importantly,
the move allows us to replace the event.Queue interface with a concrete
type.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
It was a design mistake to make profiling data available to programs.
Rather, profiling should either be a user-configurable debug overlay,
reported through runtime/trace, or both.
This change drops the io/profile package because we're about to overhaul
event routing.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This change removes the extra frame scheduled when events was delivered
during a frame. This extra frame was intended to paper over state changes
that happen later than the layout depending on it.
However, it is better for programs to never allow such state change skew,
and recent changes allows them to refresh and query state before layout.
This is an API change because programs may rely on the extra frames.
Those programs should ensure that state is updated before relying on it
in layout.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The double-negative DisabledOp is harder to understand than a
straightforward EnabledOp. Note that the absence of an EnabledOp
implies still means that the widget is enabled.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
When storing a string in an interface value that escapes, Go has to heap
allocate space for the string header, as interface values can only store
pointers. In text-heavy applications, this can lead to hundreds of
allocations per frame due to semantic.LabelOp, the primary user of
string-typed references in ops.
Instead of allocating each string header individually, provide a slice
of strings to store string-typed references in, and store pointers into
this slice as the actual references. This only allocates when resizing
the slice's backing array, and averages out to no allocations, as the
backing array gets reused between calls to Ops.Reset.
We introduce two new functions, Write1String and Write2String, which
make use of this new slice for their last argument. We could've
automated this in the existing Write1 and Write2 methods, but that would
require type assertions on each call, and the vast majority of ops do
not make use of strings.
Signed-off-by: Dominik Honnef <dominik@honnef.co>