2
0
mirror of synced 2025-02-22 14:28:14 +00:00

event: rename event.Foo to foo.Event.

Fixes golang/go#10444

Change-Id: Ie5a8ab8a09b1b1a4f7037da7cf945d39ab6a98fc
Reviewed-on: https://go-review.googlesource.com/12225
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Nigel Tao 2015-07-15 17:17:08 +10:00
parent a2120ea61f
commit e4c6af17e3
23 changed files with 397 additions and 293 deletions

View File

@ -8,6 +8,10 @@ package app
import (
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/event/paint"
"golang.org/x/mobile/event/touch"
"golang.org/x/mobile/gl"
_ "golang.org/x/mobile/internal/mobileinit"
)
@ -24,12 +28,12 @@ func Main(f func(App)) {
type App interface {
// Events returns the events channel. It carries events from the system to
// the app. The type of such events include:
// - event.Config
// - event.Draw
// - event.Lifecycle
// - event.Touch
// from the golang.org/x/mobile/events package. Other packages may define
// other event types that are carried on this channel.
// - config.Event
// - lifecycle.Event
// - paint.Event
// - touch.Event
// from the golang.org/x/mobile/event/etc packages. Other packages may
// define other event types that are carried on this channel.
Events() <-chan interface{}
// Send sends an event on the events channel. It does not block.
@ -40,7 +44,7 @@ type App interface {
}
var (
lifecycleStage = event.LifecycleStageDead
lifecycleStage = lifecycle.StageDead
pixelsPerPt = float32(1)
eventsOut = make(chan interface{})
@ -48,11 +52,11 @@ var (
endDraw = make(chan struct{}, 1)
)
func sendLifecycle(to event.LifecycleStage) {
func sendLifecycle(to lifecycle.Stage) {
if lifecycleStage == to {
return
}
eventsIn <- event.Lifecycle{
eventsIn <- lifecycle.Event{
From: lifecycleStage,
To: to,
}
@ -157,31 +161,31 @@ func pump(dst chan interface{}) (src chan interface{}) {
// Deprecated: call Main directly instead.
func Run(cb Callbacks) {
Main(func(a App) {
var c event.Config
var c config.Event
for e := range a.Events() {
switch e := event.Filter(e).(type) {
case event.Lifecycle:
switch e.Crosses(event.LifecycleStageVisible) {
case event.ChangeOn:
case lifecycle.Event:
switch e.Crosses(lifecycle.StageVisible) {
case lifecycle.CrossOn:
if cb.Start != nil {
cb.Start()
}
case event.ChangeOff:
case lifecycle.CrossOff:
if cb.Stop != nil {
cb.Stop()
}
}
case event.Config:
case config.Event:
if cb.Config != nil {
cb.Config(e, c)
}
c = e
case event.Draw:
case paint.Event:
if cb.Draw != nil {
cb.Draw(c)
}
a.EndDraw()
case event.Touch:
case touch.Event:
if cb.Touch != nil {
cb.Touch(e, c)
}
@ -231,13 +235,13 @@ type Callbacks struct {
//
// Drawing is done into a framebuffer, which is then swapped onto the
// screen when Draw returns. It is called 60 times a second.
Draw func(event.Config)
Draw func(config.Event)
// Touch is called by the app when a touch event occurs.
Touch func(event.Touch, event.Config)
Touch func(touch.Event, config.Event)
// Config is called by the app when configuration has changed.
Config func(new, old event.Config)
Config func(new, old config.Event)
}
// TODO: do this for all build targets, not just linux (x11 and Android)? If
@ -247,7 +251,7 @@ type Callbacks struct {
// KitKat). If only x11 needs this, should we move this to x11.go??
func registerGLViewportFilter() {
event.RegisterFilter(func(e interface{}) interface{} {
if e, ok := e.(event.Config); ok {
if e, ok := e.(config.Event); ok {
w := int(e.PixelsPerPt * float32(e.Width))
h := int(e.PixelsPerPt * float32(e.Height))
gl.Viewport(0, 0, w, h)

View File

@ -27,7 +27,10 @@ import (
"runtime"
"sync"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/event/paint"
"golang.org/x/mobile/event/touch"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
)
@ -75,7 +78,7 @@ func loop(ctx C.GLintptr) {
C.makeCurrentContext(ctx)
for range draw {
eventsIn <- event.Draw{}
eventsIn <- paint.Event{}
loop1:
for {
select {
@ -112,7 +115,7 @@ var windowHeight geom.Pt
func setGeom(ppp float32, width, height int) {
pixelsPerPt = ppp
windowHeight = geom.Pt(float32(height) / pixelsPerPt)
eventsIn <- event.Config{
eventsIn <- config.Event{
Width: geom.Pt(float32(width) / pixelsPerPt),
Height: windowHeight,
PixelsPerPt: pixelsPerPt,
@ -121,13 +124,13 @@ func setGeom(ppp float32, width, height int) {
var touchEvents struct {
sync.Mutex
pending []event.Touch
pending []touch.Event
}
func sendTouch(c event.Change, x, y float32) {
eventsIn <- event.Touch{
ID: 0,
Change: c,
func sendTouch(t touch.Type, x, y float32) {
eventsIn <- touch.Event{
Sequence: 0,
Type: t,
Loc: geom.Point{
X: geom.Pt(x / pixelsPerPt),
Y: windowHeight - geom.Pt(y/pixelsPerPt),
@ -136,22 +139,22 @@ func sendTouch(c event.Change, x, y float32) {
}
//export eventMouseDown
func eventMouseDown(x, y float32) { sendTouch(event.ChangeOn, x, y) }
func eventMouseDown(x, y float32) { sendTouch(touch.TypeStart, x, y) }
//export eventMouseDragged
func eventMouseDragged(x, y float32) { sendTouch(event.ChangeNone, x, y) }
func eventMouseDragged(x, y float32) { sendTouch(touch.TypeMove, x, y) }
//export eventMouseEnd
func eventMouseEnd(x, y float32) { sendTouch(event.ChangeOff, x, y) }
func eventMouseEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) }
//export lifecycleDead
func lifecycleDead() { sendLifecycle(event.LifecycleStageDead) }
func lifecycleDead() { sendLifecycle(lifecycle.StageDead) }
//export lifecycleAlive
func lifecycleAlive() { sendLifecycle(event.LifecycleStageAlive) }
func lifecycleAlive() { sendLifecycle(lifecycle.StageAlive) }
//export lifecycleVisible
func lifecycleVisible() { sendLifecycle(event.LifecycleStageVisible) }
func lifecycleVisible() { sendLifecycle(lifecycle.StageVisible) }
//export lifecycleFocused
func lifecycleFocused() { sendLifecycle(event.LifecycleStageFocused) }
func lifecycleFocused() { sendLifecycle(lifecycle.StageFocused) }

View File

@ -28,7 +28,10 @@ import (
"sync"
"unsafe"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/event/paint"
"golang.org/x/mobile/event/touch"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
)
@ -95,7 +98,7 @@ func setScreen(scale int) {
//export updateConfig
func updateConfig(width, height int) {
eventsIn <- event.Config{
eventsIn <- config.Event{
Width: geom.Pt(float32(screenScale*width) / pixelsPerPt),
Height: geom.Pt(float32(screenScale*height) / pixelsPerPt),
PixelsPerPt: pixelsPerPt,
@ -113,11 +116,11 @@ var touchIDs [11]uintptr
var touchEvents struct {
sync.Mutex
pending []event.Touch
pending []touch.Event
}
//export sendTouch
func sendTouch(touch, change uintptr, x, y float32) {
func sendTouch(touch, touchType uintptr, x, y float32) {
id := -1
for i, val := range touchIDs {
if val == touch {
@ -138,14 +141,14 @@ func sendTouch(touch, change uintptr, x, y float32) {
}
}
c := event.Change(change)
if c == event.ChangeOff {
t := touch.Type(touchType)
if t == touch.TypeEnd {
touchIDs[id] = 0
}
eventsIn <- event.Touch{
ID: event.TouchSequenceID(id),
Change: c,
eventsIn <- touch.Event{
Sequence: touch.Sequence(id),
Type: t,
Loc: geom.Point{
X: geom.Pt(x / pixelsPerPt),
Y: geom.Pt(y / pixelsPerPt),
@ -159,10 +162,10 @@ func drawgl(ctx uintptr) {
startedgl = true
C.setContext(unsafe.Pointer(ctx))
// TODO(crawshaw): not just on process start.
sendLifecycle(event.LifecycleStageFocused)
sendLifecycle(lifecycle.StageFocused)
}
eventsIn <- event.Draw{}
eventsIn <- paint.Event{}
for {
select {

View File

@ -65,9 +65,9 @@ struct utsname sysInfo;
drawgl((GoUintptr)self.context);
}
#define CHANGE_NONE 0 // event.ChangeNone
#define CHANGE_ON 1 // event.ChangeOn
#define CHANGE_OFF 2 // event.ChangeOff
#define TOUCH_TYPE_START 0 // touch.TypeStart
#define TOUCH_TYPE_MOVE 1 // touch.TypeMove
#define TOUCH_TYPE_END 2 // touch.TypeEnd
static void sendTouches(int change, NSSet* touches) {
CGFloat scale = [UIScreen mainScreen].scale;
@ -78,15 +78,15 @@ static void sendTouches(int change, NSSet* touches) {
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
sendTouches(CHANGE_ON, touches);
sendTouches(TOUCH_TYPE_START, touches);
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
sendTouches(CHANGE_NONE, touches);
sendTouches(TOUCH_TYPE_MOVE, touches);
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
sendTouches(CHANGE_OFF, touches);
sendTouches(TOUCH_TYPE_END, touches);
}
@end

View File

@ -42,15 +42,18 @@ function exits, the app exits.
"log"
"golang.org/x/mobile/app"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/event/paint"
)
func main() {
app.Main(func(a app.App) {
for e := range a.Events() {
switch e := event.Filter(e).(type) {
case event.Lifecycle:
case lifecycle.Event:
// ...
case event.Draw:
case paint.Event:
log.Print("Call OpenGL here.")
a.EndDraw()
}

View File

@ -84,7 +84,10 @@ import "C"
import (
"log"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/event/paint"
"golang.org/x/mobile/event/touch"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
)
@ -95,16 +98,16 @@ func windowDraw(w *C.ANativeWindow, queue *C.AInputQueue, donec chan struct{}) (
C.createEGLWindow(w)
// TODO: is this needed if we also have the "case <-windowRedrawNeeded:" below??
sendLifecycle(event.LifecycleStageFocused)
eventsIn <- event.Config{
sendLifecycle(lifecycle.StageFocused)
eventsIn <- config.Event{
Width: geom.Pt(float32(C.windowWidth) / pixelsPerPt),
Height: geom.Pt(float32(C.windowHeight) / pixelsPerPt),
PixelsPerPt: pixelsPerPt,
}
if firstWindowDraw {
firstWindowDraw = false
// TODO: be more principled about when to send a draw event.
eventsIn <- event.Draw{}
// TODO: be more principled about when to send a paint event.
eventsIn <- paint.Event{}
}
for {
@ -115,21 +118,21 @@ func windowDraw(w *C.ANativeWindow, queue *C.AInputQueue, donec chan struct{}) (
case <-windowRedrawNeeded:
// Re-query the width and height.
C.querySurfaceWidthAndHeight()
sendLifecycle(event.LifecycleStageFocused)
eventsIn <- event.Config{
sendLifecycle(lifecycle.StageFocused)
eventsIn <- config.Event{
Width: geom.Pt(float32(C.windowWidth) / pixelsPerPt),
Height: geom.Pt(float32(C.windowHeight) / pixelsPerPt),
PixelsPerPt: pixelsPerPt,
}
case <-windowDestroyed:
sendLifecycle(event.LifecycleStageAlive)
sendLifecycle(lifecycle.StageAlive)
return false
case <-gl.WorkAvailable:
gl.DoWork()
case <-endDraw:
// eglSwapBuffers blocks until vsync.
C.eglSwapBuffers(C.display, C.surface)
eventsIn <- event.Draw{}
eventsIn <- paint.Event{}
}
}
}
@ -152,22 +155,22 @@ func processEvent(e *C.AInputEvent) {
case C.AINPUT_EVENT_TYPE_MOTION:
// At most one of the events in this batch is an up or down event; get its index and change.
upDownIndex := C.size_t(C.AMotionEvent_getAction(e)&C.AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> C.AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT
upDownChange := event.ChangeNone
upDownType := touch.TypeMove
switch C.AMotionEvent_getAction(e) & C.AMOTION_EVENT_ACTION_MASK {
case C.AMOTION_EVENT_ACTION_DOWN, C.AMOTION_EVENT_ACTION_POINTER_DOWN:
upDownChange = event.ChangeOn
upDownType = touch.TypeStart
case C.AMOTION_EVENT_ACTION_UP, C.AMOTION_EVENT_ACTION_POINTER_UP:
upDownChange = event.ChangeOff
upDownType = touch.TypeEnd
}
for i, n := C.size_t(0), C.AMotionEvent_getPointerCount(e); i < n; i++ {
change := event.ChangeNone
t := touch.TypeMove
if i == upDownIndex {
change = upDownChange
t = upDownType
}
eventsIn <- event.Touch{
ID: event.TouchSequenceID(C.AMotionEvent_getPointerId(e, i)),
Change: change,
eventsIn <- touch.Event{
Sequence: touch.Sequence(C.AMotionEvent_getPointerId(e, i)),
Type: t,
Loc: geom.Point{
X: geom.Pt(float32(C.AMotionEvent_getX(e, i)) / pixelsPerPt),
Y: geom.Pt(float32(C.AMotionEvent_getY(e, i)) / pixelsPerPt),

View File

@ -27,7 +27,10 @@ import (
"runtime"
"time"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/event/paint"
"golang.org/x/mobile/event/touch"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
)
@ -41,7 +44,7 @@ func main(f func(App)) {
C.createWindow()
// TODO: send lifecycle events when e.g. the X11 window is iconified or moved off-screen.
sendLifecycle(event.LifecycleStageFocused)
sendLifecycle(lifecycle.StageFocused)
donec := make(chan struct{})
go func() {
@ -65,7 +68,7 @@ func main(f func(App)) {
tc = ticker.C
case <-tc:
tc = nil
eventsIn <- event.Draw{}
eventsIn <- paint.Event{}
}
C.processEvents()
}
@ -76,17 +79,17 @@ func onResize(w, h int) {
// TODO(nigeltao): don't assume 72 DPI. DisplayWidth and DisplayWidthMM
// is probably the best place to start looking.
pixelsPerPt = 1
eventsIn <- event.Config{
eventsIn <- config.Event{
Width: geom.Pt(w),
Height: geom.Pt(h),
PixelsPerPt: pixelsPerPt,
}
}
func sendTouch(c event.Change, x, y float32) {
eventsIn <- event.Touch{
ID: 0, // TODO: button??
Change: c,
func sendTouch(t touch.Type, x, y float32) {
eventsIn <- touch.Event{
Sequence: 0, // TODO: button??
Type: t,
Loc: geom.Point{
X: geom.Pt(x / pixelsPerPt),
Y: geom.Pt(y / pixelsPerPt),
@ -95,13 +98,13 @@ func sendTouch(c event.Change, x, y float32) {
}
//export onTouchStart
func onTouchStart(x, y float32) { sendTouch(event.ChangeOn, x, y) }
func onTouchStart(x, y float32) { sendTouch(touch.TypeStart, x, y) }
//export onTouchMove
func onTouchMove(x, y float32) { sendTouch(event.ChangeNone, x, y) }
func onTouchMove(x, y float32) { sendTouch(touch.TypeMove, x, y) }
//export onTouchEnd
func onTouchEnd(x, y float32) { sendTouch(event.ChangeOff, x, y) }
func onTouchEnd(x, y float32) { sendTouch(touch.TypeEnd, x, y) }
var stopped bool
@ -111,6 +114,6 @@ func onStop() {
return
}
stopped = true
sendLifecycle(event.LifecycleStageDead)
sendLifecycle(lifecycle.StageDead)
eventsIn <- stopPumping{}
}

27
event/config/config.go Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package config defines an event for the dimensions and physical resolution
// of the app's window.
//
// See the golang.org/x/mobile/event package for details on the event model.
package config // import "golang.org/x/mobile/event/config"
import (
"golang.org/x/mobile/geom"
)
// Event holds the dimensions and physical resolution of the app's window.
type Event struct {
// Width and Height are the window's dimensions.
Width, Height geom.Pt
// PixelsPerPt is the window's physical resolution. It is the number of
// pixels in a single geom.Pt, from the golang.org/x/mobile/geom package.
//
// There are a wide variety of pixel densities in existing phones and
// tablets, so apps should be written to expect various non-integer
// PixelsPerPt values. In general, work in geom.Pt.
PixelsPerPt float32
}

View File

@ -2,15 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package event defines mobile app events, such as user input events.
// Package event defines a model for mobile app events, such as user input
// events.
//
// An event is represented by the empty interface type interface{}. Any value
// can be an event. This package defines a number of commonly used events used
// by the golang.org/x/mobile/app package:
// - Config
// - Draw
// - Lifecycle
// - Touch
// can be an event. Packages under this directory define a number of commonly
// used events used by the golang.org/x/mobile/app package:
// - golang.org/x/mobile/event/config.Event
// - golang.org/x/mobile/event/lifecycle.Event
// - golang.org/x/mobile/event/paint.Event
// - golang.org/x/mobile/event/touch.Event
// Other packages may define their own events, and post them onto an app's
// event channel.
//
@ -28,19 +29,6 @@
// }
package event // import "golang.org/x/mobile/event"
// The best source on android input events is the NDK: include/android/input.h
//
// iOS event handling guide:
// https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS
// TODO: keyboard events.
import (
"fmt"
"golang.org/x/mobile/geom"
)
var filters []func(interface{}) interface{}
// Filter calls each registered filter function in sequence.
@ -60,148 +48,3 @@ func Filter(event interface{}) interface{} {
func RegisterFilter(f func(interface{}) interface{}) {
filters = append(filters, f)
}
// Change is a change in state, such as key or mouse button being up (off) or
// down (on). Some events with a Change-typed field can have no change in
// state, such as a key repeat or a mouse or touch drag.
type Change uint32
func (c Change) String() string {
switch c {
case ChangeOn:
return "on"
case ChangeOff:
return "off"
}
return "none"
}
const (
ChangeNone Change = 0
ChangeOn Change = 1
ChangeOff Change = 2
)
// Config holds the dimensions and physical resolution of the app's window.
type Config struct {
// Width and Height are the window's dimensions.
Width, Height geom.Pt
// PixelsPerPt is the window's physical resolution. It is the number of
// pixels in a single geom.Pt, from the golang.org/x/mobile/geom package.
//
// There are a wide variety of pixel densities in existing phones and
// tablets, so apps should be written to expect various non-integer
// PixelsPerPt values. In general, work in geom.Pt.
PixelsPerPt float32
}
// Draw indicates that the app is ready to draw the next frame of the GUI. A
// frame is completed by calling the App's EndDraw method.
type Draw struct{}
// Lifecycle is a lifecycle change from an old stage to a new stage.
type Lifecycle struct {
From, To LifecycleStage
}
// Crosses returns whether the transition from From to To crosses the stage s:
// - It returns ChangeOn if it does, and the Lifecycle change is positive.
// - It returns ChangeOff if it does, and the Lifecycle change is negative.
// - Otherwise, it returns ChangeNone.
// See the documentation for LifecycleStage for more discussion of positive and
// negative changes, and crosses.
func (l Lifecycle) Crosses(s LifecycleStage) Change {
switch {
case l.From < s && l.To >= s:
return ChangeOn
case l.From >= s && l.To < s:
return ChangeOff
}
return ChangeNone
}
// LifecycleStage is a stage in the app's lifecycle. The values are ordered, so
// that a lifecycle change from stage From to stage To implicitly crosses every
// stage in the range (min, max], exclusive on the low end and inclusive on the
// high end, where min is the minimum of From and To, and max is the maximum.
//
// The documentation for individual stages talk about positive and negative
// crosses. A positive Lifecycle change is one where its From stage is less
// than its To stage. Similarly, a negative Lifecycle change is one where From
// is greater than To. Thus, a positive Lifecycle change crosses every stage in
// the range (From, To] in increasing order, and a negative Lifecycle change
// crosses every stage in the range (To, From] in decreasing order.
type LifecycleStage uint32
// TODO: how does iOS map to these stages? What do cross-platform mobile
// abstractions do?
const (
// LifecycleStageDead is the zero stage. No Lifecycle change crosses this
// stage, but:
// - A positive change from this stage is the very first lifecycle change.
// - A negative change to this stage is the very last lifecycle change.
LifecycleStageDead LifecycleStage = iota
// LifecycleStageAlive means that the app is alive.
// - A positive cross means that the app has been created.
// - A negative cross means that the app is being destroyed.
// Each cross, either from or to LifecycleStageDead, will occur only once.
// On Android, these correspond to onCreate and onDestroy.
LifecycleStageAlive
// LifecycleStageVisible means that the app window is visible.
// - A positive cross means that the app window has become visible.
// - A negative cross means that the app window has become invisible.
// On Android, these correspond to onStart and onStop.
// On Desktop, an app window can become invisible if e.g. it is minimized,
// unmapped, or not on a visible workspace.
LifecycleStageVisible
// LifecycleStageFocused means that the app window has the focus.
// - A positive cross means that the app window has gained the focus.
// - A negative cross means that the app window has lost the focus.
// On Android, these correspond to onResume and onFreeze.
LifecycleStageFocused
)
func (l LifecycleStage) String() string {
switch l {
case LifecycleStageDead:
return "LifecycleStageDead"
case LifecycleStageAlive:
return "LifecycleStageAlive"
case LifecycleStageVisible:
return "LifecycleStageVisible"
case LifecycleStageFocused:
return "LifecycleStageFocused"
default:
return fmt.Sprintf("LifecycleStageInvalid:%d", l)
}
}
// On Android, Touch is an AInputEvent with AINPUT_EVENT_TYPE_MOTION:
// - ChangeOn is an AMOTION_EVENT_ACTION_DOWN.
// - ChangeNone is an AMOTION_EVENT_ACTION_MOVE.
// - ChangeOff is an AMOTION_EVENT_ACTION_UP.
//
// On iOS, Touch is the UIEvent delivered to a UIView:
// - ChangeOn is a call to touchesBegan.
// - ChangeNone is a call to touchesMoved.
// - ChangeOff is a call to touchesEnded.
// Touch is a user touch event.
//
// The same ID is shared by all events in a sequence. A sequence starts with a
// single ChangeOn (a touch start), is followed by zero or more ChangeNones
// (touch moves), and ends with a single ChangeOff (a touch end). An ID
// distinguishes concurrent sequences but is subsequently reused.
type Touch struct {
ID TouchSequenceID
Change Change
Loc geom.Point
}
// TouchSequenceID identifies a sequence of Touch events.
type TouchSequenceID int64

View File

@ -0,0 +1,124 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package lifecycle defines an event for an app's lifecycle.
//
// The app lifecycle consists of moving back and forth between an ordered
// sequence of stages. For example, being at a stage greater than or equal to
// StageVisible means that the app is visible on the screen.
//
// A lifecycle event is a change from one stage to another, which crosses every
// intermediate stage. For example, changing from StageAlive to StageFocused
// implicitly crosses StageVisible.
//
// Crosses can be in a positive or negative direction. A positive crossing of
// StageFocused means that the app has gained the focus. A negative crossing
// means it has lost the focus.
//
// See the golang.org/x/mobile/event package for details on the event model.
package lifecycle // import "golang.org/x/mobile/event/lifecycle"
import (
"fmt"
)
// Cross is whether a lifecycle stage was crossed.
type Cross uint32
func (c Cross) String() string {
switch c {
case CrossOn:
return "on"
case CrossOff:
return "off"
}
return "none"
}
const (
CrossNone Cross = 0
CrossOn Cross = 1
CrossOff Cross = 2
)
// Event is a lifecycle change from an old stage to a new stage.
type Event struct {
From, To Stage
}
// Crosses returns whether the transition from From to To crosses the stage s:
// - It returns CrossOn if it does, and the lifecycle change is positive.
// - It returns CrossOff if it does, and the lifecycle change is negative.
// - Otherwise, it returns CrossNone.
// See the documentation for Stage for more discussion of positive and negative
// crosses.
func (e Event) Crosses(s Stage) Cross {
switch {
case e.From < s && e.To >= s:
return CrossOn
case e.From >= s && e.To < s:
return CrossOff
}
return CrossNone
}
// Stage is a stage in the app's lifecycle. The values are ordered, so that a
// lifecycle change from stage From to stage To implicitly crosses every stage
// in the range (min, max], exclusive on the low end and inclusive on the high
// end, where min is the minimum of From and To, and max is the maximum.
//
// The documentation for individual stages talk about positive and negative
// crosses. A positive lifecycle change is one where its From stage is less
// than its To stage. Similarly, a negative lifecycle change is one where From
// is greater than To. Thus, a positive lifecycle change crosses every stage in
// the range (From, To] in increasing order, and a negative lifecycle change
// crosses every stage in the range (To, From] in decreasing order.
type Stage uint32
// TODO: how does iOS map to these stages? What do cross-platform mobile
// abstractions do?
const (
// StageDead is the zero stage. No lifecycle change crosses this stage,
// but:
// - A positive change from this stage is the very first lifecycle change.
// - A negative change to this stage is the very last lifecycle change.
StageDead Stage = iota
// StageAlive means that the app is alive.
// - A positive cross means that the app has been created.
// - A negative cross means that the app is being destroyed.
// Each cross, either from or to StageDead, will occur only once.
// On Android, these correspond to onCreate and onDestroy.
StageAlive
// StageVisible means that the app window is visible.
// - A positive cross means that the app window has become visible.
// - A negative cross means that the app window has become invisible.
// On Android, these correspond to onStart and onStop.
// On Desktop, an app window can become invisible if e.g. it is minimized,
// unmapped, or not on a visible workspace.
StageVisible
// StageFocused means that the app window has the focus.
// - A positive cross means that the app window has gained the focus.
// - A negative cross means that the app window has lost the focus.
// On Android, these correspond to onResume and onFreeze.
StageFocused
)
func (s Stage) String() string {
switch s {
case StageDead:
return "StageDead"
case StageAlive:
return "StageAlive"
case StageVisible:
return "StageVisible"
case StageFocused:
return "StageFocused"
default:
return fmt.Sprintf("lifecycle.Stage(%d)", s)
}
}

17
event/paint/paint.go Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package paint defines an event for the app being ready to paint.
//
// See the golang.org/x/mobile/event package for details on the event model.
package paint // import "golang.org/x/mobile/event/paint"
// TODO: rename App.EndDraw to App.EndPaint.
//
// This is "package paint", not "package draw", to avoid conflicting with the
// standard library's "image/draw" package.
// Event indicates that the app is ready to paint the next frame of the GUI. A
// frame is completed by calling the App's EndDraw method.
type Event struct{}

71
event/touch/touch.go Normal file
View File

@ -0,0 +1,71 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package touch defines an event for touch input.
//
// See the golang.org/x/mobile/event package for details on the event model.
package touch // import "golang.org/x/mobile/event/touch"
// The best source on android input events is the NDK: include/android/input.h
//
// iOS event handling guide:
// https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS
import (
"fmt"
"golang.org/x/mobile/geom"
)
// Event is a touch event.
//
// The same Sequence is shared by all events in a sequence. A sequence starts
// with a single TypeStart, is followed by zero or more TypeMoves, and ends
// with a single TypeEnd. A Sequence distinguishes concurrent sequences but its
// value is subsequently reused.
type Event struct {
Sequence Sequence
Type Type
Loc geom.Point
}
// Sequence identifies a sequence of touch events.
type Sequence int64
// Type describes the type of a touch event.
type Type byte
const (
// TypeStart is a user first touching the device.
//
// On Android, this is a AMOTION_EVENT_ACTION_DOWN.
// On iOS, this is a call to touchesBegan.
TypeStart Type = iota
// TypeMove is a user dragging across the device.
//
// A TypeMove is delivered between a TypeStart and TypeEnd.
//
// On Android, this is a AMOTION_EVENT_ACTION_MOVE.
// On iOS, this is a call to touchesMoved.
TypeMove
// TypeEnd is a user no longer touching the device.
//
// On Android, this is a AMOTION_EVENT_ACTION_UP.
// On iOS, this is a call to touchesEnded.
TypeEnd
)
func (t Type) String() string {
switch t {
case TypeStart:
return "start"
case TypeMove:
return "move"
case TypeEnd:
return "end"
}
return fmt.Sprintf("touch.Type(%d)", t)
}

View File

@ -39,7 +39,7 @@ import (
"golang.org/x/mobile/app"
"golang.org/x/mobile/asset"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/app/debug"
"golang.org/x/mobile/exp/audio"
"golang.org/x/mobile/exp/f32"
@ -65,13 +65,13 @@ var (
func main() {
app.Run(app.Callbacks{
Start: start,
Stop: stop,
Draw: draw,
Start: onStart,
Stop: onStop,
Draw: onDraw,
})
}
func start() {
func onStart() {
rc, err := asset.Open("boing.wav")
if err != nil {
log.Fatal(err)
@ -82,11 +82,11 @@ func start() {
}
}
func stop() {
func onStop() {
player.Close()
}
func draw(c event.Config) {
func onDraw(c config.Event) {
if scene == nil {
loadScene(c)
}
@ -104,7 +104,7 @@ func newNode() *sprite.Node {
return n
}
func loadScene(c event.Config) {
func loadScene(c config.Event) {
gopher := loadGopher()
scene = &sprite.Node{}
eng.Register(scene)

View File

@ -31,7 +31,8 @@ import (
"log"
"golang.org/x/mobile/app"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/event/touch"
"golang.org/x/mobile/exp/app/debug"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/exp/gl/glutil"
@ -52,15 +53,15 @@ var (
func main() {
app.Run(app.Callbacks{
Start: start,
Stop: stop,
Draw: draw,
Touch: touch,
Config: config,
Start: onStart,
Stop: onStop,
Draw: onDraw,
Touch: onTouch,
Config: onConfig,
})
}
func start() {
func onStart() {
var err error
program, err = glutil.CreateProgram(vertexShader, fragmentShader)
if err != nil {
@ -80,20 +81,20 @@ func start() {
// Can this be an event.Register call now??
}
func stop() {
func onStop() {
gl.DeleteProgram(program)
gl.DeleteBuffer(buf)
}
func config(new, old event.Config) {
func onConfig(new, old config.Event) {
touchLoc = geom.Point{new.Width / 2, new.Height / 2}
}
func touch(t event.Touch, c event.Config) {
func onTouch(t touch.Event, c config.Event) {
touchLoc = t.Loc
}
func draw(c event.Config) {
func onDraw(c config.Event) {
gl.ClearColor(1, 0, 0, 1)
gl.Clear(gl.COLOR_BUFFER_BIT)

View File

@ -41,7 +41,7 @@ import (
"net/http"
"golang.org/x/mobile/app"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/app/debug"
"golang.org/x/mobile/gl"
)
@ -51,7 +51,7 @@ func main() {
go checkNetwork()
app.Run(app.Callbacks{
Draw: draw,
Draw: onDraw,
})
}
@ -70,7 +70,7 @@ func checkNetwork() {
ok = true
}
func draw(c event.Config) {
func onDraw(c config.Event) {
select {
case <-determined:
if ok {

View File

@ -36,7 +36,7 @@ import (
"golang.org/x/mobile/app"
"golang.org/x/mobile/asset"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/app/debug"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/exp/sprite"
@ -53,11 +53,11 @@ var (
func main() {
app.Run(app.Callbacks{
Draw: draw,
Draw: onDraw,
})
}
func draw(c event.Config) {
func onDraw(c config.Event) {
if scene == nil {
loadScene()
}

View File

@ -12,7 +12,7 @@ import (
"sync"
"time"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/gl/glutil"
"golang.org/x/mobile/geom"
)
@ -21,12 +21,12 @@ var lastDraw = time.Now()
var fps struct {
mu sync.Mutex
c event.Config
c config.Event
m *glutil.Image
}
// DrawFPS draws the per second framerate in the bottom-left of the screen.
func DrawFPS(c event.Config) {
func DrawFPS(c config.Event) {
const imgW, imgH = 7*(fontWidth+1) + 1, fontHeight + 2
fps.mu.Lock()

View File

@ -14,6 +14,8 @@ import (
"sync"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/event/lifecycle"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
@ -32,11 +34,11 @@ var glimage struct {
func init() {
event.RegisterFilter(func(e interface{}) interface{} {
if e, ok := e.(event.Lifecycle); ok {
switch e.Crosses(event.LifecycleStageVisible) {
case event.ChangeOn:
if e, ok := e.(lifecycle.Event); ok {
switch e.Crosses(lifecycle.StageVisible) {
case lifecycle.CrossOn:
start()
case event.ChangeOff:
case lifecycle.CrossOff:
stop()
}
}
@ -223,7 +225,7 @@ func (img *Image) Delete() {
// Draw draws the srcBounds part of the image onto a parallelogram, defined by
// three of its corners, in the current GL framebuffer.
func (img *Image) Draw(c event.Config, topLeft, topRight, bottomLeft geom.Point, srcBounds image.Rectangle) {
func (img *Image) Draw(c config.Event, topLeft, topRight, bottomLeft geom.Point, srcBounds image.Rectangle) {
// TODO(crawshaw): Adjust viewport for the top bar on android?
gl.UseProgram(glimage.program)
tex := texmap.get(*img.key)

View File

@ -18,7 +18,7 @@ import (
"runtime"
"testing"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/geom"
"golang.org/x/mobile/gl"
)
@ -65,7 +65,7 @@ func TestImage(t *testing.T) {
ptW = geom.Pt(50)
ptH = geom.Pt(50)
)
cfg := event.Config{
cfg := config.Event{
Width: ptW,
Height: ptH,
PixelsPerPt: float32(pixW) / float32(ptW),

View File

@ -12,7 +12,7 @@ import (
"image"
"image/draw"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/exp/gl/glutil"
"golang.org/x/mobile/exp/sprite"
@ -91,7 +91,7 @@ func (e *engine) SetTransform(n *sprite.Node, m f32.Affine) {
e.nodes[n.EngineFields.Index].relTransform = m
}
func (e *engine) Render(scene *sprite.Node, t clock.Time, cfg event.Config) {
func (e *engine) Render(scene *sprite.Node, t clock.Time, cfg config.Event) {
e.absTransforms = append(e.absTransforms[:0], f32.Affine{
{1, 0, 0},
{0, 1, 0},
@ -99,7 +99,7 @@ func (e *engine) Render(scene *sprite.Node, t clock.Time, cfg event.Config) {
e.render(scene, t, cfg)
}
func (e *engine) render(n *sprite.Node, t clock.Time, cfg event.Config) {
func (e *engine) render(n *sprite.Node, t clock.Time, cfg config.Event) {
if n.EngineFields.Index == 0 {
panic("glsprite: sprite.Node not registered")
}

View File

@ -14,7 +14,7 @@ import (
"os"
"testing"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/geom"
)
@ -38,7 +38,7 @@ func TestAffine(t *testing.T) {
ptW = geom.Pt(50)
ptH = geom.Pt(50)
)
cfg := event.Config{
cfg := config.Event{
Width: ptW,
Height: ptH,
PixelsPerPt: float32(pixW) / float32(ptW),

View File

@ -13,7 +13,7 @@ import (
"image"
"image/draw"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/exp/sprite"
"golang.org/x/mobile/exp/sprite/clock"
@ -92,7 +92,7 @@ func (e *engine) SetTransform(n *sprite.Node, m f32.Affine) {
e.nodes[n.EngineFields.Index].relTransform = m
}
func (e *engine) Render(scene *sprite.Node, t clock.Time, cfg event.Config) {
func (e *engine) Render(scene *sprite.Node, t clock.Time, cfg config.Event) {
// Affine transforms are done in geom.Pt. When finally drawing
// the geom.Pt onto an image.Image we need to convert to system
// pixels. We scale by cfg.PixelsPerPt to do this.

View File

@ -28,7 +28,7 @@ import (
"image"
"image/draw"
"golang.org/x/mobile/event"
"golang.org/x/mobile/event/config"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/exp/sprite/clock"
)
@ -60,7 +60,7 @@ type Engine interface {
// Render renders the scene arranged at the given time, for the given
// window configuration (dimensions and resolution).
Render(scene *Node, t clock.Time, c event.Config)
Render(scene *Node, t clock.Time, c config.Event)
}
// A Node is a renderable element and forms a tree of Nodes.