63 Commits

Author SHA1 Message Date
Eugene e49c5b02c7 gesture: refresh PointerID on Press and Enter
Click and Hover both stored the first PointerID they observed in
their internal pid field and only updated it when not currently
hovered/entered. Once the gesture became hovered, any later event
under a different PointerID was effectively ignored: Click.Press
fell through 'c.pid != e.PointerID' and was silently dropped, and
Hover could never reset entered when the matching Leave arrived
under a new ID.

The Windows backend enables EnableMouseInPointer
(app/os_windows.go), under which Windows reassigns the same
physical mouse's PointerID across focus changes, window
leave/re-enter, and similar events. Once a widget had been hovered,
every subsequent press on it failed to register, including
widget.Editor's internal clicker that positions the caret on press.
Multi-line editors silently refused to move the caret on click
after the window had received any focus event.

Always take the latest PointerID on Hover.Enter and Click.Press.
The Press/Release handshake still works because Press now records
the press's own PointerID and Release continues to gate on
'c.pid != e.PointerID' so an unrelated pointer's release can't end
the press tracking.

Signed-off-by: Eugene <eugenebosyakov@gmail.com>
2026-04-30 06:19:20 +02:00
inkeliz 0225334124 layout,gesture: add option to handle vertical scroll on horizontal list
Previously, it was impossible to scroll a Axis == Horizontal using
ordinary mouse-wheel. Now, it's possible to set ScrollAnyAxis == True,
which combine scrolling from any direction. That makes possible
to scroll Horizontal lists with vertical mouse-wheel.

By default this option is false, keeping the old behaviour.

