diff --git a/app/app.go b/app/app.go index f08b3ef1..7d8ab085 100644 --- a/app/app.go +++ b/app/app.go @@ -3,9 +3,16 @@ package app import ( + "image" "os" "path/filepath" "strings" + "time" + + "gioui.org/io/event" + "gioui.org/layout" + "gioui.org/op" + "gioui.org/unit" ) // extraArgs contains extra arguments to append to @@ -30,13 +37,68 @@ var extraArgs string // is not supported. Default value of ID is filepath.Base(os.Args[0]). var ID = "" -func init() { - if extraArgs != "" { - args := strings.Split(extraArgs, "|") - os.Args = append(os.Args, args...) +// A FrameEvent requests a new frame in the form of a list of +// operations that describes what to display and how to handle +// input. +type FrameEvent struct { + // Now is the current animation. Use Now instead of time.Now to + // synchronize animation and to avoid the time.Now call overhead. + Now time.Time + // Metric converts device independent dp and sp to device pixels. + Metric unit.Metric + // Size is the dimensions of the window. + Size image.Point + // Insets represent the space occupied by system decorations and controls. + Insets Insets + // Frame completes the FrameEvent by drawing the graphical operations + // from ops into the window. + Frame func(frame *op.Ops) + // Queue supplies the events for event handlers. + Queue event.Queue +} + +// Insets is the space taken up by +// system decoration such as translucent +// system bars and software keyboards. +type Insets struct { + // Values are in pixels. + Top, Bottom, Left, Right unit.Dp +} + +// NewContext is a shorthand for +// +// layout.Context{ +// Ops: ops, +// Now: e.Now, +// Queue: e.Queue, +// Config: e.Config, +// Constraints: layout.Exact(e.Size), +// } +// +// NewContext calls ops.Reset and adjusts ops for e.Insets. +func NewContext(ops *op.Ops, e FrameEvent) layout.Context { + ops.Reset() + + size := e.Size + + if e.Insets != (Insets{}) { + left := e.Metric.Dp(e.Insets.Left) + top := e.Metric.Dp(e.Insets.Top) + op.Offset(image.Point{ + X: left, + Y: top, + }).Add(ops) + + size.X -= left + e.Metric.Dp(e.Insets.Right) + size.Y -= top + e.Metric.Dp(e.Insets.Bottom) } - if ID == "" { - ID = filepath.Base(os.Args[0]) + + return layout.Context{ + Ops: ops, + Now: e.Now, + Queue: e.Queue, + Metric: e.Metric, + Constraints: layout.Exact(size), } } @@ -63,3 +125,15 @@ func DataDir() (string, error) { func Main() { osMain() } + +func (FrameEvent) ImplementsEvent() {} + +func init() { + if extraArgs != "" { + args := strings.Split(extraArgs, "|") + os.Args = append(os.Args, args...) + } + if ID == "" { + ID = filepath.Base(os.Args[0]) + } +} diff --git a/app/doc.go b/app/doc.go index 51e872b4..dbbce080 100644 --- a/app/doc.go +++ b/app/doc.go @@ -17,12 +17,10 @@ FrameEvent that prompts an update of the window contents. For example: - import "gioui.org/unit" - w := app.NewWindow() for { e := w.NextEvent() - if e, ok := e.(system.FrameEvent); ok { + if e, ok := e.(app.FrameEvent); ok { ops.Reset() // Add operations to ops. ... diff --git a/app/os.go b/app/os.go index b5f18bcc..d030cabb 100644 --- a/app/os.go +++ b/app/os.go @@ -132,7 +132,7 @@ func (o Orientation) String() string { } type frameEvent struct { - system.FrameEvent + FrameEvent Sync bool } diff --git a/app/os_android.go b/app/os_android.go index 17d29162..1c80ec03 100644 --- a/app/os_android.go +++ b/app/os_android.go @@ -836,14 +836,14 @@ func (w *window) draw(env *C.JNIEnv, sync bool) { const inchPrDp = 1.0 / 160 ppdp := float32(w.dpi) * inchPrDp dppp := unit.Dp(1.0 / ppdp) - insets := system.Insets{ + insets := Insets{ Top: unit.Dp(w.insets.top) * dppp, Bottom: unit.Dp(w.insets.bottom) * dppp, Left: unit.Dp(w.insets.left) * dppp, Right: unit.Dp(w.insets.right) * dppp, } w.callbacks.Event(frameEvent{ - FrameEvent: system.FrameEvent{ + FrameEvent: FrameEvent{ Now: time.Now(), Size: w.config.Size, Insets: insets, diff --git a/app/os_ios.go b/app/os_ios.go index 662271a3..d890c265 100644 --- a/app/os_ios.go +++ b/app/os_ios.go @@ -156,13 +156,13 @@ func (w *window) draw(sync bool) { } dppp := unit.Dp(1. / m.PxPerDp) w.w.Event(frameEvent{ - FrameEvent: system.FrameEvent{ + FrameEvent: FrameEvent{ Now: time.Now(), Size: image.Point{ X: int(params.width + .5), Y: int(params.height + .5), }, - Insets: system.Insets{ + Insets: Insets{ Top: unit.Dp(params.top) * dppp, Bottom: unit.Dp(params.bottom) * dppp, Left: unit.Dp(params.left) * dppp, diff --git a/app/os_js.go b/app/os_js.go index 2752e814..fbeaa97f 100644 --- a/app/os_js.go +++ b/app/os_js.go @@ -666,7 +666,7 @@ func (w *window) draw(sync bool) { } w.w.Event(frameEvent{ - FrameEvent: system.FrameEvent{ + FrameEvent: FrameEvent{ Now: time.Now(), Size: size, Insets: insets, @@ -676,10 +676,10 @@ func (w *window) draw(sync bool) { }) } -func (w *window) getConfig() (image.Point, system.Insets, unit.Metric) { +func (w *window) getConfig() (image.Point, Insets, unit.Metric) { invscale := unit.Dp(1. / w.scale) return image.Pt(w.config.Size.X, w.config.Size.Y), - system.Insets{ + Insets{ Bottom: unit.Dp(w.inset.Y) * invscale, Right: unit.Dp(w.inset.X) * invscale, }, unit.Metric{ diff --git a/app/os_macos.go b/app/os_macos.go index d02c7cb9..09d26121 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -777,7 +777,7 @@ func (w *window) draw() { cfg := configFor(w.scale) w.setStage(system.StageRunning) w.w.Event(frameEvent{ - FrameEvent: system.FrameEvent{ + FrameEvent: FrameEvent{ Now: time.Now(), Size: w.config.Size, Metric: cfg, diff --git a/app/os_wayland.go b/app/os_wayland.go index e3750526..72e8131c 100644 --- a/app/os_wayland.go +++ b/app/os_wayland.go @@ -1712,7 +1712,7 @@ func (w *window) draw() { C.wl_callback_add_listener(w.lastFrameCallback, &C.gio_callback_listener, unsafe.Pointer(w.surf)) } w.w.Event(frameEvent{ - FrameEvent: system.FrameEvent{ + FrameEvent: FrameEvent{ Now: time.Now(), Size: w.config.Size, Metric: cfg, diff --git a/app/os_windows.go b/app/os_windows.go index 49a19585..467dc91f 100644 --- a/app/os_windows.go +++ b/app/os_windows.go @@ -621,7 +621,7 @@ func (w *window) draw(sync bool) { dpi := windows.GetWindowDPI(w.hwnd) cfg := configForDPI(dpi) w.w.Event(frameEvent{ - FrameEvent: system.FrameEvent{ + FrameEvent: FrameEvent{ Now: time.Now(), Size: w.config.Size, Metric: cfg, diff --git a/app/os_x11.go b/app/os_x11.go index a80c9c60..4ebc2af4 100644 --- a/app/os_x11.go +++ b/app/os_x11.go @@ -458,7 +458,7 @@ loop: if (anim || syn) && w.config.Size.X != 0 && w.config.Size.Y != 0 { w.w.Event(frameEvent{ - FrameEvent: system.FrameEvent{ + FrameEvent: FrameEvent{ Now: time.Now(), Size: w.config.Size, Metric: w.metric, diff --git a/app/window.go b/app/window.go index 3b1ee9af..c3ce9113 100644 --- a/app/window.go +++ b/app/window.go @@ -994,7 +994,7 @@ func (w *Window) fallbackDecorate() bool { } // decorate the window if enabled and returns the corresponding Insets. -func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) (size, offset image.Point) { +func (w *Window) decorate(d driver, e FrameEvent, o *op.Ops) (size, offset image.Point) { if !w.fallbackDecorate() { return e.Size, image.Pt(0, 0) } diff --git a/io/system/system.go b/io/system/system.go index 7dc4a0fa..e7032b36 100644 --- a/io/system/system.go +++ b/io/system/system.go @@ -4,35 +4,6 @@ // program level. package system -import ( - "image" - "time" - - "gioui.org/io/event" - "gioui.org/op" - "gioui.org/unit" -) - -// A FrameEvent requests a new frame in the form of a list of -// operations that describes what to display and how to handle -// input. -type FrameEvent struct { - // Now is the current animation. Use Now instead of time.Now to - // synchronize animation and to avoid the time.Now call overhead. - Now time.Time - // Metric converts device independent dp and sp to device pixels. - Metric unit.Metric - // Size is the dimensions of the window. - Size image.Point - // Insets represent the space occupied by system decorations and controls. - Insets Insets - // Frame completes the FrameEvent by drawing the graphical operations - // from ops into the window. - Frame func(frame *op.Ops) - // Queue supplies the events for event handlers. - Queue event.Queue -} - // DestroyEvent is the last event sent through // a window event channel. type DestroyEvent struct { @@ -41,14 +12,6 @@ type DestroyEvent struct { Err error } -// Insets is the space taken up by -// system decoration such as translucent -// system bars and software keyboards. -type Insets struct { - // Values are in pixels. - Top, Bottom, Left, Right unit.Dp -} - // A StageEvent is generated whenever the stage of a // Window changes. type StageEvent struct { @@ -60,13 +23,13 @@ type Stage uint8 const ( // StagePaused is the stage for windows that have no on-screen representation. - // Paused windows don't receive FrameEvent. + // Paused windows don't receive frames. StagePaused Stage = iota // StageInactive is the stage for windows that are visible, but not active. - // Inactive windows receive FrameEvent. + // Inactive windows receive frames. StageInactive // StageRunning is for active and visible Windows. - // Running windows receive FrameEvent. + // Running windows receive frames. StageRunning ) @@ -84,6 +47,5 @@ func (l Stage) String() string { } } -func (FrameEvent) ImplementsEvent() {} func (StageEvent) ImplementsEvent() {} func (DestroyEvent) ImplementsEvent() {} diff --git a/layout/context.go b/layout/context.go index 46ea337f..7c657e07 100644 --- a/layout/context.go +++ b/layout/context.go @@ -3,7 +3,6 @@ package layout import ( - "image" "time" "gioui.org/io/event" @@ -35,43 +34,6 @@ type Context struct { *op.Ops } -// NewContext is a shorthand for -// -// Context{ -// Ops: ops, -// Now: e.Now, -// Queue: e.Queue, -// Config: e.Config, -// Constraints: Exact(e.Size), -// } -// -// NewContext calls ops.Reset and adjusts ops for e.Insets. -func NewContext(ops *op.Ops, e system.FrameEvent) Context { - ops.Reset() - - size := e.Size - - if e.Insets != (system.Insets{}) { - left := e.Metric.Dp(e.Insets.Left) - top := e.Metric.Dp(e.Insets.Top) - op.Offset(image.Point{ - X: left, - Y: top, - }).Add(ops) - - size.X -= left + e.Metric.Dp(e.Insets.Right) - size.Y -= top + e.Metric.Dp(e.Insets.Bottom) - } - - return Context{ - Ops: ops, - Now: e.Now, - Queue: e.Queue, - Metric: e.Metric, - Constraints: Exact(size), - } -} - // Dp converts v to pixels. func (c Context) Dp(v unit.Dp) int { return c.Metric.Dp(v) diff --git a/widget/button_test.go b/widget/button_test.go index 49f3a5ee..0a00f1c8 100644 --- a/widget/button_test.go +++ b/widget/button_test.go @@ -6,9 +6,9 @@ import ( "image" "testing" + "gioui.org/app" "gioui.org/io/key" "gioui.org/io/router" - "gioui.org/io/system" "gioui.org/layout" "gioui.org/op" "gioui.org/widget" @@ -21,7 +21,7 @@ func TestClickable(t *testing.T) { b1 widget.Clickable b2 widget.Clickable ) - gtx := layout.NewContext(&ops, system.FrameEvent{Queue: &r}) + gtx := app.NewContext(&ops, app.FrameEvent{Queue: &r}) layout := func() { b1.Layout(gtx, func(gtx layout.Context) layout.Dimensions { return layout.Dimensions{Size: image.Pt(100, 100)} diff --git a/widget/material/list_test.go b/widget/material/list_test.go index 873e28d8..9ac1019a 100644 --- a/widget/material/list_test.go +++ b/widget/material/list_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "gioui.org/io/system" + "gioui.org/app" "gioui.org/layout" "gioui.org/op" "gioui.org/unit" @@ -15,7 +15,7 @@ import ( func TestListAnchorStrategies(t *testing.T) { var ops op.Ops - gtx := layout.NewContext(&ops, system.FrameEvent{ + gtx := app.NewContext(&ops, app.FrameEvent{ Metric: unit.Metric{ PxPerDp: 1, PxPerSp: 1, diff --git a/widget/widget_test.go b/widget/widget_test.go index 99a718ad..cd10d8c5 100644 --- a/widget/widget_test.go +++ b/widget/widget_test.go @@ -6,11 +6,11 @@ import ( "image" "testing" + "gioui.org/app" "gioui.org/f32" "gioui.org/io/pointer" "gioui.org/io/router" "gioui.org/io/semantic" - "gioui.org/io/system" "gioui.org/layout" "gioui.org/op" "gioui.org/widget" @@ -22,7 +22,7 @@ func TestBool(t *testing.T) { r router.Router b widget.Bool ) - gtx := layout.NewContext(&ops, system.FrameEvent{Queue: &r}) + gtx := app.NewContext(&ops, app.FrameEvent{Queue: &r}) layout := func() { b.Layout(gtx, func(gtx layout.Context) layout.Dimensions { semantic.CheckBox.Add(gtx.Ops)