mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 15:45:38 +00:00
all: rename the gioui.org/ui module to gioui.org
The "ui" is redundant and stutters. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+117
@@ -0,0 +1,117 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
/*
|
||||
Package pointer implements pointer events and operations.
|
||||
A pointer is either a mouse controlled cursor or a touch
|
||||
object such as a finger.
|
||||
|
||||
The InputOp operation is used to declare a handler ready for pointer
|
||||
events. Use a ui.Queue to receive events.
|
||||
|
||||
Areas
|
||||
|
||||
The area operations are used for specifying the area where
|
||||
subsequent InputOp are active.
|
||||
|
||||
For example, to set up a rectangular hit area:
|
||||
|
||||
var ops ui.Ops
|
||||
var h *Handler = ...
|
||||
|
||||
r := image.Rectangle{...}
|
||||
pointer.RectAreaOp{Rect: r}.Add(ops)
|
||||
pointer.InputOp{Key: h}.Add(ops)
|
||||
|
||||
Note that areas compound: the effective area of multiple area
|
||||
operations is the intersection of the areas.
|
||||
|
||||
Matching events
|
||||
|
||||
StackOp operations and input handlers form an implicit tree.
|
||||
Each stack operation is a node, and each input handler is associated
|
||||
with the most recent node.
|
||||
|
||||
For example:
|
||||
|
||||
ops := new(ui.Ops)
|
||||
var stack ui.StackOp
|
||||
var h1, h2 *Handler
|
||||
|
||||
stack.Push(ops)
|
||||
pointer.InputOp{Key: h1}.Add(Ops)
|
||||
stack.Pop()
|
||||
|
||||
stack.Push(ops)
|
||||
pointer.InputOp{Key: h2}.Add(ops)
|
||||
stack.Pop()
|
||||
|
||||
implies a tree of two inner nodes, each with one pointer handler.
|
||||
|
||||
When determining which handlers match an Event, only handlers whose
|
||||
areas contain the event position are considered. The matching
|
||||
proceeds as follows.
|
||||
|
||||
First, the foremost matching handler is included. If the handler
|
||||
has pass-through enabled, this step is repeated.
|
||||
|
||||
Then, all matching handlers from the current node and all parent
|
||||
nodes are included.
|
||||
|
||||
In the example above, all events will go to h2 only even though both
|
||||
handlers have the same area (the entire screen).
|
||||
|
||||
Pass-through
|
||||
|
||||
The PassOp operations controls the pass-through setting. A handler's
|
||||
pass-through setting is recorded along with the InputOp.
|
||||
|
||||
Pass-through handlers are useful for overlay widgets such as a hidden
|
||||
side drawer. When the user touches the side, both the (transparent)
|
||||
drawer handle and the interface below should receive pointer events.
|
||||
|
||||
Disambiguation
|
||||
|
||||
When more than one handler matches a pointer event, the event queue
|
||||
follows a set of rules for distributing the event.
|
||||
|
||||
As long as the pointer has not received a Press event, all
|
||||
matching handlers receive all events.
|
||||
|
||||
When a pointer is pressed, the set of matching handlers is
|
||||
recorded. The set is not updated according to the pointer position
|
||||
and hit areas. Rather, handlers stay in the matching set until they
|
||||
no longer appear in a InputOp or when another handler in the set
|
||||
grabs the pointer.
|
||||
|
||||
A handler can exclude all other handler from its matching sets
|
||||
by setting the Grab flag in its InputOp. The Grab flag is sticky
|
||||
and stays in effect until the handler no longer appears in any
|
||||
matching sets.
|
||||
|
||||
The losing handlers are notified by a Cancel event.
|
||||
|
||||
For multiple grabbing handlers, the foremost handler wins.
|
||||
|
||||
Priorities
|
||||
|
||||
Handlers know their position in a matching set of a pointer through
|
||||
event priorities. The Shared and Foremost priorities are for matching sets
|
||||
with multiple handlers; the Grabbed priority indicate exclusive access.
|
||||
|
||||
Priorities are useful for deferred gesture matching.
|
||||
|
||||
Consider a scrollable list of clickable elements. When the user touches an
|
||||
element, it is unknown whether the gesture is a click on the element
|
||||
or a drag (scroll) of the list. While the click handler might light up
|
||||
the element in anticipation of a click, the scrolling handler does not
|
||||
scroll on finger movements with lower than Grabbed priority.
|
||||
|
||||
Should the user release the finger, the click handler registers a click.
|
||||
|
||||
However, if the finger moves beyond a threshold, the scrolling handler
|
||||
determines that the gesture is a drag and sets its Grab flag. The
|
||||
click handler receives a Cancel (removing the highlight) and further
|
||||
movements for the scroll handler has priority Grabbed, scrolling the
|
||||
list.
|
||||
*/
|
||||
package pointer
|
||||
@@ -0,0 +1,209 @@
|
||||
// SPDX-License-Identifier: Unlicense OR MIT
|
||||
|
||||
package pointer
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"image"
|
||||
"time"
|
||||
|
||||
"gioui.org/ui"
|
||||
"gioui.org/f32"
|
||||
"gioui.org/internal/opconst"
|
||||
)
|
||||
|
||||
// Event is a pointer event.
|
||||
type Event struct {
|
||||
Type Type
|
||||
Source Source
|
||||
// PointerID is the id for the pointer and can be used
|
||||
// to track a particular pointer from Press to
|
||||
// Release or Cancel.
|
||||
PointerID ID
|
||||
// Priority is the priority of the receiving handler
|
||||
// for this event.
|
||||
Priority Priority
|
||||
// Time is when the event was received. The
|
||||
// timestamp is relative to an undefined base.
|
||||
Time time.Duration
|
||||
// Hit is set when the event was within the registered
|
||||
// area for the handler. Hit can be false when a pointer
|
||||
// was pressed within the hit area, and then dragged
|
||||
// outside it.
|
||||
Hit bool
|
||||
// Position is the position of the event, relative to
|
||||
// the current transformation, as set by ui.TransformOp.
|
||||
Position f32.Point
|
||||
// Scroll is the scroll amount, if any.
|
||||
Scroll f32.Point
|
||||
}
|
||||
|
||||
// RectAreaOp updates the hit area to the intersection
|
||||
// of the current hit area with a rectangular area.
|
||||
type RectAreaOp struct {
|
||||
// Rect defines the rectangle. The current transform
|
||||
// is applied to it.
|
||||
Rect image.Rectangle
|
||||
}
|
||||
|
||||
// EllipseAreaOp updates the hit area to the intersection
|
||||
// of the current hit area with an elliptical area.
|
||||
type EllipseAreaOp struct {
|
||||
// Rect is the bounds for the ellipse. The current transform
|
||||
// is applied to the rectangle.
|
||||
Rect image.Rectangle
|
||||
}
|
||||
|
||||
// Must match the structure in input.areaOp
|
||||
type areaOp struct {
|
||||
kind areaKind
|
||||
rect image.Rectangle
|
||||
}
|
||||
|
||||
// InputOp declares an input handler ready for pointer
|
||||
// events.
|
||||
type InputOp struct {
|
||||
Key ui.Key
|
||||
// Grab, if set, request that the handler get
|
||||
// Grabbed priority.
|
||||
Grab bool
|
||||
}
|
||||
|
||||
// PassOp sets the pass-through mode.
|
||||
type PassOp struct {
|
||||
Pass bool
|
||||
}
|
||||
|
||||
type ID uint16
|
||||
|
||||
// Type of an Event.
|
||||
type Type uint8
|
||||
|
||||
// Priority of an Event.
|
||||
type Priority uint8
|
||||
|
||||
// Source of an Event.
|
||||
type Source uint8
|
||||
|
||||
// Must match app/internal/input.areaKind
|
||||
type areaKind uint8
|
||||
|
||||
const (
|
||||
// A Cancel event is generated when the current gesture is
|
||||
// interrupted by other handlers or the system.
|
||||
Cancel Type = iota
|
||||
// Press of a pointer.
|
||||
Press
|
||||
// Release of a pointer.
|
||||
Release
|
||||
// Move of a pointer.
|
||||
Move
|
||||
)
|
||||
|
||||
const (
|
||||
// Mouse generated event.
|
||||
Mouse Source = iota
|
||||
// Touch generated event.
|
||||
Touch
|
||||
)
|
||||
|
||||
const (
|
||||
// Shared priority is for handlers that
|
||||
// are part of a matching set larger than 1.
|
||||
Shared Priority = iota
|
||||
// Foremost is like Shared, but the handler is
|
||||
// the foremost in the matching set.
|
||||
Foremost
|
||||
// Grabbed is used for matching sets of size 1.
|
||||
Grabbed
|
||||
)
|
||||
|
||||
const (
|
||||
areaRect areaKind = iota
|
||||
areaEllipse
|
||||
)
|
||||
|
||||
func (op RectAreaOp) Add(ops *ui.Ops) {
|
||||
areaOp{
|
||||
kind: areaRect,
|
||||
rect: op.Rect,
|
||||
}.add(ops)
|
||||
}
|
||||
|
||||
func (op EllipseAreaOp) Add(ops *ui.Ops) {
|
||||
areaOp{
|
||||
kind: areaEllipse,
|
||||
rect: op.Rect,
|
||||
}.add(ops)
|
||||
}
|
||||
|
||||
func (op areaOp) add(o *ui.Ops) {
|
||||
data := make([]byte, opconst.TypeAreaLen)
|
||||
data[0] = byte(opconst.TypeArea)
|
||||
data[1] = byte(op.kind)
|
||||
bo := binary.LittleEndian
|
||||
bo.PutUint32(data[2:], uint32(op.rect.Min.X))
|
||||
bo.PutUint32(data[6:], uint32(op.rect.Min.Y))
|
||||
bo.PutUint32(data[10:], uint32(op.rect.Max.X))
|
||||
bo.PutUint32(data[14:], uint32(op.rect.Max.Y))
|
||||
o.Write(data)
|
||||
}
|
||||
|
||||
func (h InputOp) Add(o *ui.Ops) {
|
||||
data := make([]byte, opconst.TypePointerInputLen)
|
||||
data[0] = byte(opconst.TypePointerInput)
|
||||
if h.Grab {
|
||||
data[1] = 1
|
||||
}
|
||||
o.Write(data, h.Key)
|
||||
}
|
||||
|
||||
func (op PassOp) Add(o *ui.Ops) {
|
||||
data := make([]byte, opconst.TypePassLen)
|
||||
data[0] = byte(opconst.TypePass)
|
||||
if op.Pass {
|
||||
data[1] = 1
|
||||
}
|
||||
o.Write(data)
|
||||
}
|
||||
|
||||
func (t Type) String() string {
|
||||
switch t {
|
||||
case Press:
|
||||
return "Press"
|
||||
case Release:
|
||||
return "Release"
|
||||
case Cancel:
|
||||
return "Cancel"
|
||||
case Move:
|
||||
return "Move"
|
||||
default:
|
||||
panic("unknown Type")
|
||||
}
|
||||
}
|
||||
|
||||
func (p Priority) String() string {
|
||||
switch p {
|
||||
case Shared:
|
||||
return "Shared"
|
||||
case Foremost:
|
||||
return "Foremost"
|
||||
case Grabbed:
|
||||
return "Grabbed"
|
||||
default:
|
||||
panic("unknown priority")
|
||||
}
|
||||
}
|
||||
|
||||
func (s Source) String() string {
|
||||
switch s {
|
||||
case Mouse:
|
||||
return "Mouse"
|
||||
case Touch:
|
||||
return "Touch"
|
||||
default:
|
||||
panic("unknown source")
|
||||
}
|
||||
}
|
||||
|
||||
func (Event) ImplementsEvent() {}
|
||||
Reference in New Issue
Block a user