app,io/system: extract system events to separate package

Package app is the only package that depends on native libraries and
Cgo. Minimize its API, thereby minimizing Gio clients' dependency on
it. In the future, a headless, testing or remote "Window" should be
very easy to replace app.Window.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-10-14 14:55:42 +02:00
parent 641656b307
commit 36d1cd90f2
10 changed files with 251 additions and 214 deletions
+4 -86
View File
@@ -4,66 +4,14 @@ package app
import (
"errors"
"image"
"math"
"os"
"strings"
"time"
"gioui.org/op"
"gioui.org/unit"
)
// A FrameEvent asks for a new frame in the form of a list of
// operations.
type FrameEvent struct {
Config Config
// Size is the dimensions of the window.
Size image.Point
// Insets is the insets to apply.
Insets Insets
// Frame replaces the window's frame with the new
// frame.
Frame func(frame *op.Ops)
// Whether this draw is system generated and needs a complete
// frame before proceeding.
sync bool
}
// DestroyEvent is the last event sent through
// a window event channel.
type DestroyEvent struct {
// Err is nil for normal window closures. If a
// window is prematurely closed, Err is the cause.
Err error
}
// Insets is the space taken up by
// system decoration such as translucent
// system bars and software keyboards.
type Insets struct {
Top, Bottom, Left, Right unit.Value
}
// A StageEvent is generated whenever the stage of a
// Window changes.
type StageEvent struct {
Stage Stage
}
// CommandEvent is a system event.
type CommandEvent struct {
Type CommandType
// Suppress the default action of the command.
Cancel bool
}
// Stage of a Window.
type Stage uint8
// CommandType is the type of a CommandEvent.
type CommandType uint8
type windowRendezvous struct {
in chan windowAndOptions
out chan windowAndOptions
@@ -75,20 +23,6 @@ type windowAndOptions struct {
opts *windowOptions
}
const (
// StagePaused is the Stage for inactive Windows.
// Inactive Windows don't receive FrameEvents.
StagePaused Stage = iota
// StateRunning is for active Windows.
StageRunning
)
const (
// CommandBack is the command for a back action
// such as the Android back button.
CommandBack CommandType = iota
)
const (
inchPrDp = 1.0 / 160
mmPrDp = 25.4 / 160
@@ -109,17 +43,6 @@ const (
// Set with the go linker flag -X.
var extraArgs string
func (l Stage) String() string {
switch l {
case StagePaused:
return "StagePaused"
case StageRunning:
return "StageRunning"
default:
panic("unexpected Stage value")
}
}
func init() {
if extraArgs != "" {
args := strings.Split(extraArgs, "|")
@@ -149,8 +72,8 @@ func Main() {
main()
}
// Config implements the layout.Config interface.
type Config struct {
// config implements the system.Config interface.
type config struct {
// Device pixels per dp.
pxPerDp float32
// Device pixels per sp.
@@ -158,11 +81,11 @@ type Config struct {
now time.Time
}
func (c *Config) Now() time.Time {
func (c *config) Now() time.Time {
return c.now
}
func (c *Config) Px(v unit.Value) int {
func (c *config) Px(v unit.Value) int {
var r float32
switch v.U {
case unit.UnitPx:
@@ -202,8 +125,3 @@ func newWindowRendezvous() *windowRendezvous {
}()
return wr
}
func (_ FrameEvent) ImplementsEvent() {}
func (_ StageEvent) ImplementsEvent() {}
func (_ *CommandEvent) ImplementsEvent() {}
func (_ DestroyEvent) ImplementsEvent() {}
+26 -23
View File
@@ -27,6 +27,7 @@ import (
"gioui.org/f32"
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/io/system"
"gioui.org/unit"
)
@@ -37,9 +38,9 @@ type window struct {
dpi int
fontScale float32
insets Insets
insets system.Insets
stage Stage
stage system.Stage
started bool
mu sync.Mutex
@@ -112,7 +113,7 @@ func onCreateView(env *C.JNIEnv, class C.jclass, view C.jobject) C.jlong {
handle := C.jlong(view)
views[handle] = w
w.loadConfig(env, class)
w.setStage(StagePaused)
w.setStage(system.StagePaused)
return handle
}
@@ -129,7 +130,7 @@ func onDestroyView(env *C.JNIEnv, class C.jclass, handle C.jlong) {
func onStopView(env *C.JNIEnv, class C.jclass, handle C.jlong) {
w := views[handle]
w.started = false
w.setStage(StagePaused)
w.setStage(system.StagePaused)
}
//export onStartView
@@ -147,7 +148,7 @@ func onSurfaceDestroyed(env *C.JNIEnv, class C.jclass, handle C.jlong) {
w.mu.Lock()
w.win = nil
w.mu.Unlock()
w.setStage(StagePaused)
w.setStage(system.StagePaused)
}
//export onSurfaceChanged
@@ -171,7 +172,7 @@ func onLowMemory() {
func onConfigurationChanged(env *C.JNIEnv, class C.jclass, view C.jlong) {
w := views[view]
w.loadConfig(env, class)
if w.stage >= StageRunning {
if w.stage >= system.StageRunning {
w.draw(true)
}
}
@@ -182,7 +183,7 @@ func onFrameCallback(env *C.JNIEnv, class C.jclass, view C.jlong, nanos C.jlong)
if !exist {
return
}
if w.stage < StageRunning {
if w.stage < system.StageRunning {
return
}
w.mu.Lock()
@@ -199,7 +200,7 @@ func onFrameCallback(env *C.JNIEnv, class C.jclass, view C.jlong, nanos C.jlong)
//export onBack
func onBack(env *C.JNIEnv, class C.jclass, view C.jlong) C.jboolean {
w := views[view]
ev := &CommandEvent{Type: CommandBack}
ev := &system.CommandEvent{Type: system.CommandBack}
w.event(ev)
if ev.Cancel {
return C.JNI_TRUE
@@ -216,13 +217,13 @@ func onFocusChange(env *C.JNIEnv, class C.jclass, view C.jlong, focus C.jboolean
//export onWindowInsets
func onWindowInsets(env *C.JNIEnv, class C.jclass, view C.jlong, top, right, bottom, left C.jint) {
w := views[view]
w.insets = Insets{
w.insets = system.Insets{
Top: unit.Px(float32(top)),
Right: unit.Px(float32(right)),
Bottom: unit.Px(float32(bottom)),
Left: unit.Px(float32(left)),
}
if w.stage >= StageRunning {
if w.stage >= system.StageRunning {
w.draw(true)
}
}
@@ -233,16 +234,16 @@ func (w *window) setVisible() {
if width == 0 || height == 0 {
return
}
w.setStage(StageRunning)
w.setStage(system.StageRunning)
w.draw(true)
}
func (w *window) setStage(stage Stage) {
func (w *window) setStage(stage system.Stage) {
if stage == w.stage {
return
}
w.stage = stage
w.event(StageEvent{stage})
w.event(system.StageEvent{stage})
}
func (w *window) nativeWindow(visID int) (*C.ANativeWindow, int, int) {
@@ -296,16 +297,18 @@ func (w *window) draw(sync bool) {
return
}
ppdp := float32(w.dpi) * inchPrDp
w.event(FrameEvent{
Size: image.Point{
X: int(width),
Y: int(height),
},
Insets: w.insets,
Config: Config{
pxPerDp: ppdp,
pxPerSp: w.fontScale * ppdp,
now: time.Now(),
w.event(frameEvent{
FrameEvent: system.FrameEvent{
Size: image.Point{
X: int(width),
Y: int(height),
},
Insets: w.insets,
Config: &config{
pxPerDp: ppdp,
pxPerSp: w.fontScale * ppdp,
now: time.Now(),
},
},
sync: sync,
})
+22 -19
View File
@@ -25,6 +25,7 @@ import (
"gioui.org/f32"
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/io/system"
"gioui.org/unit"
)
@@ -61,7 +62,7 @@ func onCreate(view C.CFTypeRef) {
w.layer = C.CFTypeRef(layerFactory())
C.gio_addLayerToView(view, w.layer)
views[view] = w
w.w.event(StageEvent{StagePaused})
w.w.event(system.StageEvent{Stage: system.StagePaused})
}
//export onDraw
@@ -74,27 +75,29 @@ func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, to
w.visible.Store(true)
C.gio_updateView(view, w.layer)
if !wasVisible {
w.w.event(StageEvent{StageRunning})
w.w.event(system.StageEvent{Stage: system.StageRunning})
}
isSync := false
if sync != 0 {
isSync = true
}
w.w.event(FrameEvent{
Size: image.Point{
X: int(width + .5),
Y: int(height + .5),
},
Insets: Insets{
Top: unit.Px(float32(top)),
Right: unit.Px(float32(right)),
Bottom: unit.Px(float32(bottom)),
Left: unit.Px(float32(left)),
},
Config: Config{
pxPerDp: float32(dpi) * inchPrDp,
pxPerSp: float32(sdpi) * inchPrDp,
now: time.Now(),
w.w.event(frameEvent{
FrameEvent: system.FrameEvent{
Size: image.Point{
X: int(width + .5),
Y: int(height + .5),
},
Insets: system.Insets{
Top: unit.Px(float32(top)),
Right: unit.Px(float32(right)),
Bottom: unit.Px(float32(bottom)),
Left: unit.Px(float32(left)),
},
Config: &config{
pxPerDp: float32(dpi) * inchPrDp,
pxPerSp: float32(sdpi) * inchPrDp,
now: time.Now(),
},
},
sync: isSync,
})
@@ -104,14 +107,14 @@ func onDraw(view C.CFTypeRef, dpi, sdpi, width, height C.CGFloat, sync C.int, to
func onStop(view C.CFTypeRef) {
w := views[view]
w.visible.Store(false)
w.w.event(StageEvent{StagePaused})
w.w.event(system.StageEvent{Stage: system.StagePaused})
}
//export onDestroy
func onDestroy(view C.CFTypeRef) {
w := views[view]
delete(views, view)
w.w.event(DestroyEvent{})
w.w.event(system.DestroyEvent{})
C.gio_removeLayer(w.layer)
C.CFRelease(w.layer)
w.layer = 0
+13 -10
View File
@@ -11,6 +11,7 @@ import (
"gioui.org/f32"
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/io/system"
)
type window struct {
@@ -53,7 +54,7 @@ func createWindow(win *Window, opts *windowOptions) error {
go func() {
w.w.setDriver(w)
w.focus()
w.w.event(StageEvent{StageRunning})
w.w.event(system.StageEvent{Stage: system.StageRunning})
w.draw(true)
select {}
w.cleanup()
@@ -338,24 +339,26 @@ func (w *window) showTextInput(show bool) {
func (w *window) draw(sync bool) {
width, height, scale, cfg := w.config()
if cfg == (Config{}) {
if cfg == (config{}) {
return
}
w.mu.Lock()
w.scale = float32(scale)
w.mu.Unlock()
cfg.now = time.Now()
w.w.event(FrameEvent{
Size: image.Point{
X: width,
Y: height,
w.w.event(frameEvent{
FrameEvent: system.FrameEvent{
Size: image.Point{
X: width,
Y: height,
},
Config: &cfg,
},
Config: cfg,
sync: sync,
sync: sync,
})
}
func (w *window) config() (int, int, float32, Config) {
func (w *window) config() (int, int, float32, config) {
rect := w.cnv.Call("getBoundingClientRect")
width, height := rect.Get("width").Float(), rect.Get("height").Float()
scale := w.window.Get("devicePixelRatio").Float()
@@ -368,7 +371,7 @@ func (w *window) config() (int, int, float32, Config) {
w.cnv.Set("height", ih)
}
const ppdp = 96 * inchPrDp * monitorScale
return iw, ih, float32(scale), Config{
return iw, ih, float32(scale), config{
pxPerDp: ppdp * float32(scale),
pxPerSp: ppdp * float32(scale),
}
+26 -22
View File
@@ -4,13 +4,6 @@
package app
/*
#cgo CFLAGS: -DGL_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c
#include <AppKit/AppKit.h>
#include "os_macos.h"
*/
import "C"
import (
"errors"
"image"
@@ -22,8 +15,17 @@ import (
"gioui.org/f32"
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/io/system"
)
/*
#cgo CFLAGS: -DGL_SILENCE_DEPRECATION -Werror -Wno-deprecated-declarations -fmodules -fobjc-arc -x objective-c
#include <AppKit/AppKit.h>
#include "os_macos.h"
*/
import "C"
func init() {
// Darwin requires that UI operations happen on the main thread only.
runtime.LockOSThread()
@@ -32,7 +34,7 @@ func init() {
type window struct {
view C.CFTypeRef
w *Window
stage Stage
stage system.Stage
ppdp float32
scale float32
}
@@ -89,12 +91,12 @@ func (w *window) setAnimating(anim bool) {
C.gio_setAnimating(w.view, animb)
}
func (w *window) setStage(stage Stage) {
func (w *window) setStage(stage system.Stage) {
if stage == w.stage {
return
}
w.stage = stage
w.w.event(StageEvent{stage})
w.w.event(system.StageEvent{Stage: stage})
}
// Use a top level func for onFrameCallback to avoid
@@ -197,14 +199,16 @@ func (w *window) draw(sync bool) {
height := int(hf*w.scale + .5)
cfg := configFor(w.ppdp, w.scale)
cfg.now = time.Now()
w.setStage(StageRunning)
w.w.event(FrameEvent{
Size: image.Point{
X: width,
Y: height,
w.setStage(system.StageRunning)
w.w.event(frameEvent{
FrameEvent: system.FrameEvent{
Size: image.Point{
X: width,
Y: height,
},
Config: &cfg,
},
Config: cfg,
sync: sync,
sync: sync,
})
}
@@ -217,9 +221,9 @@ func getPixelsPerDp(scale float32) float32 {
return ppdp / scale
}
func configFor(ppdp, scale float32) Config {
func configFor(ppdp, scale float32) config {
ppdp = ppdp * scale
return Config{
return config{
pxPerDp: ppdp,
pxPerSp: ppdp,
}
@@ -230,7 +234,7 @@ func gio_onTerminate(view C.CFTypeRef) {
viewDo(view, func(views viewMap, view C.CFTypeRef) {
w := views[view]
delete(views, view)
w.w.event(DestroyEvent{})
w.w.event(system.DestroyEvent{})
})
}
@@ -238,7 +242,7 @@ func gio_onTerminate(view C.CFTypeRef) {
func gio_onHide(view C.CFTypeRef) {
viewDo(view, func(views viewMap, view C.CFTypeRef) {
w := views[view]
w.setStage(StagePaused)
w.setStage(system.StagePaused)
})
}
@@ -246,7 +250,7 @@ func gio_onHide(view C.CFTypeRef) {
func gio_onShow(view C.CFTypeRef) {
viewDo(view, func(views viewMap, view C.CFTypeRef) {
w := views[view]
w.setStage(StageRunning)
w.setStage(system.StageRunning)
})
}
+19 -16
View File
@@ -21,6 +21,7 @@ import (
"gioui.org/internal/fling"
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/io/system"
syscall "golang.org/x/sys/unix"
)
@@ -116,7 +117,7 @@ type window struct {
dir f32.Point
}
stage Stage
stage system.Stage
dead bool
pendingErr error
lastFrameCallback *C.struct_wl_callback
@@ -302,7 +303,7 @@ func gio_onXdgSurfaceConfigure(data unsafe.Pointer, wmSurf *C.struct_xdg_surface
w.serial = serial
w.needAck = true
w.mu.Unlock()
w.setStage(StageRunning)
w.setStage(system.StageRunning)
w.draw(true)
}
@@ -772,7 +773,7 @@ loop:
break
}
if w.dead {
w.w.event(DestroyEvent{Err: w.pendingErr})
w.w.event(system.DestroyEvent{Err: w.pendingErr})
break
}
// Clear poll events.
@@ -979,16 +980,16 @@ func (w *window) updateOutputs() {
}
w.mu.Unlock()
if !found {
w.setStage(StagePaused)
w.setStage(system.StagePaused)
} else {
w.setStage(StageRunning)
w.setStage(system.StageRunning)
w.draw(true)
}
}
func (w *window) config() (int, int, Config) {
func (w *window) config() (int, int, config) {
width, height := w.width*w.scale, w.height*w.scale
return width, height, Config{
return width, height, config{
pxPerDp: w.ppdp * float32(w.scale),
pxPerSp: w.ppsp * float32(w.scale),
}
@@ -1015,7 +1016,7 @@ func (w *window) draw(sync bool) {
return
}
width, height, cfg := w.config()
if cfg == (Config{}) {
if cfg == (config{}) {
return
}
if animating && w.lastFrameCallback == nil {
@@ -1024,22 +1025,24 @@ func (w *window) draw(sync bool) {
C.gio_wl_callback_add_listener(w.lastFrameCallback, unsafe.Pointer(w.surf))
}
cfg.now = time.Now()
w.w.event(FrameEvent{
Size: image.Point{
X: width,
Y: height,
w.w.event(frameEvent{
FrameEvent: system.FrameEvent{
Size: image.Point{
X: width,
Y: height,
},
Config: &cfg,
},
Config: cfg,
sync: sync,
sync: sync,
})
}
func (w *window) setStage(s Stage) {
func (w *window) setStage(s system.Stage) {
if s == w.stage {
return
}
w.stage = s
w.w.event(StageEvent{s})
w.w.event(system.StageEvent{s})
}
func (w *window) display() *C.struct_wl_display {
+17 -14
View File
@@ -17,6 +17,7 @@ import (
"gioui.org/f32"
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/io/system"
)
var winMap = make(map[syscall.Handle]*window)
@@ -60,7 +61,7 @@ type window struct {
w *Window
width int
height int
stage Stage
stage system.Stage
dead bool
mu sync.Mutex
@@ -183,7 +184,7 @@ func createWindow(window *Window, opts *windowOptions) error {
defer delete(winMap, w.hwnd)
w.w = window
w.w.setDriver(w)
defer w.w.event(DestroyEvent{})
defer w.w.event(system.DestroyEvent{})
showWindow(w.hwnd, _SW_SHOWDEFAULT)
setForegroundWindow(w.hwnd)
setFocus(w.hwnd)
@@ -326,9 +327,9 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
case _WM_SIZE:
switch wParam {
case _SIZE_MINIMIZED:
w.setStage(StagePaused)
w.setStage(system.StagePaused)
case _SIZE_MAXIMIZED, _SIZE_RESTORED:
w.setStage(StageRunning)
w.setStage(system.StageRunning)
w.draw(true)
}
}
@@ -395,9 +396,9 @@ func (w *window) postRedraw() {
}
}
func (w *window) setStage(s Stage) {
func (w *window) setStage(s system.Stage) {
w.stage = s
w.w.event(StageEvent{s})
w.w.event(system.StageEvent{Stage: s})
}
func (w *window) draw(sync bool) {
@@ -407,13 +408,15 @@ func (w *window) draw(sync bool) {
w.height = int(r.bottom - r.top)
cfg := configForDC(w.hdc)
cfg.now = time.Now()
w.w.event(FrameEvent{
Size: image.Point{
X: w.width,
Y: w.height,
w.w.event(frameEvent{
FrameEvent: system.FrameEvent{
Size: image.Point{
X: w.width,
Y: w.height,
},
Config: &cfg,
},
Config: cfg,
sync: sync,
sync: sync,
})
}
@@ -474,14 +477,14 @@ func convertKeyCode(code uintptr) (rune, bool) {
return r, true
}
func configForDC(hdc syscall.Handle) Config {
func configForDC(hdc syscall.Handle) config {
dpi := getDeviceCaps(hdc, _LOGPIXELSX)
ppdp := float32(dpi) * inchPrDp * monitorScale
// Force a minimum density to keep text legible and to handle bogus output geometry.
if ppdp < minDensity {
ppdp = minDensity
}
return Config{
return config{
pxPerDp: ppdp,
pxPerSp: ppdp,
}
+19 -12
View File
@@ -12,6 +12,7 @@ import (
"gioui.org/app/internal/input"
"gioui.org/io/event"
"gioui.org/io/profile"
"gioui.org/io/system"
"gioui.org/op"
"gioui.org/unit"
)
@@ -24,6 +25,12 @@ type windowOptions struct {
Title string
}
type frameEvent struct {
system.FrameEvent
sync bool
}
// Window represents an operating system window.
type Window struct {
driver *window
@@ -37,7 +44,7 @@ type Window struct {
invalidates chan struct{}
frames chan *op.Ops
stage Stage
stage system.Stage
animating bool
hasNextFrame bool
nextFrame time.Time
@@ -170,7 +177,7 @@ func (w *Window) updateAnimation() {
w.delayedDraw.Stop()
w.delayedDraw = nil
}
if w.stage >= StageRunning && w.hasNextFrame {
if w.stage >= system.StageRunning && w.hasNextFrame {
if dt := time.Until(w.nextFrame); dt <= 0 {
animate = true
} else {
@@ -210,10 +217,10 @@ func (w *Window) waitAck() {
func (w *Window) destroy(err error) {
// Ack the current event.
w.ack <- struct{}{}
w.out <- DestroyEvent{err}
w.out <- system.DestroyEvent{Err: err}
for e := range w.in {
w.ack <- struct{}{}
if _, ok := e.(DestroyEvent); ok {
if _, ok := e.(system.DestroyEvent); ok {
return
}
}
@@ -223,7 +230,7 @@ func (w *Window) run(opts *windowOptions) {
defer close(w.in)
defer close(w.out)
if err := createWindow(w, opts); err != nil {
w.out <- DestroyEvent{err}
w.out <- system.DestroyEvent{Err: err}
return
}
for {
@@ -240,9 +247,9 @@ func (w *Window) run(opts *windowOptions) {
w.updateAnimation()
case e := <-w.in:
switch e2 := e.(type) {
case StageEvent:
case system.StageEvent:
if w.gpu != nil {
if e2.Stage < StageRunning {
if e2.Stage < system.StageRunning {
w.gpu.Release()
w.gpu = nil
} else {
@@ -253,18 +260,18 @@ func (w *Window) run(opts *windowOptions) {
w.updateAnimation()
w.out <- e
w.waitAck()
case FrameEvent:
case frameEvent:
if e2.Size == (image.Point{}) {
panic(errors.New("internal error: zero-sized Draw"))
}
if w.stage < StageRunning {
if w.stage < system.StageRunning {
// No drawing if not visible.
break
}
w.drawStart = time.Now()
w.hasNextFrame = false
e2.Frame = w.update
w.out <- e2
w.out <- e2.FrameEvent
var frame *op.Ops
// Wait for either a frame or the ack event,
// which meant that the client didn't draw.
@@ -303,12 +310,12 @@ func (w *Window) run(opts *windowOptions) {
return
}
}
case *CommandEvent:
case *system.CommandEvent:
w.out <- e
w.waitAck()
case driverEvent:
w.driver = e2.driver
case DestroyEvent:
case system.DestroyEvent:
w.out <- e2
w.ack <- struct{}{}
return
+102
View File
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: Unlicense OR MIT
// Package system contains events usually handled at the top-level
// program level.
package system
import (
"image"
"time"
"gioui.org/op"
"gioui.org/unit"
)
// A FrameEvent asks for a new frame in the form of a list of
// operations.
type FrameEvent struct {
Config Config
// Size is the dimensions of the window.
Size image.Point
// Insets is the insets to apply.
Insets Insets
// Frame replaces the window's frame with the new
// frame.
Frame func(frame *op.Ops)
// Whether this draw is system generated and needs a complete
// frame before proceeding.
sync bool
}
// Config define the essential properties of
// the environment.
type Config interface {
// Now returns the current animation time.
Now() time.Time
unit.Converter
}
// DestroyEvent is the last event sent through
// a window event channel.
type DestroyEvent struct {
// Err is nil for normal window closures. If a
// window is prematurely closed, Err is the cause.
Err error
}
// Insets is the space taken up by
// system decoration such as translucent
// system bars and software keyboards.
type Insets struct {
Top, Bottom, Left, Right unit.Value
}
// A StageEvent is generated whenever the stage of a
// Window changes.
type StageEvent struct {
Stage Stage
}
// CommandEvent is a system event.
type CommandEvent struct {
Type CommandType
// Suppress the default action of the command.
Cancel bool
}
// Stage of a Window.
type Stage uint8
// CommandType is the type of a CommandEvent.
type CommandType uint8
const (
// StagePaused is the Stage for inactive Windows.
// Inactive Windows don't receive FrameEvents.
StagePaused Stage = iota
// StateRunning is for active Windows.
StageRunning
)
const (
// CommandBack is the command for a back action
// such as the Android back button.
CommandBack CommandType = iota
)
func (l Stage) String() string {
switch l {
case StagePaused:
return "StagePaused"
case StageRunning:
return "StageRunning"
default:
panic("unexpected Stage value")
}
}
func (_ FrameEvent) ImplementsEvent() {}
func (_ StageEvent) ImplementsEvent() {}
func (_ *CommandEvent) ImplementsEvent() {}
func (_ DestroyEvent) ImplementsEvent() {}
+3 -12
View File
@@ -4,9 +4,9 @@ package layout
import (
"image"
"time"
"gioui.org/io/event"
"gioui.org/io/system"
"gioui.org/op"
"gioui.org/unit"
)
@@ -53,20 +53,11 @@ type Context struct {
// operation.
Dimensions Dimensions
Config
system.Config
event.Queue
*op.Ops
}
// Config define the essential properties of
// the environment.
type Config interface {
// Now returns the current animation time.
Now() time.Time
unit.Converter
}
const (
Start Alignment = iota
End
@@ -104,7 +95,7 @@ func (s *Context) Layout(cs Constraints, w Widget) Dimensions {
// Reset the context. The constraints' minimum and maximum values are
// set to the size.
func (c *Context) Reset(cfg Config, size image.Point) {
func (c *Context) Reset(cfg system.Config, size image.Point) {
c.Constraints = RigidConstraints(size)
c.Dimensions = Dimensions{}
c.Config = cfg