ui: merge package input

Event handling is as fundamental as operations, so move the input
package declarations to package ui.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-09-24 22:11:44 +02:00
parent 2782436ffc
commit 3944ef4b2e
15 changed files with 108 additions and 122 deletions
+3 -3
View File
@@ -57,9 +57,9 @@ For example, to display a blank but otherwise functional window:
Event queue
A Window's Queue method returns an input.Queue implementation that distributes
incoming events to the input handlers declared in the latest call to Update.
See the gioui.org/ui/input package for more information about input handlers.
A Window's Queue method returns an ui.Queue implementation that distributes
incoming events to the event handlers declared in the latest call to Update.
See the gioui.org/ui package for more information about event handlers.
*/
package app
+8 -9
View File
@@ -4,7 +4,6 @@ package input
import (
"gioui.org/ui"
"gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/ops"
"gioui.org/ui/key"
@@ -13,8 +12,8 @@ import (
type TextInputState uint8
type keyQueue struct {
focus input.Key
handlers map[input.Key]*keyHandler
focus ui.Key
handlers map[ui.Key]*keyHandler
reader ops.Reader
state TextInputState
}
@@ -46,7 +45,7 @@ func (q *keyQueue) InputState() TextInputState {
func (q *keyQueue) Frame(root *ui.Ops, events *handlerEvents) {
if q.handlers == nil {
q.handlers = make(map[input.Key]*keyHandler)
q.handlers = make(map[ui.Key]*keyHandler)
}
for _, h := range q.handlers {
h.active = false
@@ -83,14 +82,14 @@ func (q *keyQueue) Frame(root *ui.Ops, events *handlerEvents) {
}
}
func (q *keyQueue) Push(e input.Event, events *handlerEvents) {
func (q *keyQueue) Push(e ui.Event, events *handlerEvents) {
if q.focus != nil {
events.Add(q.focus, e)
}
}
func (q *keyQueue) resolveFocus(events *handlerEvents) (input.Key, listenerPriority, bool) {
var k input.Key
func (q *keyQueue) resolveFocus(events *handlerEvents) (ui.Key, listenerPriority, bool) {
var k ui.Key
var pri listenerPriority
var hide bool
loop:
@@ -116,7 +115,7 @@ loop:
h = new(keyHandler)
q.handlers[op.Key] = h
// Reset the handler on (each) first appearance.
events.Set(op.Key, []input.Event{key.FocusEvent{Focus: false}})
events.Set(op.Key, []ui.Event{key.FocusEvent{Focus: false}})
}
h.active = true
case opconst.TypeHideInput:
@@ -145,6 +144,6 @@ func decodeKeyInputOp(d []byte, refs []interface{}) key.InputOp {
}
return key.InputOp{
Focus: d[1] != 0,
Key: refs[0].(input.Key),
Key: refs[0].(ui.Key),
}
}
+9 -10
View File
@@ -8,7 +8,6 @@ import (
"gioui.org/ui"
"gioui.org/ui/f32"
"gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/ops"
"gioui.org/ui/pointer"
@@ -17,10 +16,10 @@ import (
type pointerQueue struct {
hitTree []hitNode
areas []areaNode
handlers map[input.Key]*pointerHandler
handlers map[ui.Key]*pointerHandler
pointers []pointerInfo
reader ops.Reader
scratch []input.Key
scratch []ui.Key
}
type hitNode struct {
@@ -30,13 +29,13 @@ type hitNode struct {
pass bool
// For handler nodes.
key input.Key
key ui.Key
}
type pointerInfo struct {
id pointer.ID
pressed bool
handlers []input.Key
handlers []ui.Key
}
type pointerHandler struct {
@@ -101,7 +100,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t u
if !ok {
h = new(pointerHandler)
q.handlers[op.Key] = h
events.Set(op.Key, []input.Event{pointer.Event{Type: pointer.Cancel}})
events.Set(op.Key, []ui.Event{pointer.Event{Type: pointer.Cancel}})
}
h.active = true
h.area = area
@@ -111,7 +110,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t u
}
}
func (q *pointerQueue) opHit(handlers *[]input.Key, pos f32.Point) {
func (q *pointerQueue) opHit(handlers *[]ui.Key, pos f32.Point) {
// Track whether we're passing through hits.
pass := true
idx := len(q.hitTree) - 1
@@ -154,7 +153,7 @@ func (a *areaNode) hit(p f32.Point) bool {
func (q *pointerQueue) init() {
if q.handlers == nil {
q.handlers = make(map[input.Key]*pointerHandler)
q.handlers = make(map[ui.Key]*pointerHandler)
}
}
@@ -176,7 +175,7 @@ func (q *pointerQueue) Frame(root *ui.Ops, events *handlerEvents) {
}
}
func (q *pointerQueue) dropHandler(k input.Key) {
func (q *pointerQueue) dropHandler(k ui.Key) {
for i := range q.pointers {
p := &q.pointers[i]
for i := len(p.handlers) - 1; i >= 0; i-- {
@@ -320,7 +319,7 @@ func decodePointerInputOp(d []byte, refs []interface{}) pointer.InputOp {
}
return pointer.InputOp{
Grab: d[1] != 0,
Key: refs[0].(input.Key),
Key: refs[0].(ui.Key),
}
}
+9 -10
View File
@@ -7,7 +7,6 @@ import (
"time"
"gioui.org/ui"
"gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
"gioui.org/ui/internal/ops"
"gioui.org/ui/key"
@@ -30,15 +29,15 @@ type Router struct {
wakeupTime time.Time
// ProfileOp summary.
profHandlers []input.Key
profHandlers []ui.Key
}
type handlerEvents struct {
handlers map[input.Key][]input.Event
handlers map[ui.Key][]ui.Event
updated bool
}
func (q *Router) Next(k input.Key) (input.Event, bool) {
func (q *Router) Next(k ui.Key) (ui.Event, bool) {
return q.handlers.Next(k)
}
@@ -57,7 +56,7 @@ func (q *Router) Frame(ops *ui.Ops) {
}
}
func (q *Router) Add(e input.Event) bool {
func (q *Router) Add(e ui.Event) bool {
switch e := e.(type) {
case pointer.Event:
q.pqueue.Push(e, &q.handlers)
@@ -103,17 +102,17 @@ func (q *Router) WakeupTime() (time.Time, bool) {
func (h *handlerEvents) init() {
if h.handlers == nil {
h.handlers = make(map[input.Key][]input.Event)
h.handlers = make(map[ui.Key][]ui.Event)
}
}
func (h *handlerEvents) Set(k input.Key, evts []input.Event) {
func (h *handlerEvents) Set(k ui.Key, evts []ui.Event) {
h.init()
h.handlers[k] = evts
h.updated = true
}
func (h *handlerEvents) Add(k input.Key, e input.Event) {
func (h *handlerEvents) Add(k ui.Key, e ui.Event) {
h.init()
h.handlers[k] = append(h.handlers[k], e)
h.updated = true
@@ -125,7 +124,7 @@ func (h *handlerEvents) Updated() bool {
return u
}
func (h *handlerEvents) Next(k input.Key) (input.Event, bool) {
func (h *handlerEvents) Next(k ui.Key) (ui.Event, bool) {
events := h.handlers[k]
if len(events) == 0 {
return nil, false
@@ -146,7 +145,7 @@ func decodeProfileOp(d []byte, refs []interface{}) system.ProfileOp {
panic("invalid op")
}
return system.ProfileOp{
Key: refs[0].(input.Key),
Key: refs[0].(ui.Key),
}
}
+15 -17
View File
@@ -10,8 +10,7 @@ import (
"gioui.org/ui"
"gioui.org/ui/app/internal/gpu"
iinput "gioui.org/ui/app/internal/input"
"gioui.org/ui/input"
"gioui.org/ui/app/internal/input"
"gioui.org/ui/system"
)
@@ -32,8 +31,8 @@ type Window struct {
drawStart time.Time
gpu *gpu.GPU
out chan input.Event
in chan input.Event
out chan ui.Event
in chan ui.Event
ack chan struct{}
invalidates chan struct{}
frames chan *ui.Ops
@@ -47,11 +46,10 @@ type Window struct {
queue Queue
}
// Queue is an input.Queue implementation that distributes
// system input events to the input handlers declared in the
// most recent call to Update.
// Queue is an ui.Queue implementation that distributes system events
// to the input handlers declared in the most recent call to Update.
type Queue struct {
q iinput.Router
q input.Router
}
// driverEvent is sent when a new native driver
@@ -71,7 +69,7 @@ var _ interface {
} = (*window)(nil)
// Pre-allocate the ack event to avoid garbage.
var ackEvent input.Event
var ackEvent ui.Event
// NewWindow creates a new window for a set of window
// options. The options are hints; the platform is free to
@@ -96,8 +94,8 @@ func NewWindow(options ...WindowOption) *Window {
}
w := &Window{
in: make(chan input.Event),
out: make(chan input.Event),
in: make(chan ui.Event),
out: make(chan ui.Event),
ack: make(chan struct{}),
invalidates: make(chan struct{}, 1),
frames: make(chan *ui.Ops),
@@ -107,7 +105,7 @@ func NewWindow(options ...WindowOption) *Window {
}
// Events returns the channel where events are delivered.
func (w *Window) Events() <-chan input.Event {
func (w *Window) Events() <-chan ui.Event {
return w.out
}
@@ -135,9 +133,9 @@ func (w *Window) draw(size image.Point, frame *ui.Ops) {
w.queue.q.Frame(frame)
now := time.Now()
switch w.queue.q.TextInputState() {
case iinput.TextInputOpen:
case input.TextInputOpen:
w.driver.showTextInput(true)
case iinput.TextInputClose:
case input.TextInputClose:
w.driver.showTextInput(false)
}
frameDur := now.Sub(w.lastFrame)
@@ -196,7 +194,7 @@ func (w *Window) setDriver(d *window) {
w.event(driverEvent{d})
}
func (w *Window) event(e input.Event) {
func (w *Window) event(e ui.Event) {
w.in <- e
<-w.ack
}
@@ -313,7 +311,7 @@ func (w *Window) run(opts *windowOptions) {
w.out <- e2
w.ack <- struct{}{}
return
case input.Event:
case ui.Event:
if w.queue.q.Add(e2) {
w.setNextFrame(time.Time{})
w.updateAnimation()
@@ -325,7 +323,7 @@ func (w *Window) run(opts *windowOptions) {
}
}
func (q *Queue) Next(k input.Key) (input.Event, bool) {
func (q *Queue) Next(k ui.Key) (ui.Event, bool) {
return q.q.Next(k)
}
+27
View File
@@ -80,5 +80,32 @@ size vary between platforms and displays.
To maintain a constant visual size across platforms and displays, always
use dps or sps to define user interfaces. Only use pixels for derived
values.
Events
The Queue interface is the protocol for receiving external events.
For example:
var queue ui.Queue = ...
for e, ok := queue.Next(h); ok; e, ok = queue.Next(h) {
switch e.(type) {
...
}
}
In general, handlers must be declared before events become
available. Other packages such as pointer and key provide
the means for declaring handlers for specific event types.
The following example declares a handler ready for key input:
import gioui.org/ui/key
ops := new(ui.Ops)
var h *Handler = ...
key.InputOp{Key: h}.Add(ops)
*/
package ui
+3 -4
View File
@@ -3,7 +3,7 @@
/*
Package gesture implements common pointer gestures.
Gestures accept low level pointer Events from an input
Gestures accept low level pointer Events from an event
Queue and detect higher level actions such as clicks
and scrolling.
*/
@@ -14,7 +14,6 @@ import (
"gioui.org/ui"
"gioui.org/ui/f32"
"gioui.org/ui/input"
"gioui.org/ui/internal/fling"
"gioui.org/ui/pointer"
)
@@ -106,7 +105,7 @@ func (c *Click) State() ClickState {
}
// Next returns the next click event, if any.
func (c *Click) Next(q input.Queue) (ClickEvent, bool) {
func (c *Click) Next(q ui.Queue) (ClickEvent, bool) {
for evt, ok := q.Next(c); ok; evt, ok = q.Next(c) {
e, ok := evt.(pointer.Event)
if !ok {
@@ -154,7 +153,7 @@ func (s *Scroll) Stop() {
// Scroll detects the scrolling distance from the available events and
// ongoing fling gestures.
func (s *Scroll) Scroll(cfg ui.Config, q input.Queue, axis Axis) int {
func (s *Scroll) Scroll(cfg ui.Config, q ui.Queue, axis Axis) int {
if s.axis != axis {
s.axis = axis
return 0
+20
View File
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Unlicense OR MIT
package ui
// Queue maps an event handler key to the events
// available to the handler.
type Queue interface {
// Next returns the next available event, or
// false if none are available.
Next(k Key) (Event, bool)
}
// Key is the stable identifier for an event handler.
// For a handler h, the key is typically &h.
type Key interface{}
// Event is the marker interface for events.
type Event interface {
ImplementsEvent()
}
-48
View File
@@ -1,48 +0,0 @@
// SPDX-License-Identifier: Unlicense OR MIT
/*
Package input exposes a unified interface for receiving input
events.
For example:
var queue input.Queue = ...
for e, ok := queue.Next(h); ok; e, ok = queue.Next(h) {
switch e.(type) {
...
}
}
In general, handlers must be declared before events become
available. Other packages such as pointer and key provide
the means for declaring handlers for specific input types.
The following example marks a handler ready for key input:
import gioui.org/ui/input
import gioui.org/ui/key
ops := new(ui.Ops)
var h *Handler = ...
key.InputOp{Key: h}.Add(ops)
*/
package input
// Queue maps an event handler key to the events
// available to the handler.
type Queue interface {
// Next returns the next available event, or
// false if none are available.
Next(k Key) (Event, bool)
}
// Key is the stable identifier for an event handler.
// For a handler h, the key is typically &h.
type Key interface{}
// Event is the marker interface for events.
type Event interface {
ImplementsEvent()
}
+5 -7
View File
@@ -1,18 +1,16 @@
// SPDX-License-Identifier: Unlicense OR MIT
/*
Package key implements key and text events and
operations.
Package key implements key and text events and operations.
The InputOp operations is used for declaring key
input handlers. Use the Queue interface from package
input to receive events.
The InputOp operations is used for declaring key input handlers. Use
an implementation of the Queue interface from package ui to receive
events.
*/
package key
import (
"gioui.org/ui"
"gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
)
@@ -21,7 +19,7 @@ import (
// focused key handler. Set the Focus flag to request
// the focus.
type InputOp struct {
Key input.Key
Key ui.Key
Focus bool
}
+2 -3
View File
@@ -6,7 +6,6 @@ import (
"image"
"gioui.org/ui"
"gioui.org/ui/input"
)
// Constraints represent a set of acceptable ranges for
@@ -38,7 +37,7 @@ type Alignment uint8
// space.
type Direction uint8
// Widget is a function scope for drawing, processing input and
// Widget is a function scope for drawing, processing events and
// computing dimensions for a user interface element.
type Widget func()
@@ -52,7 +51,7 @@ type Context struct {
Dimensions Dimensions
ui.Config
input.Queue
ui.Queue
*ui.Ops
}
+1 -2
View File
@@ -6,7 +6,6 @@ import (
"time"
"gioui.org/ui"
"gioui.org/ui/input"
"gioui.org/ui/layout"
)
@@ -150,6 +149,6 @@ func (config) Px(v ui.Value) int {
return int(v.V + .5)
}
func (queue) Next(k input.Key) (input.Event, bool) {
func (queue) Next(k ui.Key) (ui.Event, bool) {
return nil, false
}
+3 -4
View File
@@ -5,9 +5,8 @@ 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 Queue from package input to
receive events.
The InputOp operation is used to declare a handler ready for pointer
events. Use a ui.Queue to receive events.
Areas
@@ -72,7 +71,7 @@ drawer handle and the interface below should receive pointer events.
Disambiguation
When more than one handler matches a pointer event, the input queue
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
+2 -3
View File
@@ -9,7 +9,6 @@ import (
"gioui.org/ui"
"gioui.org/ui/f32"
"gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
)
@@ -64,7 +63,7 @@ type areaOp struct {
// InputOp declares an input handler ready for pointer
// events.
type InputOp struct {
Key input.Key
Key ui.Key
// Grab, if set, request that the handler get
// Grabbed priority.
Grab bool
@@ -86,7 +85,7 @@ type Priority uint8
// Source of an Event.
type Source uint8
// Must match input.areaKind
// Must match app/internal/input.areaKind
type areaKind uint8
const (
+1 -2
View File
@@ -6,14 +6,13 @@ package system
import (
"gioui.org/ui"
"gioui.org/ui/input"
"gioui.org/ui/internal/opconst"
)
// ProfileOp registers a handler for receiving
// ProfileEvents.
type ProfileOp struct {
Key input.Key
Key ui.Key
}
// ProfileEvent contain profile data from a single