io/event: move event types from package ui to its own package

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-09-30 15:13:25 +02:00
parent 7a259e68f7
commit e7a97bf176
16 changed files with 107 additions and 94 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ For example, to display a blank but otherwise functional window:
Event queue Event queue
A Window's Queue method returns an ui.Queue implementation that distributes A Window's Queue method returns an event.Queue implementation that distributes
incoming events to the event handlers declared in the latest call to Update. 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. See the gioui.org/ui package for more information about event handlers.
+9 -8
View File
@@ -5,6 +5,7 @@ package input
import ( import (
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/internal/ops" "gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -12,8 +13,8 @@ import (
type TextInputState uint8 type TextInputState uint8
type keyQueue struct { type keyQueue struct {
focus ui.Key focus event.Key
handlers map[ui.Key]*keyHandler handlers map[event.Key]*keyHandler
reader ops.Reader reader ops.Reader
state TextInputState state TextInputState
} }
@@ -45,7 +46,7 @@ func (q *keyQueue) InputState() TextInputState {
func (q *keyQueue) Frame(root *ui.Ops, events *handlerEvents) { func (q *keyQueue) Frame(root *ui.Ops, events *handlerEvents) {
if q.handlers == nil { if q.handlers == nil {
q.handlers = make(map[ui.Key]*keyHandler) q.handlers = make(map[event.Key]*keyHandler)
} }
for _, h := range q.handlers { for _, h := range q.handlers {
h.active = false h.active = false
@@ -82,14 +83,14 @@ func (q *keyQueue) Frame(root *ui.Ops, events *handlerEvents) {
} }
} }
func (q *keyQueue) Push(e ui.Event, events *handlerEvents) { func (q *keyQueue) Push(e event.Event, events *handlerEvents) {
if q.focus != nil { if q.focus != nil {
events.Add(q.focus, e) events.Add(q.focus, e)
} }
} }
func (q *keyQueue) resolveFocus(events *handlerEvents) (ui.Key, listenerPriority, bool) { func (q *keyQueue) resolveFocus(events *handlerEvents) (event.Key, listenerPriority, bool) {
var k ui.Key var k event.Key
var pri listenerPriority var pri listenerPriority
var hide bool var hide bool
loop: loop:
@@ -115,7 +116,7 @@ loop:
h = new(keyHandler) h = new(keyHandler)
q.handlers[op.Key] = h q.handlers[op.Key] = h
// Reset the handler on (each) first appearance. // Reset the handler on (each) first appearance.
events.Set(op.Key, []ui.Event{key.FocusEvent{Focus: false}}) events.Set(op.Key, []event.Event{key.FocusEvent{Focus: false}})
} }
h.active = true h.active = true
case opconst.TypeHideInput: case opconst.TypeHideInput:
@@ -144,6 +145,6 @@ func decodeKeyInputOp(d []byte, refs []interface{}) key.InputOp {
} }
return key.InputOp{ return key.InputOp{
Focus: d[1] != 0, Focus: d[1] != 0,
Key: refs[0].(ui.Key), Key: refs[0].(event.Key),
} }
} }
+10 -9
View File
@@ -9,6 +9,7 @@ import (
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/internal/ops" "gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -16,10 +17,10 @@ import (
type pointerQueue struct { type pointerQueue struct {
hitTree []hitNode hitTree []hitNode
areas []areaNode areas []areaNode
handlers map[ui.Key]*pointerHandler handlers map[event.Key]*pointerHandler
pointers []pointerInfo pointers []pointerInfo
reader ops.Reader reader ops.Reader
scratch []ui.Key scratch []event.Key
} }
type hitNode struct { type hitNode struct {
@@ -29,13 +30,13 @@ type hitNode struct {
pass bool pass bool
// For handler nodes. // For handler nodes.
key ui.Key key event.Key
} }
type pointerInfo struct { type pointerInfo struct {
id pointer.ID id pointer.ID
pressed bool pressed bool
handlers []ui.Key handlers []event.Key
} }
type pointerHandler struct { type pointerHandler struct {
@@ -100,7 +101,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t u
if !ok { if !ok {
h = new(pointerHandler) h = new(pointerHandler)
q.handlers[op.Key] = h q.handlers[op.Key] = h
events.Set(op.Key, []ui.Event{pointer.Event{Type: pointer.Cancel}}) events.Set(op.Key, []event.Event{pointer.Event{Type: pointer.Cancel}})
} }
h.active = true h.active = true
h.area = area h.area = area
@@ -110,7 +111,7 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t u
} }
} }
func (q *pointerQueue) opHit(handlers *[]ui.Key, pos f32.Point) { func (q *pointerQueue) opHit(handlers *[]event.Key, pos f32.Point) {
// Track whether we're passing through hits. // Track whether we're passing through hits.
pass := true pass := true
idx := len(q.hitTree) - 1 idx := len(q.hitTree) - 1
@@ -153,7 +154,7 @@ func (a *areaNode) hit(p f32.Point) bool {
func (q *pointerQueue) init() { func (q *pointerQueue) init() {
if q.handlers == nil { if q.handlers == nil {
q.handlers = make(map[ui.Key]*pointerHandler) q.handlers = make(map[event.Key]*pointerHandler)
} }
} }
@@ -175,7 +176,7 @@ func (q *pointerQueue) Frame(root *ui.Ops, events *handlerEvents) {
} }
} }
func (q *pointerQueue) dropHandler(k ui.Key) { func (q *pointerQueue) dropHandler(k event.Key) {
for i := range q.pointers { for i := range q.pointers {
p := &q.pointers[i] p := &q.pointers[i]
for i := len(p.handlers) - 1; i >= 0; i-- { for i := len(p.handlers) - 1; i >= 0; i-- {
@@ -319,7 +320,7 @@ func decodePointerInputOp(d []byte, refs []interface{}) pointer.InputOp {
} }
return pointer.InputOp{ return pointer.InputOp{
Grab: d[1] != 0, Grab: d[1] != 0,
Key: refs[0].(ui.Key), Key: refs[0].(event.Key),
} }
} }
+10 -9
View File
@@ -8,6 +8,7 @@ import (
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/internal/ops" "gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/io/profile" "gioui.org/io/profile"
@@ -38,15 +39,15 @@ type Router struct {
wakeupTime time.Time wakeupTime time.Time
// ProfileOp summary. // ProfileOp summary.
profHandlers []ui.Key profHandlers []event.Key
} }
type handlerEvents struct { type handlerEvents struct {
handlers map[ui.Key][]ui.Event handlers map[event.Key][]event.Event
hadEvents bool hadEvents bool
} }
func (q *Router) Events(k ui.Key) []ui.Event { func (q *Router) Events(k event.Key) []event.Event {
events := q.handlers.Events(k) events := q.handlers.Events(k)
q.deliveredEvents = q.deliveredEvents || len(events) > 0 q.deliveredEvents = q.deliveredEvents || len(events) > 0
return events return events
@@ -68,7 +69,7 @@ func (q *Router) Frame(ops *ui.Ops) {
} }
} }
func (q *Router) Add(e ui.Event) bool { func (q *Router) Add(e event.Event) bool {
switch e := e.(type) { switch e := e.(type) {
case pointer.Event: case pointer.Event:
q.pqueue.Push(e, &q.handlers) q.pqueue.Push(e, &q.handlers)
@@ -114,17 +115,17 @@ func (q *Router) WakeupTime() (time.Time, bool) {
func (h *handlerEvents) init() { func (h *handlerEvents) init() {
if h.handlers == nil { if h.handlers == nil {
h.handlers = make(map[ui.Key][]ui.Event) h.handlers = make(map[event.Key][]event.Event)
} }
} }
func (h *handlerEvents) Set(k ui.Key, evts []ui.Event) { func (h *handlerEvents) Set(k event.Key, evts []event.Event) {
h.init() h.init()
h.handlers[k] = evts h.handlers[k] = evts
h.hadEvents = true h.hadEvents = true
} }
func (h *handlerEvents) Add(k ui.Key, e ui.Event) { func (h *handlerEvents) Add(k event.Key, e event.Event) {
h.init() h.init()
h.handlers[k] = append(h.handlers[k], e) h.handlers[k] = append(h.handlers[k], e)
h.hadEvents = true h.hadEvents = true
@@ -136,7 +137,7 @@ func (h *handlerEvents) HadEvents() bool {
return u return u
} }
func (h *handlerEvents) Events(k ui.Key) []ui.Event { func (h *handlerEvents) Events(k event.Key) []event.Event {
if events, ok := h.handlers[k]; ok { if events, ok := h.handlers[k]; ok {
h.handlers[k] = h.handlers[k][:0] h.handlers[k] = h.handlers[k][:0]
return events return events
@@ -155,7 +156,7 @@ func decodeProfileOp(d []byte, refs []interface{}) profile.Op {
panic("invalid op") panic("invalid op")
} }
return profile.Op{ return profile.Op{
Key: refs[0].(ui.Key), Key: refs[0].(event.Key),
} }
} }
+11 -10
View File
@@ -10,6 +10,7 @@ import (
"gioui.org/app/internal/gpu" "gioui.org/app/internal/gpu"
"gioui.org/app/internal/input" "gioui.org/app/internal/input"
"gioui.org/io/event"
"gioui.org/io/profile" "gioui.org/io/profile"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -31,8 +32,8 @@ type Window struct {
drawStart time.Time drawStart time.Time
gpu *gpu.GPU gpu *gpu.GPU
out chan ui.Event out chan event.Event
in chan ui.Event in chan event.Event
ack chan struct{} ack chan struct{}
invalidates chan struct{} invalidates chan struct{}
frames chan *ui.Ops frames chan *ui.Ops
@@ -46,7 +47,7 @@ type Window struct {
queue Queue queue Queue
} }
// Queue is an ui.Queue implementation that distributes system events // Queue is an event.Queue implementation that distributes system events
// to the input handlers declared in the most recent call to Update. // to the input handlers declared in the most recent call to Update.
type Queue struct { type Queue struct {
q input.Router q input.Router
@@ -69,7 +70,7 @@ var _ interface {
} = (*window)(nil) } = (*window)(nil)
// Pre-allocate the ack event to avoid garbage. // Pre-allocate the ack event to avoid garbage.
var ackEvent ui.Event var ackEvent event.Event
// NewWindow creates a new window for a set of window // NewWindow creates a new window for a set of window
// options. The options are hints; the platform is free to // options. The options are hints; the platform is free to
@@ -94,8 +95,8 @@ func NewWindow(options ...WindowOption) *Window {
} }
w := &Window{ w := &Window{
in: make(chan ui.Event), in: make(chan event.Event),
out: make(chan ui.Event), out: make(chan event.Event),
ack: make(chan struct{}), ack: make(chan struct{}),
invalidates: make(chan struct{}, 1), invalidates: make(chan struct{}, 1),
frames: make(chan *ui.Ops), frames: make(chan *ui.Ops),
@@ -105,7 +106,7 @@ func NewWindow(options ...WindowOption) *Window {
} }
// Events returns the channel where events are delivered. // Events returns the channel where events are delivered.
func (w *Window) Events() <-chan ui.Event { func (w *Window) Events() <-chan event.Event {
return w.out return w.out
} }
@@ -194,7 +195,7 @@ func (w *Window) setDriver(d *window) {
w.event(driverEvent{d}) w.event(driverEvent{d})
} }
func (w *Window) event(e ui.Event) { func (w *Window) event(e event.Event) {
w.in <- e w.in <- e
<-w.ack <-w.ack
} }
@@ -311,7 +312,7 @@ func (w *Window) run(opts *windowOptions) {
w.out <- e2 w.out <- e2
w.ack <- struct{}{} w.ack <- struct{}{}
return return
case ui.Event: case event.Event:
if w.queue.q.Add(e2) { if w.queue.q.Add(e2) {
w.setNextFrame(time.Time{}) w.setNextFrame(time.Time{})
w.updateAnimation() w.updateAnimation()
@@ -323,7 +324,7 @@ func (w *Window) run(opts *windowOptions) {
} }
} }
func (q *Queue) Events(k ui.Key) []ui.Event { func (q *Queue) Events(k event.Key) []event.Event {
return q.q.Events(k) return q.q.Events(k)
} }
+3 -2
View File
@@ -14,6 +14,7 @@ import (
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/fling" "gioui.org/internal/fling"
"gioui.org/io/event"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -105,7 +106,7 @@ func (c *Click) State() ClickState {
} }
// Events returns the next click event, if any. // Events returns the next click event, if any.
func (c *Click) Events(q ui.Queue) []ClickEvent { func (c *Click) Events(q event.Queue) []ClickEvent {
var events []ClickEvent var events []ClickEvent
for _, evt := range q.Events(c) { for _, evt := range q.Events(c) {
e, ok := evt.(pointer.Event) e, ok := evt.(pointer.Event)
@@ -154,7 +155,7 @@ func (s *Scroll) Stop() {
// Scroll detects the scrolling distance from the available events and // Scroll detects the scrolling distance from the available events and
// ongoing fling gestures. // ongoing fling gestures.
func (s *Scroll) Scroll(cfg ui.Config, q ui.Queue, axis Axis) int { func (s *Scroll) Scroll(cfg ui.Config, q event.Queue, axis Axis) int {
if s.axis != axis { if s.axis != axis {
s.axis = axis s.axis = axis
return 0 return 0
+48
View File
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Unlicense OR MIT
/*
Package event contains the types for event handling.
The Queue interface is the protocol for receiving external events.
For example:
var queue event.Queue = ...
for _, e := range queue.Events(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/io/key
ops := new(ui.Ops)
var h *Handler = ...
key.InputOp{Key: h}.Add(ops)
*/
package event
// Queue maps an event handler key to the events
// available to the handler.
type Queue interface {
// Events returns the available events for a
// Key.
Events(k Key) []Event
}
// 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()
}
+3 -2
View File
@@ -10,8 +10,9 @@ events.
package key package key
import ( import (
"gioui.org/ui"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/io/event"
"gioui.org/ui"
) )
// InputOp declares a handler ready for key events. // InputOp declares a handler ready for key events.
@@ -19,7 +20,7 @@ import (
// focused key handler. Set the Focus flag to request // focused key handler. Set the Focus flag to request
// the focus. // the focus.
type InputOp struct { type InputOp struct {
Key ui.Key Key event.Key
Focus bool Focus bool
} }
+1 -1
View File
@@ -6,7 +6,7 @@ A pointer is either a mouse controlled cursor or a touch
object such as a finger. object such as a finger.
The InputOp operation is used to declare a handler ready for pointer The InputOp operation is used to declare a handler ready for pointer
events. Use a ui.Queue to receive events. events. Use an event.Queue to receive events.
Areas Areas
+3 -2
View File
@@ -7,9 +7,10 @@ import (
"image" "image"
"time" "time"
"gioui.org/ui"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/io/event"
"gioui.org/ui"
) )
// Event is a pointer event. // Event is a pointer event.
@@ -63,7 +64,7 @@ type areaOp struct {
// InputOp declares an input handler ready for pointer // InputOp declares an input handler ready for pointer
// events. // events.
type InputOp struct { type InputOp struct {
Key ui.Key Key event.Key
// Grab, if set, request that the handler get // Grab, if set, request that the handler get
// Grabbed priority. // Grabbed priority.
Grab bool Grab bool
+2 -1
View File
@@ -6,13 +6,14 @@ package profile
import ( import (
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/io/event"
"gioui.org/ui" "gioui.org/ui"
) )
// Op registers a handler for receiving // Op registers a handler for receiving
// Events. // Events.
type Op struct { type Op struct {
Key ui.Key Key event.Key
} }
// Event contains profile data from a single // Event contains profile data from a single
+2 -1
View File
@@ -5,6 +5,7 @@ package layout
import ( import (
"image" "image"
"gioui.org/io/event"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -51,7 +52,7 @@ type Context struct {
Dimensions Dimensions Dimensions Dimensions
ui.Config ui.Config
ui.Queue event.Queue
*ui.Ops *ui.Ops
} }
+2 -1
View File
@@ -5,6 +5,7 @@ import (
"image" "image"
"time" "time"
"gioui.org/io/event"
"gioui.org/layout" "gioui.org/layout"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -149,6 +150,6 @@ func (config) Px(v ui.Value) int {
return int(v.V + .5) return int(v.V + .5)
} }
func (queue) Events(k ui.Key) []ui.Event { func (queue) Events(k event.Key) []event.Event {
return nil return nil
} }
+2 -1
View File
@@ -10,6 +10,7 @@ import (
"unicode/utf8" "unicode/utf8"
"gioui.org/gesture" "gioui.org/gesture"
"gioui.org/io/event"
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/layout" "gioui.org/layout"
@@ -64,7 +65,7 @@ type Editor struct {
clicker gesture.Click clicker gesture.Click
// events is the list of events not yet processed. // events is the list of events not yet processed.
events []ui.Event events []event.Event
} }
type EditorEvent interface { type EditorEvent interface {
-26
View File
@@ -81,31 +81,5 @@ To maintain a constant visual size across platforms and displays, always
use dps or sps to define user interfaces. Only use pixels for derived use dps or sps to define user interfaces. Only use pixels for derived
values. values.
Events
The Queue interface is the protocol for receiving external events.
For example:
var queue ui.Queue = ...
for _, e := range queue.Events(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/io/key
ops := new(ui.Ops)
var h *Handler = ...
key.InputOp{Key: h}.Add(ops)
*/ */
package ui package ui
-20
View File
@@ -1,20 +0,0 @@
// SPDX-License-Identifier: Unlicense OR MIT
package ui
// Queue maps an event handler key to the events
// available to the handler.
type Queue interface {
// Events returns the available events for a
// Key.
Events(k Key) []Event
}
// 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()
}