op: add package op for operations

Extract operation types from package ui into package op.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-09-30 15:41:15 +02:00
parent eba1b3a95f
commit 8cf35a1f97
27 changed files with 225 additions and 227 deletions
+6 -6
View File
@@ -12,11 +12,11 @@ import (
"strings" "strings"
"time" "time"
"gioui.org/ui"
"gioui.org/app/internal/gl" "gioui.org/app/internal/gl"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/internal/ops" "gioui.org/internal/ops"
"gioui.org/op"
"gioui.org/paint" "gioui.org/paint"
"golang.org/x/image/draw" "golang.org/x/image/draw"
) )
@@ -74,7 +74,7 @@ type drawOps struct {
type drawState struct { type drawState struct {
clip f32.Rectangle clip f32.Rectangle
t ui.TransformOp t op.TransformOp
cpath *pathOp cpath *pathOp
rect bool rect bool
z int z int
@@ -398,7 +398,7 @@ func (g *GPU) Refresh() {
g.setErr(<-g.refreshErr) g.setErr(<-g.refreshErr)
} }
func (g *GPU) Draw(profile bool, viewport image.Point, root *ui.Ops) { func (g *GPU) Draw(profile bool, viewport image.Point, root *op.Ops) {
if g.err != nil { if g.err != nil {
return return
} }
@@ -678,7 +678,7 @@ func (d *drawOps) reset(cache *resourceCache, viewport image.Point) {
d.pathOpCache = d.pathOpCache[:0] d.pathOpCache = d.pathOpCache[:0]
} }
func (d *drawOps) collect(cache *resourceCache, root *ui.Ops, viewport image.Point) { func (d *drawOps) collect(cache *resourceCache, root *op.Ops, viewport image.Point) {
d.reset(cache, viewport) d.reset(cache, viewport)
clip := f32.Rectangle{ clip := f32.Rectangle{
Max: f32.Point{X: float32(viewport.X), Y: float32(viewport.Y)}, Max: f32.Point{X: float32(viewport.X), Y: float32(viewport.Y)},
@@ -704,8 +704,8 @@ loop:
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() { for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
switch opconst.OpType(encOp.Data[0]) { switch opconst.OpType(encOp.Data[0]) {
case opconst.TypeTransform: case opconst.TypeTransform:
op := ops.DecodeTransformOp(encOp.Data) dop := ops.DecodeTransformOp(encOp.Data)
state.t = state.t.Multiply(ui.TransformOp(op)) state.t = state.t.Multiply(op.TransformOp(dop))
case opconst.TypeAux: case opconst.TypeAux:
aux = encOp.Data[opconst.TypeAuxLen:] aux = encOp.Data[opconst.TypeAuxLen:]
auxKey = encOp.Key auxKey = encOp.Key
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"gioui.org/internal/ops" "gioui.org/internal/ops"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/ui" "gioui.org/op"
) )
type TextInputState uint8 type TextInputState uint8
@@ -44,7 +44,7 @@ func (q *keyQueue) InputState() TextInputState {
return q.state return q.state
} }
func (q *keyQueue) Frame(root *ui.Ops, events *handlerEvents) { func (q *keyQueue) Frame(root *op.Ops, events *handlerEvents) {
if q.handlers == nil { if q.handlers == nil {
q.handlers = make(map[event.Key]*keyHandler) q.handlers = make(map[event.Key]*keyHandler)
} }
+8 -8
View File
@@ -11,7 +11,7 @@ import (
"gioui.org/internal/ops" "gioui.org/internal/ops"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/ui" "gioui.org/op"
) )
type pointerQueue struct { type pointerQueue struct {
@@ -42,7 +42,7 @@ type pointerInfo struct {
type pointerHandler struct { type pointerHandler struct {
area int area int
active bool active bool
transform ui.TransformOp transform op.TransformOp
wantsGrab bool wantsGrab bool
} }
@@ -52,7 +52,7 @@ type areaOp struct {
} }
type areaNode struct { type areaNode struct {
trans ui.TransformOp trans op.TransformOp
next int next int
area areaOp area areaOp
} }
@@ -64,7 +64,7 @@ const (
areaEllipse areaEllipse
) )
func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t ui.TransformOp, area, node int, pass bool) { func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t op.TransformOp, area, node int, pass bool) {
for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() { for encOp, ok := r.Decode(); ok; encOp, ok = r.Decode() {
switch opconst.OpType(encOp.Data[0]) { switch opconst.OpType(encOp.Data[0]) {
case opconst.TypePush: case opconst.TypePush:
@@ -86,8 +86,8 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t u
}) })
node = len(q.hitTree) - 1 node = len(q.hitTree) - 1
case opconst.TypeTransform: case opconst.TypeTransform:
op := ops.DecodeTransformOp(encOp.Data) dop := ops.DecodeTransformOp(encOp.Data)
t = t.Multiply(ui.TransformOp(op)) t = t.Multiply(op.TransformOp(dop))
case opconst.TypePointerInput: case opconst.TypePointerInput:
op := decodePointerInputOp(encOp.Data, encOp.Refs) op := decodePointerInputOp(encOp.Data, encOp.Refs)
q.hitTree = append(q.hitTree, hitNode{ q.hitTree = append(q.hitTree, hitNode{
@@ -158,7 +158,7 @@ func (q *pointerQueue) init() {
} }
} }
func (q *pointerQueue) Frame(root *ui.Ops, events *handlerEvents) { func (q *pointerQueue) Frame(root *op.Ops, events *handlerEvents) {
q.init() q.init()
for _, h := range q.handlers { for _, h := range q.handlers {
// Reset handler. // Reset handler.
@@ -167,7 +167,7 @@ func (q *pointerQueue) Frame(root *ui.Ops, events *handlerEvents) {
q.hitTree = q.hitTree[:0] q.hitTree = q.hitTree[:0]
q.areas = q.areas[:0] q.areas = q.areas[:0]
q.reader.Reset(root) q.reader.Reset(root)
q.collectHandlers(&q.reader, events, ui.TransformOp{}, -1, -1, false) q.collectHandlers(&q.reader, events, op.TransformOp{}, -1, -1, false)
for k, h := range q.handlers { for k, h := range q.handlers {
if !h.active { if !h.active {
q.dropHandler(k) q.dropHandler(k)
+4 -4
View File
@@ -12,7 +12,7 @@ import (
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/io/profile" "gioui.org/io/profile"
"gioui.org/ui" "gioui.org/op"
) )
// Router is a Queue implementation that routes events from // Router is a Queue implementation that routes events from
@@ -53,7 +53,7 @@ func (q *Router) Events(k event.Key) []event.Event {
return events return events
} }
func (q *Router) Frame(ops *ui.Ops) { func (q *Router) Frame(ops *op.Ops) {
q.handlers.Clear() q.handlers.Clear()
q.wakeup = false q.wakeup = false
q.profHandlers = q.profHandlers[:0] q.profHandlers = q.profHandlers[:0]
@@ -160,12 +160,12 @@ func decodeProfileOp(d []byte, refs []interface{}) profile.Op {
} }
} }
func decodeInvalidateOp(d []byte) ui.InvalidateOp { func decodeInvalidateOp(d []byte) op.InvalidateOp {
bo := binary.LittleEndian bo := binary.LittleEndian
if opconst.OpType(d[0]) != opconst.TypeInvalidate { if opconst.OpType(d[0]) != opconst.TypeInvalidate {
panic("invalid op") panic("invalid op")
} }
var o ui.InvalidateOp var o op.InvalidateOp
if nanos := bo.Uint64(d[1:]); nanos > 0 { if nanos := bo.Uint64(d[1:]); nanos > 0 {
o.At = time.Unix(0, int64(nanos)) o.At = time.Unix(0, int64(nanos))
} }
+6 -5
View File
@@ -12,6 +12,7 @@ import (
"gioui.org/app/internal/input" "gioui.org/app/internal/input"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/profile" "gioui.org/io/profile"
"gioui.org/op"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -36,7 +37,7 @@ type Window struct {
in chan event.Event in chan event.Event
ack chan struct{} ack chan struct{}
invalidates chan struct{} invalidates chan struct{}
frames chan *ui.Ops frames chan *op.Ops
stage Stage stage Stage
animating bool animating bool
@@ -99,7 +100,7 @@ func NewWindow(options ...WindowOption) *Window {
out: make(chan event.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 *op.Ops),
} }
go w.run(opts) go w.run(opts)
return w return w
@@ -120,11 +121,11 @@ func (w *Window) Queue() *Queue {
// window contents, input operations declare input handlers, // window contents, input operations declare input handlers,
// and so on. The supplied operations list completely replaces // and so on. The supplied operations list completely replaces
// the window state from previous calls. // the window state from previous calls.
func (w *Window) Update(frame *ui.Ops) { func (w *Window) Update(frame *op.Ops) {
w.frames <- frame w.frames <- frame
} }
func (w *Window) draw(size image.Point, frame *ui.Ops) { func (w *Window) draw(size image.Point, frame *op.Ops) {
var drawDur time.Duration var drawDur time.Duration
if !w.drawStart.IsZero() { if !w.drawStart.IsZero() {
drawDur = time.Since(w.drawStart) drawDur = time.Since(w.drawStart)
@@ -265,7 +266,7 @@ func (w *Window) run(opts *windowOptions) {
w.drawStart = time.Now() w.drawStart = time.Now()
w.hasNextFrame = false w.hasNextFrame = false
w.out <- e w.out <- e
var frame *ui.Ops var frame *op.Ops
// Wait for either a frame or the ack event, // Wait for either a frame or the ack event,
// which meant that the client didn't draw. // which meant that the client didn't draw.
select { select {
+1 -2
View File
@@ -7,7 +7,6 @@ import (
"image/color" "image/color"
"log" "log"
"gioui.org/ui"
"gioui.org/app" "gioui.org/app"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/paint" "gioui.org/paint"
@@ -25,7 +24,7 @@ func main() {
func loop(w *app.Window) error { func loop(w *app.Window) error {
background := color.RGBA{255, 0, 0, 255} background := color.RGBA{255, 0, 0, 255}
ops := new(ui.Ops) ops := new(op.Ops)
for { for {
e := <-w.Events() e := <-w.Events()
switch e := e.(type) { switch e := e.(type) {
+4 -3
View File
@@ -16,6 +16,7 @@ import (
"gioui.org/internal/fling" "gioui.org/internal/fling"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/op"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -95,7 +96,7 @@ const (
var touchSlop = ui.Dp(3) var touchSlop = ui.Dp(3)
// Add the handler to the operation list to receive click events. // Add the handler to the operation list to receive click events.
func (c *Click) Add(ops *ui.Ops) { func (c *Click) Add(ops *op.Ops) {
op := pointer.InputOp{Key: c} op := pointer.InputOp{Key: c}
op.Add(ops) op.Add(ops)
} }
@@ -140,11 +141,11 @@ func (c *Click) Events(q event.Queue) []ClickEvent {
} }
// Add the handler to the operation list to receive scroll events. // Add the handler to the operation list to receive scroll events.
func (s *Scroll) Add(ops *ui.Ops) { func (s *Scroll) Add(ops *op.Ops) {
oph := pointer.InputOp{Key: s, Grab: s.grab} oph := pointer.InputOp{Key: s, Grab: s.grab}
oph.Add(ops) oph.Add(ops)
if s.flinger.Active() { if s.flinger.Active() {
ui.InvalidateOp{}.Add(ops) op.InvalidateOp{}.Add(ops)
} }
} }
+3 -3
View File
@@ -6,17 +6,17 @@ import (
"encoding/binary" "encoding/binary"
"math" "math"
"gioui.org/ui"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/op"
) )
func DecodeTransformOp(d []byte) ui.TransformOp { func DecodeTransformOp(d []byte) op.TransformOp {
bo := binary.LittleEndian bo := binary.LittleEndian
if opconst.OpType(d[0]) != opconst.TypeTransform { if opconst.OpType(d[0]) != opconst.TypeTransform {
panic("invalid op") panic("invalid op")
} }
return ui.TransformOp{}.Offset(f32.Point{ return op.TransformOp{}.Offset(f32.Point{
X: math.Float32frombits(bo.Uint32(d[1:])), X: math.Float32frombits(bo.Uint32(d[1:])),
Y: math.Float32frombits(bo.Uint32(d[5:])), Y: math.Float32frombits(bo.Uint32(d[5:])),
}) })
+8 -8
View File
@@ -5,15 +5,15 @@ package ops
import ( import (
"encoding/binary" "encoding/binary"
"gioui.org/ui"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/op"
) )
// Reader parses an ops list. // Reader parses an ops list.
type Reader struct { type Reader struct {
pc pc pc pc
stack []macro stack []macro
ops *ui.Ops ops *op.Ops
} }
// EncodedOp represents an encoded op returned by // EncodedOp represents an encoded op returned by
@@ -26,14 +26,14 @@ type EncodedOp struct {
// Key is a unique key for a given op. // Key is a unique key for a given op.
type Key struct { type Key struct {
ops *ui.Ops ops *op.Ops
pc int pc int
version int version int
} }
// Shadow of ui.MacroOp. // Shadow of op.MacroOp.
type macroOp struct { type macroOp struct {
ops *ui.Ops ops *op.Ops
version int version int
pc pc pc pc
} }
@@ -44,7 +44,7 @@ type pc struct {
} }
type macro struct { type macro struct {
ops *ui.Ops ops *op.Ops
retPC pc retPC pc
endPC pc endPC pc
} }
@@ -58,7 +58,7 @@ type opAux struct {
} }
// Reset start reading from the op list. // Reset start reading from the op list.
func (r *Reader) Reset(ops *ui.Ops) { func (r *Reader) Reset(ops *op.Ops) {
r.stack = r.stack[:0] r.stack = r.stack[:0]
r.pc = pc{} r.pc = pc{}
r.ops = ops r.ops = ops
@@ -170,7 +170,7 @@ func (m *macroOp) decode(data []byte, refs []interface{}) {
refsIdx := int(int32(bo.Uint32(data[5:]))) refsIdx := int(int32(bo.Uint32(data[5:])))
version := int(int32(bo.Uint32(data[9:]))) version := int(int32(bo.Uint32(data[9:])))
*m = macroOp{ *m = macroOp{
ops: refs[0].(*ui.Ops), ops: refs[0].(*op.Ops),
pc: pc{ pc: pc{
data: dataIdx, data: dataIdx,
refs: refsIdx, refs: refsIdx,
+1 -1
View File
@@ -23,7 +23,7 @@ The following example declares a handler ready for key input:
import gioui.org/io/key import gioui.org/io/key
ops := new(ui.Ops) ops := new(op.Ops)
var h *Handler = ... var h *Handler = ...
key.InputOp{Key: h}.Add(ops) key.InputOp{Key: h}.Add(ops)
+3 -3
View File
@@ -12,7 +12,7 @@ package key
import ( import (
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/ui" "gioui.org/op"
) )
// InputOp declares a handler ready for key events. // InputOp declares a handler ready for key events.
@@ -86,7 +86,7 @@ func (m Modifiers) Contain(m2 Modifiers) bool {
return m&m2 == m2 return m&m2 == m2
} }
func (h InputOp) Add(o *ui.Ops) { func (h InputOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeKeyInputLen) data := make([]byte, opconst.TypeKeyInputLen)
data[0] = byte(opconst.TypeKeyInput) data[0] = byte(opconst.TypeKeyInput)
if h.Focus { if h.Focus {
@@ -95,7 +95,7 @@ func (h InputOp) Add(o *ui.Ops) {
o.Write(data, h.Key) o.Write(data, h.Key)
} }
func (h HideInputOp) Add(o *ui.Ops) { func (h HideInputOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeHideInputLen) data := make([]byte, opconst.TypeHideInputLen)
data[0] = byte(opconst.TypeHideInput) data[0] = byte(opconst.TypeHideInput)
o.Write(data) o.Write(data)
+3 -3
View File
@@ -15,7 +15,7 @@ subsequent InputOp are active.
For example, to set up a rectangular hit area: For example, to set up a rectangular hit area:
var ops ui.Ops var ops op.Ops
var h *Handler = ... var h *Handler = ...
r := image.Rectangle{...} r := image.Rectangle{...}
@@ -33,8 +33,8 @@ with the most recent node.
For example: For example:
ops := new(ui.Ops) ops := new(op.Ops)
var stack ui.StackOp var stack op.StackOp
var h1, h2 *Handler var h1, h2 *Handler
stack.Push(ops) stack.Push(ops)
+7 -7
View File
@@ -10,7 +10,7 @@ import (
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/ui" "gioui.org/op"
) )
// Event is a pointer event. // Event is a pointer event.
@@ -33,7 +33,7 @@ type Event struct {
// outside it. // outside it.
Hit bool Hit bool
// Position is the position of the event, relative to // Position is the position of the event, relative to
// the current transformation, as set by ui.TransformOp. // the current transformation, as set by op.TransformOp.
Position f32.Point Position f32.Point
// Scroll is the scroll amount, if any. // Scroll is the scroll amount, if any.
Scroll f32.Point Scroll f32.Point
@@ -124,21 +124,21 @@ const (
areaEllipse areaEllipse
) )
func (op RectAreaOp) Add(ops *ui.Ops) { func (op RectAreaOp) Add(ops *op.Ops) {
areaOp{ areaOp{
kind: areaRect, kind: areaRect,
rect: op.Rect, rect: op.Rect,
}.add(ops) }.add(ops)
} }
func (op EllipseAreaOp) Add(ops *ui.Ops) { func (op EllipseAreaOp) Add(ops *op.Ops) {
areaOp{ areaOp{
kind: areaEllipse, kind: areaEllipse,
rect: op.Rect, rect: op.Rect,
}.add(ops) }.add(ops)
} }
func (op areaOp) add(o *ui.Ops) { func (op areaOp) add(o *op.Ops) {
data := make([]byte, opconst.TypeAreaLen) data := make([]byte, opconst.TypeAreaLen)
data[0] = byte(opconst.TypeArea) data[0] = byte(opconst.TypeArea)
data[1] = byte(op.kind) data[1] = byte(op.kind)
@@ -150,7 +150,7 @@ func (op areaOp) add(o *ui.Ops) {
o.Write(data) o.Write(data)
} }
func (h InputOp) Add(o *ui.Ops) { func (h InputOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypePointerInputLen) data := make([]byte, opconst.TypePointerInputLen)
data[0] = byte(opconst.TypePointerInput) data[0] = byte(opconst.TypePointerInput)
if h.Grab { if h.Grab {
@@ -159,7 +159,7 @@ func (h InputOp) Add(o *ui.Ops) {
o.Write(data, h.Key) o.Write(data, h.Key)
} }
func (op PassOp) Add(o *ui.Ops) { func (op PassOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypePassLen) data := make([]byte, opconst.TypePassLen)
data[0] = byte(opconst.TypePass) data[0] = byte(opconst.TypePass)
if op.Pass { if op.Pass {
+2 -2
View File
@@ -7,7 +7,7 @@ package profile
import ( import (
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/ui" "gioui.org/op"
) )
// Op registers a handler for receiving // Op registers a handler for receiving
@@ -23,7 +23,7 @@ type Event struct {
Timings string Timings string
} }
func (p Op) Add(o *ui.Ops) { func (p Op) Add(o *op.Ops) {
data := make([]byte, opconst.TypeProfileLen) data := make([]byte, opconst.TypeProfileLen)
data[0] = byte(opconst.TypeProfile) data[0] = byte(opconst.TypeProfile)
o.Write(data, p.Key) o.Write(data, p.Key)
+5 -5
View File
@@ -6,7 +6,7 @@ import (
"image" "image"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/ui" "gioui.org/op"
) )
// Flex lays out child elements along an axis, // Flex lays out child elements along an axis,
@@ -21,7 +21,7 @@ type Flex struct {
Alignment Alignment Alignment Alignment
ctx *Context ctx *Context
macro ui.MacroOp macro op.MacroOp
mode flexMode mode flexMode
size int size int
rigidSize int rigidSize int
@@ -33,7 +33,7 @@ type Flex struct {
// FlexChild is the layout result of a call End. // FlexChild is the layout result of a call End.
type FlexChild struct { type FlexChild struct {
macro ui.MacroOp macro op.MacroOp
dims Dimensions dims Dimensions
} }
@@ -189,9 +189,9 @@ func (f *Flex) Layout(children ...FlexChild) {
cross = f.maxBaseline - b cross = f.maxBaseline - b
} }
} }
var stack ui.StackOp var stack op.StackOp
stack.Push(f.ctx.Ops) stack.Push(f.ctx.Ops)
ui.TransformOp{}.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))).Add(f.ctx.Ops) op.TransformOp{}.Offset(toPointF(axisPoint(f.Axis, mainSize, cross))).Add(f.ctx.Ops)
child.macro.Add(f.ctx.Ops) child.macro.Add(f.ctx.Ops)
stack.Pop() stack.Pop()
mainSize += axisMain(f.Axis, dims.Size) mainSize += axisMain(f.Axis, dims.Size)
+8 -7
View File
@@ -6,6 +6,7 @@ import (
"image" "image"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/op"
"gioui.org/ui" "gioui.org/ui"
) )
@@ -53,7 +54,7 @@ type Context struct {
ui.Config ui.Config
event.Queue event.Queue
*ui.Ops *op.Ops
} }
const ( const (
@@ -97,7 +98,7 @@ func (c *Context) Reset(cfg ui.Config, cs Constraints) {
c.Dimensions = Dimensions{} c.Dimensions = Dimensions{}
c.Config = cfg c.Config = cfg
if c.Ops == nil { if c.Ops == nil {
c.Ops = new(ui.Ops) c.Ops = new(op.Ops)
} }
c.Ops.Reset() c.Ops.Reset()
} }
@@ -157,9 +158,9 @@ func (in Inset) Layout(gtx *Context, w Widget) {
if mcs.Height.Max < mcs.Height.Min { if mcs.Height.Max < mcs.Height.Min {
mcs.Height.Max = mcs.Height.Min mcs.Height.Max = mcs.Height.Min
} }
var stack ui.StackOp var stack op.StackOp
stack.Push(gtx.Ops) stack.Push(gtx.Ops)
ui.TransformOp{}.Offset(toPointF(image.Point{X: left, Y: top})).Add(gtx.Ops) op.TransformOp{}.Offset(toPointF(image.Point{X: left, Y: top})).Add(gtx.Ops)
dims := gtx.Layout(mcs, w) dims := gtx.Layout(mcs, w)
stack.Pop() stack.Pop()
gtx.Dimensions = Dimensions{ gtx.Dimensions = Dimensions{
@@ -176,7 +177,7 @@ func UniformInset(v ui.Value) Inset {
// Layout a widget. // Layout a widget.
func (a Align) Layout(gtx *Context, w Widget) { func (a Align) Layout(gtx *Context, w Widget) {
var macro ui.MacroOp var macro op.MacroOp
macro.Record(gtx.Ops) macro.Record(gtx.Ops)
cs := gtx.Constraints cs := gtx.Constraints
mcs := cs mcs := cs
@@ -204,9 +205,9 @@ func (a Align) Layout(gtx *Context, w Widget) {
case SW, S, SE: case SW, S, SE:
p.Y = sz.Y - dims.Size.Y p.Y = sz.Y - dims.Size.Y
} }
var stack ui.StackOp var stack op.StackOp
stack.Push(gtx.Ops) stack.Push(gtx.Ops)
ui.TransformOp{}.Offset(toPointF(p)).Add(gtx.Ops) op.TransformOp{}.Offset(toPointF(p)).Add(gtx.Ops)
macro.Add(gtx.Ops) macro.Add(gtx.Ops)
stack.Pop() stack.Pop()
gtx.Dimensions = Dimensions{ gtx.Dimensions = Dimensions{
+6 -6
View File
@@ -7,13 +7,13 @@ import (
"gioui.org/gesture" "gioui.org/gesture"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/op"
"gioui.org/paint" "gioui.org/paint"
"gioui.org/ui"
) )
type scrollChild struct { type scrollChild struct {
size image.Point size image.Point
macro ui.MacroOp macro op.MacroOp
} }
// List displays a subsection of a potentially infinitely // List displays a subsection of a potentially infinitely
@@ -33,8 +33,8 @@ type List struct {
beforeEnd bool beforeEnd bool
ctx *Context ctx *Context
macro ui.MacroOp macro op.MacroOp
child ui.MacroOp child op.MacroOp
scroll gesture.Scroll scroll gesture.Scroll
scrollDelta int scrollDelta int
@@ -246,10 +246,10 @@ func (l *List) layout() Dimensions {
Min: axisPoint(l.Axis, min, -inf), Min: axisPoint(l.Axis, min, -inf),
Max: axisPoint(l.Axis, max, inf), Max: axisPoint(l.Axis, max, inf),
} }
var stack ui.StackOp var stack op.StackOp
stack.Push(ops) stack.Push(ops)
paint.RectClip(r).Add(ops) paint.RectClip(r).Add(ops)
ui.TransformOp{}.Offset(toPointF(axisPoint(l.Axis, pos, cross))).Add(ops) op.TransformOp{}.Offset(toPointF(axisPoint(l.Axis, pos, cross))).Add(ops)
child.macro.Add(ops) child.macro.Add(ops)
stack.Pop() stack.Pop()
pos += childSize pos += childSize
+5 -5
View File
@@ -5,7 +5,7 @@ package layout
import ( import (
"image" "image"
"gioui.org/ui" "gioui.org/op"
) )
// Stack lays out child elements on top of each other, // Stack lays out child elements on top of each other,
@@ -15,7 +15,7 @@ type Stack struct {
// smaller than the available space. // smaller than the available space.
Alignment Direction Alignment Direction
macro ui.MacroOp macro op.MacroOp
constrained bool constrained bool
ctx *Context ctx *Context
maxSZ image.Point maxSZ image.Point
@@ -24,7 +24,7 @@ type Stack struct {
// StackChild is the layout result of a call to End. // StackChild is the layout result of a call to End.
type StackChild struct { type StackChild struct {
macro ui.MacroOp macro op.MacroOp
dims Dimensions dims Dimensions
} }
@@ -99,9 +99,9 @@ func (s *Stack) Layout(children ...StackChild) {
case SW, S, SE: case SW, S, SE:
p.Y = s.maxSZ.Y - sz.Y p.Y = s.maxSZ.Y - sz.Y
} }
var stack ui.StackOp var stack op.StackOp
stack.Push(s.ctx.Ops) stack.Push(s.ctx.Ops)
ui.TransformOp{}.Offset(toPointF(p)).Add(s.ctx.Ops) op.TransformOp{}.Offset(toPointF(p)).Add(s.ctx.Ops)
ch.macro.Add(s.ctx.Ops) ch.macro.Add(s.ctx.Ops)
stack.Pop() stack.Pop()
} }
+7 -6
View File
@@ -10,10 +10,11 @@ import (
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
"gioui.org/ui"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/op"
"gioui.org/paint" "gioui.org/paint"
"gioui.org/text" "gioui.org/text"
"gioui.org/ui"
"golang.org/x/image/font" "golang.org/x/image/font"
"golang.org/x/image/font/sfnt" "golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
@@ -34,7 +35,7 @@ type cachedLayout struct {
type cachedPath struct { type cachedPath struct {
active bool active bool
path ui.MacroOp path op.MacroOp
} }
type layoutKey struct { type layoutKey struct {
@@ -128,7 +129,7 @@ func (f *Face) Layout(str string, opts text.LayoutOptions) *text.Layout {
return l return l
} }
func (f *Face) Path(str text.String) ui.MacroOp { func (f *Face) Path(str text.String) op.MacroOp {
ppem := fixed.Int26_6(f.faces.config.Px(f.size) * 64) ppem := fixed.Int26_6(f.faces.config.Px(f.size) * 64)
pk := pathKey{ pk := pathKey{
f: f.font.Font, f: f.font.Font,
@@ -234,14 +235,14 @@ func layoutText(ppem fixed.Int26_6, str string, f *opentype, opts text.LayoutOpt
return &text.Layout{Lines: lines} return &text.Layout{Lines: lines}
} }
func textPath(ppem fixed.Int26_6, f *opentype, str text.String) ui.MacroOp { func textPath(ppem fixed.Int26_6, f *opentype, str text.String) op.MacroOp {
var lastPos f32.Point var lastPos f32.Point
var builder paint.PathBuilder var builder paint.PathBuilder
ops := new(ui.Ops) ops := new(op.Ops)
builder.Init(ops) builder.Init(ops)
var x fixed.Int26_6 var x fixed.Int26_6
var advIdx int var advIdx int
var m ui.MacroOp var m op.MacroOp
m.Record(ops) m.Record(ops)
for _, r := range str.String { for _, r := range str.String {
if !unicode.IsSpace(r) { if !unicode.IsSpace(r) {
+115 -1
View File
@@ -1,10 +1,67 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package ui /*
Package op implements operations for updating a user interface.
Gio programs use operations, or ops, for describing their user
interfaces. There are operations for drawing, defining input
handlers, changing window properties as well as operations for
controlling the execution of other operations.
Ops represents a list of operations. The most important use
for an Ops list is to describe a complete user interface update
to a ui/app.Window's Update method.
Drawing a colored square:
import "gioui.org/ui"
import "gioui.org/app"
import "gioui.org/paint"
var w app.Window
ops := new(op.Ops)
...
ops.Reset()
paint.ColorOp{Color: ...}.Add(ops)
paint.PaintOp{Rect: ...}.Add(ops)
w.Update(ops)
State
An Ops list can be viewed as a very simple virtual machine: it has an implicit
mutable state stack and execution flow can be controlled with macros.
The StackOp saves the current state to the state stack and restores it later:
ops := new(op.Ops)
var stack op.StackOp
// Save the current state, in particular the transform.
stack.Push(ops)
// Apply a transform to subsequent operations.
op.TransformOp{}.Offset(...).Add(ops)
...
// Restore the previous transform.
stack.Pop()
The MacroOp records a list of operations to be executed later:
ops := new(op.Ops)
var macro op.MacroOp
macro.Record()
// Record operations by adding them.
op.InvalidateOp{}.Add(ops)
...
*/
package op
import ( import (
"encoding/binary" "encoding/binary"
"math"
"time"
"gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
) )
@@ -45,6 +102,18 @@ type MacroOp struct {
pc pc pc pc
} }
// InvalidateOp requests a redraw at the given time. Use
// the zero value to request an immediate redraw.
type InvalidateOp struct {
At time.Time
}
// TransformOp applies a transform to the current transform.
type TransformOp struct {
// TODO: general transformations.
offset f32.Point
}
type pc struct { type pc struct {
data int data int
refs int refs int
@@ -208,3 +277,48 @@ func (m MacroOp) Add(o *Ops) {
bo.PutUint32(data[9:], uint32(m.version)) bo.PutUint32(data[9:], uint32(m.version))
o.Write(data, m.ops) o.Write(data, m.ops)
} }
func (r InvalidateOp) Add(o *Ops) {
data := make([]byte, opconst.TypeRedrawLen)
data[0] = byte(opconst.TypeInvalidate)
bo := binary.LittleEndian
// UnixNano cannot represent the zero time.
if t := r.At; !t.IsZero() {
nanos := t.UnixNano()
if nanos > 0 {
bo.PutUint64(data[1:], uint64(nanos))
}
}
o.Write(data)
}
// Offset the transformation.
func (t TransformOp) Offset(o f32.Point) TransformOp {
return t.Multiply(TransformOp{o})
}
// Invert the transformation.
func (t TransformOp) Invert() TransformOp {
return TransformOp{offset: t.offset.Mul(-1)}
}
// Transform a point.
func (t TransformOp) Transform(p f32.Point) f32.Point {
return p.Add(t.offset)
}
// Multiply by a transformation.
func (t TransformOp) Multiply(t2 TransformOp) TransformOp {
return TransformOp{
offset: t.offset.Add(t2.offset),
}
}
func (t TransformOp) Add(o *Ops) {
data := make([]byte, opconst.TypeTransformLen)
data[0] = byte(opconst.TypeTransform)
bo := binary.LittleEndian
bo.PutUint32(data[1:], math.Float32bits(t.offset.X))
bo.PutUint32(data[5:], math.Float32bits(t.offset.Y))
o.Write(data)
}
+4 -4
View File
@@ -8,9 +8,9 @@ import (
"image/color" "image/color"
"math" "math"
"gioui.org/ui"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/op"
) )
// ImageOp sets the material to a section of an // ImageOp sets the material to a section of an
@@ -33,7 +33,7 @@ type PaintOp struct {
Rect f32.Rectangle Rect f32.Rectangle
} }
func (i ImageOp) Add(o *ui.Ops) { func (i ImageOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeImageLen) data := make([]byte, opconst.TypeImageLen)
data[0] = byte(opconst.TypeImage) data[0] = byte(opconst.TypeImage)
bo := binary.LittleEndian bo := binary.LittleEndian
@@ -44,7 +44,7 @@ func (i ImageOp) Add(o *ui.Ops) {
o.Write(data, i.Src) o.Write(data, i.Src)
} }
func (c ColorOp) Add(o *ui.Ops) { func (c ColorOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeColorLen) data := make([]byte, opconst.TypeColorLen)
data[0] = byte(opconst.TypeColor) data[0] = byte(opconst.TypeColor)
data[1] = c.Color.R data[1] = c.Color.R
@@ -54,7 +54,7 @@ func (c ColorOp) Add(o *ui.Ops) {
o.Write(data) o.Write(data)
} }
func (d PaintOp) Add(o *ui.Ops) { func (d PaintOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypePaintLen) data := make([]byte, opconst.TypePaintLen)
data[0] = byte(opconst.TypePaint) data[0] = byte(opconst.TypePaint)
bo := binary.LittleEndian bo := binary.LittleEndian
+4 -4
View File
@@ -7,10 +7,10 @@ import (
"math" "math"
"unsafe" "unsafe"
"gioui.org/ui"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/internal/opconst" "gioui.org/internal/opconst"
"gioui.org/internal/path" "gioui.org/internal/path"
"gioui.org/op"
) )
// PathBuilder builds and adds a general ClipOp clip path // PathBuilder builds and adds a general ClipOp clip path
@@ -19,7 +19,7 @@ import (
// dynamic paths; path data is stored directly in the Ops // dynamic paths; path data is stored directly in the Ops
// list supplied to Init. // list supplied to Init.
type PathBuilder struct { type PathBuilder struct {
ops *ui.Ops ops *op.Ops
firstVert int firstVert int
nverts int nverts int
maxy float32 maxy float32
@@ -33,7 +33,7 @@ type ClipOp struct {
bounds f32.Rectangle bounds f32.Rectangle
} }
func (p ClipOp) Add(o *ui.Ops) { func (p ClipOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeClipLen) data := make([]byte, opconst.TypeClipLen)
data[0] = byte(opconst.TypeClip) data[0] = byte(opconst.TypeClip)
bo := binary.LittleEndian bo := binary.LittleEndian
@@ -46,7 +46,7 @@ func (p ClipOp) Add(o *ui.Ops) {
// Init the builder and specify the operations list for // Init the builder and specify the operations list for
// storing the path data and final ClipOp. // storing the path data and final ClipOp.
func (p *PathBuilder) Init(ops *ui.Ops) { func (p *PathBuilder) Init(ops *op.Ops) {
p.ops = ops p.ops = ops
} }
+7 -6
View File
@@ -14,6 +14,7 @@ import (
"gioui.org/io/key" "gioui.org/io/key"
"gioui.org/io/pointer" "gioui.org/io/pointer"
"gioui.org/layout" "gioui.org/layout"
"gioui.org/op"
"gioui.org/paint" "gioui.org/paint"
"gioui.org/ui" "gioui.org/ui"
@@ -33,12 +34,12 @@ type Editor struct {
Submit bool Submit bool
// Material for drawing the text. // Material for drawing the text.
Material ui.MacroOp Material op.MacroOp
// Hint contains the text displayed to the user when the // Hint contains the text displayed to the user when the
// Editor is empty. // Editor is empty.
Hint string Hint string
// Mmaterial is used to draw the hint. // Mmaterial is used to draw the hint.
HintMaterial ui.MacroOp HintMaterial op.MacroOp
oldScale int oldScale int
blinkStart time.Time blinkStart time.Time
@@ -218,7 +219,7 @@ func (e *Editor) Layout(gtx *layout.Context) {
Width: e.viewWidth(), Width: e.viewWidth(),
Offset: off, Offset: off,
} }
var stack ui.StackOp var stack op.StackOp
stack.Push(gtx.Ops) stack.Push(gtx.Ops)
// Apply material. Set a default color in case the material is empty. // Apply material. Set a default color in case the material is empty.
if e.rr.len() > 0 { if e.rr.len() > 0 {
@@ -233,9 +234,9 @@ func (e *Editor) Layout(gtx *layout.Context) {
if !ok { if !ok {
break break
} }
var stack ui.StackOp var stack op.StackOp
stack.Push(gtx.Ops) stack.Push(gtx.Ops)
ui.TransformOp{}.Offset(lineOff).Add(gtx.Ops) op.TransformOp{}.Offset(lineOff).Add(gtx.Ops)
e.Face.Path(str).Add(gtx.Ops) e.Face.Path(str).Add(gtx.Ops)
paint.PaintOp{Rect: toRectF(clip).Sub(lineOff)}.Add(gtx.Ops) paint.PaintOp{Rect: toRectF(clip).Sub(lineOff)}.Add(gtx.Ops)
stack.Pop() stack.Pop()
@@ -267,7 +268,7 @@ func (e *Editor) Layout(gtx *layout.Context) {
} }
} }
if blinking { if blinking {
redraw := ui.InvalidateOp{At: nextBlink} redraw := op.InvalidateOp{At: nextBlink}
redraw.Add(gtx.Ops) redraw.Add(gtx.Ops)
} }
} }
+4 -4
View File
@@ -8,9 +8,9 @@ import (
"image/color" "image/color"
"unicode/utf8" "unicode/utf8"
"gioui.org/ui"
"gioui.org/f32" "gioui.org/f32"
"gioui.org/layout" "gioui.org/layout"
"gioui.org/op"
"gioui.org/paint" "gioui.org/paint"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
@@ -22,7 +22,7 @@ type Label struct {
Face Face Face Face
// Material is a macro recording the material to draw the // Material is a macro recording the material to draw the
// text. Use a ColorOp for colored text. // text. Use a ColorOp for colored text.
Material ui.MacroOp Material op.MacroOp
// Alignment specify the text alignment. // Alignment specify the text alignment.
Alignment Alignment Alignment Alignment
// Text is the string to draw. // Text is the string to draw.
@@ -118,9 +118,9 @@ func (l Label) Layout(gtx *layout.Context) {
break break
} }
lclip := toRectF(clip).Sub(off) lclip := toRectF(clip).Sub(off)
var stack ui.StackOp var stack op.StackOp
stack.Push(gtx.Ops) stack.Push(gtx.Ops)
ui.TransformOp{}.Offset(off).Add(gtx.Ops) op.TransformOp{}.Offset(off).Add(gtx.Ops)
l.Face.Path(str).Add(gtx.Ops) l.Face.Path(str).Add(gtx.Ops)
// Set a default color in case the material is empty. // Set a default color in case the material is empty.
paint.ColorOp{Color: color.RGBA{A: 0xff}}.Add(gtx.Ops) paint.ColorOp{Color: color.RGBA{A: 0xff}}.Add(gtx.Ops)
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"fmt" "fmt"
"image" "image"
"gioui.org/ui"
"gioui.org/layout" "gioui.org/layout"
"gioui.org/op"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
) )
@@ -50,7 +50,7 @@ type Face interface {
// options. // options.
Layout(s string, opts LayoutOptions) *Layout Layout(s string, opts LayoutOptions) *Layout
// Path returns the ClipOp outline of a text recorded in a macro. // Path returns the ClipOp outline of a text recorded in a macro.
Path(s String) ui.MacroOp Path(s String) op.MacroOp
} }
type Alignment uint8 type Alignment uint8
-58
View File
@@ -4,64 +4,6 @@
Package ui defines operations buffers, units and common operations Package ui defines operations buffers, units and common operations
for GUI programs written with the Gio module. for GUI programs written with the Gio module.
Operations
Gio programs use operations, or ops, for describing their user
interfaces. There are operations for drawing, defining input
handlers, changing window properties as well as operations for
controlling the execution of other operations.
Ops represents a list of operations. The most important use
for an Ops list is to describe a complete user interface update
to a ui/app.Window's Update method.
Drawing a colored square:
import "gioui.org/ui"
import "gioui.org/app"
import "gioui.org/paint"
var w app.Window
ops := new(ui.Ops)
...
ops.Reset()
paint.ColorOp{Color: ...}.Add(ops)
paint.PaintOp{Rect: ...}.Add(ops)
w.Update(ops)
State
An Ops list can be viewed as a very simple virtual machine: it has an implicit
mutable state stack and execution flow can be controlled with macros.
The StackOp saves the current state to the state stack and restores it later:
ops := new(ui.Ops)
var stack ui.StackOp
// Save the current state, in particular the transform.
stack.Push(ops)
// Apply a transform to subsequent operations.
ui.TransformOp{}.Offset(...).Add(ops)
...
// Restore the previous transform.
stack.Pop()
The MacroOp records a list of operations to be executed later:
ops := new(ui.Ops)
var macro ui.MacroOp
macro.Record()
// Record operations by adding them.
ui.InvalidateOp{}.Add(ops)
...
macro.Stop()
...
// Execute the recorded operations.
macro.Add(ops)
Note that operations added between Record and Stop are not executed until
the macro is Added.
Units Units
A Value is a value with a Unit attached. A Value is a value with a Unit attached.
-62
View File
@@ -3,12 +3,7 @@
package ui package ui
import ( import (
"encoding/binary"
"math"
"time" "time"
"gioui.org/f32"
"gioui.org/internal/opconst"
) )
// Config define the essential properties of // Config define the essential properties of
@@ -19,60 +14,3 @@ type Config interface {
// Px converts a Value to pixels. // Px converts a Value to pixels.
Px(v Value) int Px(v Value) int
} }
// InvalidateOp requests a redraw at the given time. Use
// the zero value to request an immediate redraw.
type InvalidateOp struct {
At time.Time
}
// TransformOp applies a transform to the current transform.
type TransformOp struct {
// TODO: general transformations.
offset f32.Point
}
func (r InvalidateOp) Add(o *Ops) {
data := make([]byte, opconst.TypeRedrawLen)
data[0] = byte(opconst.TypeInvalidate)
bo := binary.LittleEndian
// UnixNano cannot represent the zero time.
if t := r.At; !t.IsZero() {
nanos := t.UnixNano()
if nanos > 0 {
bo.PutUint64(data[1:], uint64(nanos))
}
}
o.Write(data)
}
// Offset the transformation.
func (t TransformOp) Offset(o f32.Point) TransformOp {
return t.Multiply(TransformOp{o})
}
// Invert the transformation.
func (t TransformOp) Invert() TransformOp {
return TransformOp{offset: t.offset.Mul(-1)}
}
// Transform a point.
func (t TransformOp) Transform(p f32.Point) f32.Point {
return p.Add(t.offset)
}
// Multiply by a transformation.
func (t TransformOp) Multiply(t2 TransformOp) TransformOp {
return TransformOp{
offset: t.offset.Add(t2.offset),
}
}
func (t TransformOp) Add(o *Ops) {
data := make([]byte, opconst.TypeTransformLen)
data[0] = byte(opconst.TypeTransform)
bo := binary.LittleEndian
bo.PutUint32(data[1:], math.Float32bits(t.offset.X))
bo.PutUint32(data[5:], math.Float32bits(t.offset.Y))
o.Write(data)
}