Signed-off-by: inkeliz <inkeliz@inkeliz.com>
2025-05-16 16:52:45 +02:00
Elias Naur ee6cdec60b io/pointer: [API] split scroll bounds into two separate axes
A single image.Rectangle for the scroll bounds introduced a subtle issue
with zero area rectangles (see #572). To avoid that and similar issues,
split the bounds into two separate one-dimensional ranges.

Fixes: https://todo.sr.ht/~eliasnaur/gio/572
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-04-14 08:54:12 +02:00
Elias Naur dbc10056f9 io/event: [API] rename InputOp to Op
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-02-05 11:09:36 +00:00
Elias Naur 33f9a850c8 io/pointer: make Cancel non-zero
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>
2024-02-05 11:09:36 +00:00
Elias Naur d9a007586c all: [API] replace tag parameter of Source.Event with per-filter tags
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>
2024-02-05 11:09:36 +00:00
Elias Naur 8e209fd2eb gesture: report one event at a time
Events are now delivered one at a time, and this change makes the
corresponding change to gestures.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-02-05 11:09:36 +00:00
Elias Naur c515b7804e all: replace InvalidateOp with InvalidateCmd command
Curiously, InvalidateCmd is probably the only command that is appropriate
to call during layout.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-02-05 11:09:36 +00:00
Elias Naur 88f5ac9cb9 all: [API] deliver events one at a time to allow fine-grained event processing
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>
2024-02-05 11:09:36 +00:00
Elias Naur fc208248b7 io/input: [API] execute commands immediately
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>
2024-02-05 11:09:36 +00:00
Elias Naur ef8171b971 io: [API] introduce event filters; convert pointer input to use them
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>
2024-02-05 10:59:51 +00:00
Elias Naur 1bcbaa8137 io/input,io/pointer: [API] make pointer grab a command
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-02-05 10:59:51 +00:00
Elias Naur 6027517949 io/input: [API] introduce Source, the interface between a Router and widgets
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>
2024-02-05 10:59:51 +00:00
Elias Naur d5a0d2cf60 io/input,io/router: [API] rename package io/router to io/input
The input name better matches its purpose, in particular when we
introduce input.Source.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2024-02-05 10:59:51 +00:00
Dominik Honnef e666ef35ca gesture: adjust ClickKind.String for ClickType -> ClickKind rename
Signed-off-by: Dominik Honnef <dominik@honnef.co>
2024-01-04 11:56:50 -06:00
Elias Naur c756986d9e gesture: [API] rename gesture state update methods to Update
Change the gesture state update methods to align with the convention.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-10-08 12:37:12 -05:00
Elias Naur 1686874d07 gesture: [API] rename ClickType to ClickKind
"Kind" is the Go idiomatic name for distinguishing structs outside of
the type system.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-10-06 19:11:11 -05:00
Elias Naur 650ccea28d io/pointer: [API] rename PointerEvent.Type to Kind
Kind is the idiomatic field name for distinguishing a struct without
using separate types.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2023-10-06 19:11:08 -05:00
Elias Naur 5c896eabbb gesture,widget: detect multi-click on pointer.Press
References: https://todo.sr.ht/~eliasnaur/gio/455
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-11-07 07:26:19 -06:00
Elias Naur 3d37491342 all: [API] replace unit.Value with separate unit.Dp, unit.Sp types
The unit.Value is a struct and thus more inconvenient to use than its
underlying float32 type. In addition, most uses don't need a general
value, but rather a specific unit given by the context. This change
replaces unit.Value with two float32 units, Dp and Sp. It also changes
variables and parameters of unit.Value to a specific unit type matching
the context. That is, unit.Dp everywhere except for text sizes which are
in Sp.

Switching to typed float32s has multiple advantages

- They can be constants:

const touchSlop = unit.Dp(16)

- Casting untyped constants is no longer necessary:

insets := layout.UniformInset(16)

- Calculation with values is natural:

func (s ScrollbarStyle) Width() unit.Dp {
	return s.Indicator.MinorWidth + s.Track.MinorPadding + s.Track.MinorPadding
}

The main API change is that calls to gtx.Px must be replaced with either
gtx.Dp or gtx.Sp depending on the unit.

Idea by Christophe Meessen.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-05-31 10:24:09 +02:00
Elias Naur 14805af367 gesture,widget,f32: [API] use integer coordinates for gesture coordinates
Most widget code operate in integer coordinates. This change makes
gesture pointer coordinates integer, to lessen the number of float32
to int conversions.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-05-31 10:24:09 +02:00
Elias Naur 2069d5cb2e gesture: don't rely on Enter events to determine validity of click
We're about to not emit Enter and Leave events for touch input, and
this change changes the Click gesture to no longer rely on those
events to determine whether a Release is inside its bounds.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2022-03-31 11:52:31 +02:00
Rajiv Kanchan 29e6159d30 gesture: fix Hover by handling pointer.Cancel event
pointer.Cancel event is ignored, resulting in Hovered returning true
even though the pointer is no longer hovering over the region.
This change fixes it.

Signed-off-by: Rajiv Kanchan <rajiivkanchan@gmail.com>
2022-01-25 09:54:01 +01:00
Pierre Curto c8ca36b1e6 gesture: add comment to Scroll.Add
Provide a reference to the documentation of io/pointer.InputOp.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-12-14 10:53:51 +01:00
Elias Naur 3e0b72304a all: replace deprecated pointer.Rect with clip.Rect
Converted with

gofmt -w -r 'pointer.Rect(r) -> clip.Rect(r)' .
gofmt -w -r 'pointer.Ellipse(r) -> clip.Ellipse(layout.FRect(r))' .

combined with 'goimports -w .' to clean up imports.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-11-03 14:12:31 +01:00
Elias Naur a0c756c557 gesture: add license identifier to gesture_test.go
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-10-25 17:10:26 +02:00
Pierre Curto 9c16954bef gesture: add Hover type
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-19 15:59:25 +02:00
Pierre Curto e11ac9784c gesture: add the Pressed method to Drag
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-10-06 08:21:55 +02:00
Pierre Curto 7463910191 gesture: fix typos in comments, remove unused type
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
2021-09-19 11:04:02 +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 ffb26b0e17 io/pointer: rename button names to reflect their meaning, not placement
For example, ButtonLeft may be the right-most button for a left-handed user.
Rename the button names to match their intended use.

This is an API change. Use the following commands to update your
projects:

    $ gofmt -r 'pointer.ButtonLeft -> pointer.ButtonPrimary' -w .
    $ gofmt -r 'pointer.ButtonRight -> pointer.ButtonSecondary' -w .
    $ gofmt -r 'pointer.ButtonMiddle -> pointer.ButtonTertiary' -w .

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-03-03 11:08:41 +01:00
Larry Clapp 34273940a0 widget,widget/material: add selection to the editor
- Allow dragging to be on both horizontal and vertical axes at once.
- Split Editor.caret.pos into caret.start and caret.stop. caret.start is
  the old caret.pos, and is both the position of the caret, and also the
  start of selected text. caret.end is the end of the selected text.
  Start can be after end, e.g. after after Shift-DownArrow.
- Update caret.end after a mouse drag, and various shifted keys
  (Shift-UpArrow, Shift-DownArrow, etc).
- Change Shortcut-C to copy only the selected text, not the whole editor
  text.
- Add Shortcut-X to copy and delete selected text, and Shortcut-A to
  select all text.
- The various Insert/Delete/etc functions now overwrite or delete the
  selection, as appropriate.
- Change MoveCaret to accept a distance for selection end, as well.
  Change SetCaret to accept a selection end offset.
- Add SelectionLen to get the selection length, Selection to get
  selection offsets, SelectedText to get the selected text, and
  ClearSelection to clear the selection.
- Add a rudimentary selection unit test, and extend the deleteWord unit
  test with some text selection cases.
- Add SelectionColor to material.EditorStyle, which defaults to
  Theme.Palette.ContrastBg.

Signed-off-by: Larry Clapp <larry@theclapp.org>
2021-01-24 09:44:52 +01:00
Elias Naur 4f45d9a567 io/router: rename Router.Add to the more specific Queue
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2021-01-22 16:36:14 +01:00
Egon Elbre 93ebd51531 gesture,widget: add hovered property
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2021-01-18 10:56:52 +01:00
Egon Elbre 0b2a2d6c2e {gesture,widget}: expose Dragging
Knowing whether a widget is being interacted with allows to implement
bi-directional updates without feedbacks.

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2020-12-11 16:44:22 +01:00
Elias Naur 6ab43aba3e all: implement staticcheck suggestions
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-07-19 10:47:17 +02:00
Gordon Klaus 5368743478 widget,widget/material: add Float and Slider
Signed-off-by: Gordon Klaus <gordon.klaus@gmail.com>
2020-06-22 12:17:35 +02:00
Elias Naur b9f6543cf5 gesture: always drag scroll on Android
Mice drags scroll on Android by convention. Further, ChromeOS converts
two-finger touchpad scroll gestures to press-drag with Source == Mouse.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-06-19 20:05:01 +02:00
Elias Naur 596e321610 all: make unit.Converter concrete and rename to Metric
An interface for scaling dp and sp is overkill, at least for all
current uses. Make it a concrete struct type, and rename it to the
shorter and more precise Metric.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-06-17 11:47:14 +02:00
Elias Naur 5e37a64ff1 gesture: remove Click.State and cancel Click gesture on outside Release
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-06-09 00:12:05 +02:00
Elias Naur ce56464923 widget,gesture: fade out cancelled inkwells
While here, adjust inkwell sizes to match gtx.Constraints.Min.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-06-08 23:50:00 +02:00
Elias Naur 0444caa9e3 gesture,widget: drop press markers on gesture cancel
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-06-08 21:44:57 +02:00
Elias Naur 65d4707e3e io/pointer,io/router,gesture: add pointer.Foremost priority
Replace the pointer.Scroll special case with a new priority that
indicates the foremost handler, checked in gesture.Scroll.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-06-05 10:46:19 +02:00
Gordon Klaus 1a070a36b6 io/pointer: add Drag event type
This eliminates needless redraws for handlers that care about drag events and not move events, like gesture.Scroll.

Signed-off-by: Gordon Klaus <gordon.klaus@gmail.com>
2020-06-03 20:04:16 +02:00
Gordon Klaus 9d2a6c48d8 io/pointer: add InputOp.Types to specify which types of events to receive
Signed-off-by: Gordon Klaus <gordon.klaus@gmail.com>
2020-06-03 15:29:12 +02:00
Gordon Klaus e188d0e6ff io/pointer,gesture,app/internal/window: add pointer.Scroll event type
Signed-off-by: Gordon Klaus <gordon.klaus@gmail.com>
2020-06-03 10:08:22 +02:00
Elias Naur 3b28c5d067 io/router: simplify pointer event routing
- Drop pointer.Event.Hit in favour of Enter/Leave events.
- Track enter/leaves for each pointer.ID (updates #122). Add test.
- Resolve grabs once.
- Get rid of scratch slice.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-06-01 00:04:34 +02:00
Elias Naur 03db2817ac all: rename io/event.Key to Tag
Key had an unfortunate association with keyboard input.

This is an API change. The following rewrites were run to fixup
Gio code:

        $ gofmt -r 'pointer.InputOp{Key:a} -> pointer.InputOp{Tag:a}' -w .
        $ gofmt -r 'pointer.InputOp{Key:a, Grab:b} -> pointer.InputOp{Tag:a, Grab:b}' -w .
        $ gofmt -r 'key.InputOp{Key:a} -> key.InputOp{Tag:a}' -w .
        $ gofmt -r 'key.InputOp{Key:a, Focus:b} -> key.InputOp{Tag:a, Focus:b}' -w .
        $ gofmt -r 'event.Key -> event.Tag' -w .

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-05-17 19:48:12 +02:00
Elias Naur f2fee00bab Revert "gesture: only report TypePress for Click gestures if pointer is grabbed"
This reverts commit 062e2bc54b.

Reason: delays the press too much for the common case of an embedding List.
2020-05-16 12:09:18 +02:00
Elias Naur 062e2bc54b gesture: only report TypePress for Click gestures if pointer is grabbed
Signed-off-by: Elias Naur <mail@eliasnaur.com>
2020-05-11 16:50:07 +02:00