9cc6757da99a7abd6f6c91c43b14833126c52911 — Elias Naur 14 days 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)
  	...
  	ops.Reset()
  	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.
  	stack.Push(ops)


@@ 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
  	macro.Record()
  	// 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
+ operations.
  
  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.
+ 
+ Areas
+ 
+ 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).
+ 
+ Pass-through
+ 
+ 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.
+ 
+ Disambiguation
+ 
+ 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.
+ 
+ Priorities
+ 
+ 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
+ list.
+ */
+ package pointer

M ui/pointer/pointer.go => ui/pointer/pointer.go +54 -10
@@ 13,22 13,45 @@ "gioui.org/ui/internal/opconst"
  )
  
+ // 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.
  	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
  )