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"
"time"
"gioui.org/ui"
"gioui.org/app/internal/gl"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/internal/ops"
"gioui.org/op"
"gioui.org/paint"
"golang.org/x/image/draw"
)
@@ -74,7 +74,7 @@ type drawOps struct {
type drawState struct {
clip f32.Rectangle
t ui.TransformOp
t op.TransformOp
cpath *pathOp
rect bool
z int
@@ -398,7 +398,7 @@ func (g *GPU) Refresh() {
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 {
return
}
@@ -678,7 +678,7 @@ func (d *drawOps) reset(cache *resourceCache, viewport image.Point) {
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)
clip := f32.Rectangle{
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() {
switch opconst.OpType(encOp.Data[0]) {
case opconst.TypeTransform:
op := ops.DecodeTransformOp(encOp.Data)
state.t = state.t.Multiply(ui.TransformOp(op))
dop := ops.DecodeTransformOp(encOp.Data)
state.t = state.t.Multiply(op.TransformOp(dop))
case opconst.TypeAux:
aux = encOp.Data[opconst.TypeAuxLen:]
auxKey = encOp.Key
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/key"
"gioui.org/ui"
"gioui.org/op"
)
type TextInputState uint8
@@ -44,7 +44,7 @@ func (q *keyQueue) InputState() TextInputState {
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 {
q.handlers = make(map[event.Key]*keyHandler)
}
+8 -8
View File
@@ -11,7 +11,7 @@ import (
"gioui.org/internal/ops"
"gioui.org/io/event"
"gioui.org/io/pointer"
"gioui.org/ui"
"gioui.org/op"
)
type pointerQueue struct {
@@ -42,7 +42,7 @@ type pointerInfo struct {
type pointerHandler struct {
area int
active bool
transform ui.TransformOp
transform op.TransformOp
wantsGrab bool
}
@@ -52,7 +52,7 @@ type areaOp struct {
}
type areaNode struct {
trans ui.TransformOp
trans op.TransformOp
next int
area areaOp
}
@@ -64,7 +64,7 @@ const (
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() {
switch opconst.OpType(encOp.Data[0]) {
case opconst.TypePush:
@@ -86,8 +86,8 @@ func (q *pointerQueue) collectHandlers(r *ops.Reader, events *handlerEvents, t u
})
node = len(q.hitTree) - 1
case opconst.TypeTransform:
op := ops.DecodeTransformOp(encOp.Data)
t = t.Multiply(ui.TransformOp(op))
dop := ops.DecodeTransformOp(encOp.Data)
t = t.Multiply(op.TransformOp(dop))
case opconst.TypePointerInput:
op := decodePointerInputOp(encOp.Data, encOp.Refs)
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()
for _, h := range q.handlers {
// Reset handler.
@@ -167,7 +167,7 @@ func (q *pointerQueue) Frame(root *ui.Ops, events *handlerEvents) {
q.hitTree = q.hitTree[:0]
q.areas = q.areas[:0]
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 {
if !h.active {
q.dropHandler(k)
+4 -4
View File
@@ -12,7 +12,7 @@ import (
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/io/profile"
"gioui.org/ui"
"gioui.org/op"
)
// Router is a Queue implementation that routes events from
@@ -53,7 +53,7 @@ func (q *Router) Events(k event.Key) []event.Event {
return events
}
func (q *Router) Frame(ops *ui.Ops) {
func (q *Router) Frame(ops *op.Ops) {
q.handlers.Clear()
q.wakeup = false
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
if opconst.OpType(d[0]) != opconst.TypeInvalidate {
panic("invalid op")
}
var o ui.InvalidateOp
var o op.InvalidateOp
if nanos := bo.Uint64(d[1:]); nanos > 0 {
o.At = time.Unix(0, int64(nanos))
}
+6 -5
View File
@@ -12,6 +12,7 @@ import (
"gioui.org/app/internal/input"
"gioui.org/io/event"
"gioui.org/io/profile"
"gioui.org/op"
"gioui.org/ui"
)
@@ -36,7 +37,7 @@ type Window struct {
in chan event.Event
ack chan struct{}
invalidates chan struct{}
frames chan *ui.Ops
frames chan *op.Ops
stage Stage
animating bool
@@ -99,7 +100,7 @@ func NewWindow(options ...WindowOption) *Window {
out: make(chan event.Event),
ack: make(chan struct{}),
invalidates: make(chan struct{}, 1),
frames: make(chan *ui.Ops),
frames: make(chan *op.Ops),
}
go w.run(opts)
return w
@@ -120,11 +121,11 @@ func (w *Window) Queue() *Queue {
// window contents, input operations declare input handlers,
// and so on. The supplied operations list completely replaces
// the window state from previous calls.
func (w *Window) Update(frame *ui.Ops) {
func (w *Window) Update(frame *op.Ops) {
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
if !w.drawStart.IsZero() {
drawDur = time.Since(w.drawStart)
@@ -265,7 +266,7 @@ func (w *Window) run(opts *windowOptions) {
w.drawStart = time.Now()
w.hasNextFrame = false
w.out <- e
var frame *ui.Ops
var frame *op.Ops
// Wait for either a frame or the ack event,
// which meant that the client didn't draw.
select {
+1 -2
View File
@@ -7,7 +7,6 @@ import (
"image/color"
"log"
"gioui.org/ui"
"gioui.org/app"
"gioui.org/f32"
"gioui.org/paint"
@@ -25,7 +24,7 @@ func main() {
func loop(w *app.Window) error {
background := color.RGBA{255, 0, 0, 255}
ops := new(ui.Ops)
ops := new(op.Ops)
for {
e := <-w.Events()
switch e := e.(type) {
+4 -3
View File
@@ -16,6 +16,7 @@ import (
"gioui.org/internal/fling"
"gioui.org/io/event"
"gioui.org/io/pointer"
"gioui.org/op"
"gioui.org/ui"
)
@@ -95,7 +96,7 @@ const (
var touchSlop = ui.Dp(3)
// 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.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.
func (s *Scroll) Add(ops *ui.Ops) {
func (s *Scroll) Add(ops *op.Ops) {
oph := pointer.InputOp{Key: s, Grab: s.grab}
oph.Add(ops)
if s.flinger.Active() {
ui.InvalidateOp{}.Add(ops)
op.InvalidateOp{}.Add(ops)
}
}
+3 -3
View File
@@ -6,17 +6,17 @@ import (
"encoding/binary"
"math"
"gioui.org/ui"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/op"
)
func DecodeTransformOp(d []byte) ui.TransformOp {
func DecodeTransformOp(d []byte) op.TransformOp {
bo := binary.LittleEndian
if opconst.OpType(d[0]) != opconst.TypeTransform {
panic("invalid op")
}
return ui.TransformOp{}.Offset(f32.Point{
return op.TransformOp{}.Offset(f32.Point{
X: math.Float32frombits(bo.Uint32(d[1:])),
Y: math.Float32frombits(bo.Uint32(d[5:])),
})
+8 -8
View File
@@ -5,15 +5,15 @@ package ops
import (
"encoding/binary"
"gioui.org/ui"
"gioui.org/internal/opconst"
"gioui.org/op"
)
// Reader parses an ops list.
type Reader struct {
pc pc
stack []macro
ops *ui.Ops
ops *op.Ops
}
// EncodedOp represents an encoded op returned by
@@ -26,14 +26,14 @@ type EncodedOp struct {
// Key is a unique key for a given op.
type Key struct {
ops *ui.Ops
ops *op.Ops
pc int
version int
}
// Shadow of ui.MacroOp.
// Shadow of op.MacroOp.
type macroOp struct {
ops *ui.Ops
ops *op.Ops
version int
pc pc
}
@@ -44,7 +44,7 @@ type pc struct {
}
type macro struct {
ops *ui.Ops
ops *op.Ops
retPC pc
endPC pc
}
@@ -58,7 +58,7 @@ type opAux struct {
}
// 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.pc = pc{}
r.ops = ops
@@ -170,7 +170,7 @@ func (m *macroOp) decode(data []byte, refs []interface{}) {
refsIdx := int(int32(bo.Uint32(data[5:])))
version := int(int32(bo.Uint32(data[9:])))
*m = macroOp{
ops: refs[0].(*ui.Ops),
ops: refs[0].(*op.Ops),
pc: pc{
data: dataIdx,
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
ops := new(ui.Ops)
ops := new(op.Ops)
var h *Handler = ...
key.InputOp{Key: h}.Add(ops)
+3 -3
View File
@@ -12,7 +12,7 @@ package key
import (
"gioui.org/internal/opconst"
"gioui.org/io/event"
"gioui.org/ui"
"gioui.org/op"
)
// InputOp declares a handler ready for key events.
@@ -86,7 +86,7 @@ func (m Modifiers) Contain(m2 Modifiers) bool {
return m&m2 == m2
}
func (h InputOp) Add(o *ui.Ops) {
func (h InputOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeKeyInputLen)
data[0] = byte(opconst.TypeKeyInput)
if h.Focus {
@@ -95,7 +95,7 @@ func (h InputOp) Add(o *ui.Ops) {
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[0] = byte(opconst.TypeHideInput)
o.Write(data)
+3 -3
View File
@@ -15,7 +15,7 @@ subsequent InputOp are active.
For example, to set up a rectangular hit area:
var ops ui.Ops
var ops op.Ops
var h *Handler = ...
r := image.Rectangle{...}
@@ -33,8 +33,8 @@ with the most recent node.
For example:
ops := new(ui.Ops)
var stack ui.StackOp
ops := new(op.Ops)
var stack op.StackOp
var h1, h2 *Handler
stack.Push(ops)
+7 -7
View File
@@ -10,7 +10,7 @@ import (
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/io/event"
"gioui.org/ui"
"gioui.org/op"
)
// Event is a pointer event.
@@ -33,7 +33,7 @@ type Event struct {
// outside it.
Hit bool
// 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
// Scroll is the scroll amount, if any.
Scroll f32.Point
@@ -124,21 +124,21 @@ const (
areaEllipse
)
func (op RectAreaOp) Add(ops *ui.Ops) {
func (op RectAreaOp) Add(ops *op.Ops) {
areaOp{
kind: areaRect,
rect: op.Rect,
}.add(ops)
}
func (op EllipseAreaOp) Add(ops *ui.Ops) {
func (op EllipseAreaOp) Add(ops *op.Ops) {
areaOp{
kind: areaEllipse,
rect: op.Rect,
}.add(ops)
}
func (op areaOp) add(o *ui.Ops) {
func (op areaOp) add(o *op.Ops) {
data := make([]byte, opconst.TypeAreaLen)
data[0] = byte(opconst.TypeArea)
data[1] = byte(op.kind)
@@ -150,7 +150,7 @@ func (op areaOp) add(o *ui.Ops) {
o.Write(data)
}
func (h InputOp) Add(o *ui.Ops) {
func (h InputOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypePointerInputLen)
data[0] = byte(opconst.TypePointerInput)
if h.Grab {
@@ -159,7 +159,7 @@ func (h InputOp) Add(o *ui.Ops) {
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[0] = byte(opconst.TypePass)
if op.Pass {
+2 -2
View File
@@ -7,7 +7,7 @@ package profile
import (
"gioui.org/internal/opconst"
"gioui.org/io/event"
"gioui.org/ui"
"gioui.org/op"
)
// Op registers a handler for receiving
@@ -23,7 +23,7 @@ type Event struct {
Timings string
}
func (p Op) Add(o *ui.Ops) {
func (p Op) Add(o *op.Ops) {
data := make([]byte, opconst.TypeProfileLen)
data[0] = byte(opconst.TypeProfile)
o.Write(data, p.Key)
+5 -5
View File
@@ -6,7 +6,7 @@ import (
"image"
"gioui.org/f32"
"gioui.org/ui"
"gioui.org/op"
)
// Flex lays out child elements along an axis,
@@ -21,7 +21,7 @@ type Flex struct {
Alignment Alignment
ctx *Context
macro ui.MacroOp
macro op.MacroOp
mode flexMode
size int
rigidSize int
@@ -33,7 +33,7 @@ type Flex struct {
// FlexChild is the layout result of a call End.
type FlexChild struct {
macro ui.MacroOp
macro op.MacroOp
dims Dimensions
}
@@ -189,9 +189,9 @@ func (f *Flex) Layout(children ...FlexChild) {
cross = f.maxBaseline - b
}
}
var stack ui.StackOp
var stack op.StackOp
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)
stack.Pop()
mainSize += axisMain(f.Axis, dims.Size)
+8 -7
View File
@@ -6,6 +6,7 @@ import (
"image"
"gioui.org/io/event"
"gioui.org/op"
"gioui.org/ui"
)
@@ -53,7 +54,7 @@ type Context struct {
ui.Config
event.Queue
*ui.Ops
*op.Ops
}
const (
@@ -97,7 +98,7 @@ func (c *Context) Reset(cfg ui.Config, cs Constraints) {
c.Dimensions = Dimensions{}
c.Config = cfg
if c.Ops == nil {
c.Ops = new(ui.Ops)
c.Ops = new(op.Ops)
}
c.Ops.Reset()
}
@@ -157,9 +158,9 @@ func (in Inset) Layout(gtx *Context, w Widget) {
if mcs.Height.Max < mcs.Height.Min {
mcs.Height.Max = mcs.Height.Min
}
var stack ui.StackOp
var stack op.StackOp
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)
stack.Pop()
gtx.Dimensions = Dimensions{
@@ -176,7 +177,7 @@ func UniformInset(v ui.Value) Inset {
// Layout a widget.
func (a Align) Layout(gtx *Context, w Widget) {
var macro ui.MacroOp
var macro op.MacroOp
macro.Record(gtx.Ops)
cs := gtx.Constraints
mcs := cs
@@ -204,9 +205,9 @@ func (a Align) Layout(gtx *Context, w Widget) {
case SW, S, SE:
p.Y = sz.Y - dims.Size.Y
}
var stack ui.StackOp
var stack op.StackOp
stack.Push(gtx.Ops)
ui.TransformOp{}.Offset(toPointF(p)).Add(gtx.Ops)
op.TransformOp{}.Offset(toPointF(p)).Add(gtx.Ops)
macro.Add(gtx.Ops)
stack.Pop()
gtx.Dimensions = Dimensions{
+6 -6
View File
@@ -7,13 +7,13 @@ import (
"gioui.org/gesture"
"gioui.org/io/pointer"
"gioui.org/op"
"gioui.org/paint"
"gioui.org/ui"
)
type scrollChild struct {
size image.Point
macro ui.MacroOp
macro op.MacroOp
}
// List displays a subsection of a potentially infinitely
@@ -33,8 +33,8 @@ type List struct {
beforeEnd bool
ctx *Context
macro ui.MacroOp
child ui.MacroOp
macro op.MacroOp
child op.MacroOp
scroll gesture.Scroll
scrollDelta int
@@ -246,10 +246,10 @@ func (l *List) layout() Dimensions {
Min: axisPoint(l.Axis, min, -inf),
Max: axisPoint(l.Axis, max, inf),
}
var stack ui.StackOp
var stack op.StackOp
stack.Push(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)
stack.Pop()
pos += childSize
+5 -5
View File
@@ -5,7 +5,7 @@ package layout
import (
"image"
"gioui.org/ui"
"gioui.org/op"
)
// Stack lays out child elements on top of each other,
@@ -15,7 +15,7 @@ type Stack struct {
// smaller than the available space.
Alignment Direction
macro ui.MacroOp
macro op.MacroOp
constrained bool
ctx *Context
maxSZ image.Point
@@ -24,7 +24,7 @@ type Stack struct {
// StackChild is the layout result of a call to End.
type StackChild struct {
macro ui.MacroOp
macro op.MacroOp
dims Dimensions
}
@@ -99,9 +99,9 @@ func (s *Stack) Layout(children ...StackChild) {
case SW, S, SE:
p.Y = s.maxSZ.Y - sz.Y
}
var stack ui.StackOp
var stack op.StackOp
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)
stack.Pop()
}
+7 -6
View File
@@ -10,10 +10,11 @@ import (
"unicode"
"unicode/utf8"
"gioui.org/ui"
"gioui.org/f32"
"gioui.org/op"
"gioui.org/paint"
"gioui.org/text"
"gioui.org/ui"
"golang.org/x/image/font"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
@@ -34,7 +35,7 @@ type cachedLayout struct {
type cachedPath struct {
active bool
path ui.MacroOp
path op.MacroOp
}
type layoutKey struct {
@@ -128,7 +129,7 @@ func (f *Face) Layout(str string, opts text.LayoutOptions) *text.Layout {
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)
pk := pathKey{
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}
}
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 builder paint.PathBuilder
ops := new(ui.Ops)
ops := new(op.Ops)
builder.Init(ops)
var x fixed.Int26_6
var advIdx int
var m ui.MacroOp
var m op.MacroOp
m.Record(ops)
for _, r := range str.String {
if !unicode.IsSpace(r) {
+115 -1
View File
@@ -1,10 +1,67 @@
// 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 (
"encoding/binary"
"math"
"time"
"gioui.org/f32"
"gioui.org/internal/opconst"
)
@@ -45,6 +102,18 @@ type MacroOp struct {
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 {
data int
refs int
@@ -208,3 +277,48 @@ func (m MacroOp) Add(o *Ops) {
bo.PutUint32(data[9:], uint32(m.version))
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"
"math"
"gioui.org/ui"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/op"
)
// ImageOp sets the material to a section of an
@@ -33,7 +33,7 @@ type PaintOp struct {
Rect f32.Rectangle
}
func (i ImageOp) Add(o *ui.Ops) {
func (i ImageOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeImageLen)
data[0] = byte(opconst.TypeImage)
bo := binary.LittleEndian
@@ -44,7 +44,7 @@ func (i ImageOp) Add(o *ui.Ops) {
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[0] = byte(opconst.TypeColor)
data[1] = c.Color.R
@@ -54,7 +54,7 @@ func (c ColorOp) Add(o *ui.Ops) {
o.Write(data)
}
func (d PaintOp) Add(o *ui.Ops) {
func (d PaintOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypePaintLen)
data[0] = byte(opconst.TypePaint)
bo := binary.LittleEndian
+4 -4
View File
@@ -7,10 +7,10 @@ import (
"math"
"unsafe"
"gioui.org/ui"
"gioui.org/f32"
"gioui.org/internal/opconst"
"gioui.org/internal/path"
"gioui.org/op"
)
// PathBuilder builds and adds a general ClipOp clip path
@@ -19,7 +19,7 @@ import (
// dynamic paths; path data is stored directly in the Ops
// list supplied to Init.
type PathBuilder struct {
ops *ui.Ops
ops *op.Ops
firstVert int
nverts int
maxy float32
@@ -33,7 +33,7 @@ type ClipOp struct {
bounds f32.Rectangle
}
func (p ClipOp) Add(o *ui.Ops) {
func (p ClipOp) Add(o *op.Ops) {
data := make([]byte, opconst.TypeClipLen)
data[0] = byte(opconst.TypeClip)
bo := binary.LittleEndian
@@ -46,7 +46,7 @@ func (p ClipOp) Add(o *ui.Ops) {
// Init the builder and specify the operations list for
// storing the path data and final ClipOp.
func (p *PathBuilder) Init(ops *ui.Ops) {
func (p *PathBuilder) Init(ops *op.Ops) {
p.ops = ops
}
+7 -6
View File
@@ -14,6 +14,7 @@ import (
"gioui.org/io/key"
"gioui.org/io/pointer"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/paint"
"gioui.org/ui"
@@ -33,12 +34,12 @@ type Editor struct {
Submit bool
// Material for drawing the text.
Material ui.MacroOp
Material op.MacroOp
// Hint contains the text displayed to the user when the
// Editor is empty.
Hint string
// Mmaterial is used to draw the hint.
HintMaterial ui.MacroOp
HintMaterial op.MacroOp
oldScale int
blinkStart time.Time
@@ -218,7 +219,7 @@ func (e *Editor) Layout(gtx *layout.Context) {
Width: e.viewWidth(),
Offset: off,
}
var stack ui.StackOp
var stack op.StackOp
stack.Push(gtx.Ops)
// Apply material. Set a default color in case the material is empty.
if e.rr.len() > 0 {
@@ -233,9 +234,9 @@ func (e *Editor) Layout(gtx *layout.Context) {
if !ok {
break
}
var stack ui.StackOp
var stack op.StackOp
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)
paint.PaintOp{Rect: toRectF(clip).Sub(lineOff)}.Add(gtx.Ops)
stack.Pop()
@@ -267,7 +268,7 @@ func (e *Editor) Layout(gtx *layout.Context) {
}
}
if blinking {
redraw := ui.InvalidateOp{At: nextBlink}
redraw := op.InvalidateOp{At: nextBlink}
redraw.Add(gtx.Ops)
}
}
+4 -4
View File
@@ -8,9 +8,9 @@ import (
"image/color"
"unicode/utf8"
"gioui.org/ui"
"gioui.org/f32"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/paint"
"golang.org/x/image/math/fixed"
@@ -22,7 +22,7 @@ type Label struct {
Face Face
// Material is a macro recording the material to draw the
// text. Use a ColorOp for colored text.
Material ui.MacroOp
Material op.MacroOp
// Alignment specify the text alignment.
Alignment Alignment
// Text is the string to draw.
@@ -118,9 +118,9 @@ func (l Label) Layout(gtx *layout.Context) {
break
}
lclip := toRectF(clip).Sub(off)
var stack ui.StackOp
var stack op.StackOp
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)
// Set a default color in case the material is empty.
paint.ColorOp{Color: color.RGBA{A: 0xff}}.Add(gtx.Ops)
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"fmt"
"image"
"gioui.org/ui"
"gioui.org/layout"
"gioui.org/op"
"golang.org/x/image/math/fixed"
)
@@ -50,7 +50,7 @@ type Face interface {
// options.
Layout(s string, opts LayoutOptions) *Layout
// 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
-58
View File
@@ -4,64 +4,6 @@
Package ui defines operations buffers, units and common operations
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
A Value is a value with a Unit attached.
-62
View File
@@ -3,12 +3,7 @@
package ui
import (
"encoding/binary"
"math"
"time"
"gioui.org/f32"
"gioui.org/internal/opconst"
)
// Config define the essential properties of
@@ -19,60 +14,3 @@ type Config interface {
// Px converts a Value to pixels.
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)
}