9cc6757da99a7abd6f6c91c43b14833126c52911 — Elias Naur 3 months ago 1a9e03b
ui/pointer: expand documentation

Signed-off-by: Elias Naur <mail@eliasnaur.com>
5 files changed, 179 insertions(+), 16 deletions(-)

M ui/doc.go
M ui/input/input.go
M ui/key/key.go
A ui/pointer/doc.go
M ui/pointer/pointer.go
M ui/doc.go => ui/doc.go +3 -3
@@ 24,7 24,7 @@
 	import "gioui.org/ui/paint"
 	var w app.Window
-	var ops ui.Ops
+	ops := new(ui.Ops)
 	paint.ColorOp{Color: ...}.Add(ops)

@@ 38,7 38,7 @@
 The StackOp saves the current state to the state stack and restores it later:
-	var ops ui.Ops
+	ops := new(ui.Ops)
 	var stack ui.StackOp
 	// Save the current state, in particular the transform.

@@ 50,7 50,7 @@
 The MacroOp records a list of operations to be executed later:
-	var ops ui.Ops
+	ops := new(ui.Ops)
 	var macro ui.MacroOp
 	// Record operations by adding them.

M ui/input/input.go => ui/input/input.go +1 -1
@@ 23,7 23,7 @@
 	import gioui.org/ui/input
 	import gioui.org/ui/key
-	var ops ui.Ops
+	ops := new(ui.Ops)
 	var h *Handler = ...
 	key.HandlerOp{Key: h}.Add(ops)

M ui/key/key.go => ui/key/key.go +3 -2
@@ 1,7 1,8 @@
 // SPDX-License-Identifier: Unlicense OR MIT
-Package key implements key and text input handling.
+Package key implements key and text events and
 The HandlerOp operations is used for declaring key
 input handlers. Use the Queue interface from package

@@ 28,7 29,7 @@
 // be hidden.
 type HideInputOp struct{}
-// FocusEvent is sent when a handler gains or looses
+// FocusEvent is sent when a handler gains or loses
 // focus.
 type FocusEvent struct {
 	Focus bool

A ui/pointer/doc.go => ui/pointer/doc.go +118 -0
@@ 0,0 1,118 @@
+// 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 HandlerOp operation is used to declare a handler ready
+for pointer events. Use a Queue from package input to
+receive events.
+The area operations are used for specifying the area where
+subsequent HandlerOps 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.HandlerOp{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.HandlerOp{Key: h1}.Add(Ops)
+	stack.Pop()
+	stack.Push(ops)
+	pointer.HandlerOp{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).
+The PassOp operations controls the pass-through setting. A handler's
+pass-through setting is recorded along with the HandlerOp.
+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.
+When more than one handler matches a pointer event, the input 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 HandlerOp 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 HandlerOp. 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.
+Handlers know their position in a matching set of a pointer through
+event priorities. The Shared and Foremost 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
+package pointer

M ui/pointer/pointer.go => ui/pointer/pointer.go +54 -10
@@ 13,22 13,45 @@
+// Event is a pointer event.
 type Event struct {
-	Type      Type
-	Source    Source
+	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  Priority
-	Time      time.Duration
-	Hit       bool
-	Position  f32.Point
-	Scroll    f32.Point
+	// 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

@@ 38,40 61,61 @@
 	rect image.Rectangle
+// HandlerOp declares an input handler ready for pointer
+// events.
 type HandlerOp struct {
-	Key  input.Key
+	Key input.Key
+	// Grab, if set, request that the handler get
+	// Grabbed priority.
 	Grab bool
-// PassOp change the current event pass-through
-// setting.
+// 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 input.areaKind
 type areaKind uint8
 const (
+	// Cancel is sent when the current gesture is interrupted
+	// by other handlers or the system.
 	Cancel Type = iota
+	// Press of a pointer.
+	// Release of a pointer.
+	// Move of a pointer.
 const (
+	// Mouse generated event.
 	Mouse Source = iota
+	// Touch generated event.
 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.
+	// Grabbed is used for matching sets of size 1.