mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 18:05:35 +00:00
ui: move macro recording from Ops to MacroOp
Move the Record and Stop methods from Ops to MacroOp itself. Before this change, Ops.Stop stopped the recording of the most recent macro, which could be a different macro than intended. After this change, there is no such confusion. As a bonus, the Ops API becomes less cluttered. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+4
-3
@@ -14,6 +14,7 @@ type Flex struct {
|
|||||||
MainAxisAlignment MainAxisAlignment
|
MainAxisAlignment MainAxisAlignment
|
||||||
CrossAxisAlignment CrossAxisAlignment
|
CrossAxisAlignment CrossAxisAlignment
|
||||||
|
|
||||||
|
macro ui.MacroOp
|
||||||
ops *ui.Ops
|
ops *ui.Ops
|
||||||
cs Constraints
|
cs Constraints
|
||||||
mode flexMode
|
mode flexMode
|
||||||
@@ -74,7 +75,7 @@ func (f *Flex) begin(mode flexMode) {
|
|||||||
panic("must End before adding a child")
|
panic("must End before adding a child")
|
||||||
}
|
}
|
||||||
f.mode = mode
|
f.mode = mode
|
||||||
f.ops.Record()
|
f.macro.Record(f.ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Flex) Rigid() Constraints {
|
func (f *Flex) Rigid() Constraints {
|
||||||
@@ -107,7 +108,7 @@ func (f *Flex) End(dims Dimens) FlexChild {
|
|||||||
if f.mode <= modeBegun {
|
if f.mode <= modeBegun {
|
||||||
panic("End called without an active child")
|
panic("End called without an active child")
|
||||||
}
|
}
|
||||||
macro := f.ops.Stop()
|
f.macro.Stop()
|
||||||
sz := axisMain(f.Axis, dims.Size)
|
sz := axisMain(f.Axis, dims.Size)
|
||||||
f.size += sz
|
f.size += sz
|
||||||
if f.mode == modeRigid {
|
if f.mode == modeRigid {
|
||||||
@@ -120,7 +121,7 @@ func (f *Flex) End(dims Dimens) FlexChild {
|
|||||||
if b := dims.Baseline; b > f.maxBaseline {
|
if b := dims.Baseline; b > f.maxBaseline {
|
||||||
f.maxBaseline = b
|
f.maxBaseline = b
|
||||||
}
|
}
|
||||||
return FlexChild{macro, dims}
|
return FlexChild{f.macro, dims}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Flex) Layout(children ...FlexChild) Dimens {
|
func (f *Flex) Layout(children ...FlexChild) Dimens {
|
||||||
|
|||||||
+4
-3
@@ -119,6 +119,7 @@ func UniformInset(v ui.Value) Inset {
|
|||||||
type Align struct {
|
type Align struct {
|
||||||
Alignment Direction
|
Alignment Direction
|
||||||
|
|
||||||
|
macro ui.MacroOp
|
||||||
ops *ui.Ops
|
ops *ui.Ops
|
||||||
begun bool
|
begun bool
|
||||||
cs Constraints
|
cs Constraints
|
||||||
@@ -131,7 +132,7 @@ func (a *Align) Begin(ops *ui.Ops, cs Constraints) Constraints {
|
|||||||
a.begun = true
|
a.begun = true
|
||||||
a.ops = ops
|
a.ops = ops
|
||||||
a.cs = cs
|
a.cs = cs
|
||||||
ops.Record()
|
a.macro.Record(ops)
|
||||||
cs.Width.Min = 0
|
cs.Width.Min = 0
|
||||||
cs.Height.Min = 0
|
cs.Height.Min = 0
|
||||||
return cs
|
return cs
|
||||||
@@ -143,7 +144,7 @@ func (a *Align) End(dims Dimens) Dimens {
|
|||||||
}
|
}
|
||||||
a.begun = false
|
a.begun = false
|
||||||
ops := a.ops
|
ops := a.ops
|
||||||
macro := ops.Stop()
|
a.macro.Stop()
|
||||||
sz := dims.Size
|
sz := dims.Size
|
||||||
if sz.X < a.cs.Width.Min {
|
if sz.X < a.cs.Width.Min {
|
||||||
sz.X = a.cs.Width.Min
|
sz.X = a.cs.Width.Min
|
||||||
@@ -166,7 +167,7 @@ func (a *Align) End(dims Dimens) Dimens {
|
|||||||
}
|
}
|
||||||
ui.PushOp{}.Add(ops)
|
ui.PushOp{}.Add(ops)
|
||||||
ui.TransformOp{Transform: ui.Offset(toPointF(p))}.Add(ops)
|
ui.TransformOp{Transform: ui.Offset(toPointF(p))}.Add(ops)
|
||||||
macro.Add(ops)
|
a.macro.Add(ops)
|
||||||
ui.PopOp{}.Add(ops)
|
ui.PopOp{}.Add(ops)
|
||||||
return Dimens{
|
return Dimens{
|
||||||
Size: sz,
|
Size: sz,
|
||||||
|
|||||||
+8
-6
@@ -27,6 +27,8 @@ type List struct {
|
|||||||
// The distance scrolled since last call to Init.
|
// The distance scrolled since last call to Init.
|
||||||
Distance int
|
Distance int
|
||||||
|
|
||||||
|
macro ui.MacroOp
|
||||||
|
child ui.MacroOp
|
||||||
ops *ui.Ops
|
ops *ui.Ops
|
||||||
scroll gesture.Scroll
|
scroll gesture.Scroll
|
||||||
scrollDir int
|
scrollDir int
|
||||||
@@ -70,7 +72,7 @@ func (l *List) Init(ops *ui.Ops, cs Constraints, len int) {
|
|||||||
if l.first > len {
|
if l.first > len {
|
||||||
l.first = len
|
l.first = len
|
||||||
}
|
}
|
||||||
ops.Record()
|
l.macro.Record(ops)
|
||||||
l.Next()
|
l.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +105,7 @@ func (l *List) Next() {
|
|||||||
i = l.len - 1 - i
|
i = l.len - 1 - i
|
||||||
}
|
}
|
||||||
l.index = i
|
l.index = i
|
||||||
l.ops.Record()
|
l.child.Record(l.ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index is the current element index.
|
// Index is the current element index.
|
||||||
@@ -146,8 +148,8 @@ func (l *List) next() (int, bool) {
|
|||||||
|
|
||||||
// Elem completes an element.
|
// Elem completes an element.
|
||||||
func (l *List) Elem(dims Dimens) {
|
func (l *List) Elem(dims Dimens) {
|
||||||
macro := l.ops.Stop()
|
l.child.Stop()
|
||||||
child := scrollChild{dims.Size, macro}
|
child := scrollChild{dims.Size, l.child}
|
||||||
switch l.dir {
|
switch l.dir {
|
||||||
case iterateForward:
|
case iterateForward:
|
||||||
mainSize := axisMain(l.Axis, child.size)
|
mainSize := axisMain(l.Axis, child.size)
|
||||||
@@ -237,9 +239,9 @@ func (l *List) Layout() Dimens {
|
|||||||
l.scroll.Stop()
|
l.scroll.Stop()
|
||||||
}
|
}
|
||||||
dims := axisPoint(l.Axis, mainc.Constrain(pos), maxCross)
|
dims := axisPoint(l.Axis, mainc.Constrain(pos), maxCross)
|
||||||
macro := ops.Stop()
|
l.macro.Stop()
|
||||||
pointer.RectAreaOp{Size: dims}.Add(ops)
|
pointer.RectAreaOp{Size: dims}.Add(ops)
|
||||||
l.scroll.Add(ops)
|
l.scroll.Add(ops)
|
||||||
macro.Add(ops)
|
l.macro.Add(ops)
|
||||||
return Dimens{Size: dims}
|
return Dimens{Size: dims}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -11,6 +11,7 @@ import (
|
|||||||
type Stack struct {
|
type Stack struct {
|
||||||
Alignment Direction
|
Alignment Direction
|
||||||
|
|
||||||
|
macro ui.MacroOp
|
||||||
ops *ui.Ops
|
ops *ui.Ops
|
||||||
constrained bool
|
constrained bool
|
||||||
cs Constraints
|
cs Constraints
|
||||||
@@ -54,7 +55,7 @@ func (s *Stack) begin() {
|
|||||||
panic("must End before adding a child")
|
panic("must End before adding a child")
|
||||||
}
|
}
|
||||||
s.begun = true
|
s.begun = true
|
||||||
s.ops.Record()
|
s.macro.Record(s.ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) Rigid() Constraints {
|
func (s *Stack) Rigid() Constraints {
|
||||||
@@ -71,7 +72,7 @@ func (s *Stack) Expand() Constraints {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) End(dims Dimens) StackChild {
|
func (s *Stack) End(dims Dimens) StackChild {
|
||||||
b := s.ops.Stop()
|
s.macro.Stop()
|
||||||
s.begun = false
|
s.begun = false
|
||||||
if w := dims.Size.X; w > s.maxSZ.X {
|
if w := dims.Size.X; w > s.maxSZ.X {
|
||||||
s.maxSZ.X = w
|
s.maxSZ.X = w
|
||||||
@@ -84,7 +85,7 @@ func (s *Stack) End(dims Dimens) StackChild {
|
|||||||
s.baseline = b
|
s.baseline = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return StackChild{b, dims}
|
return StackChild{s.macro, dims}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stack) Layout(children ...StackChild) Dimens {
|
func (s *Stack) Layout(children ...StackChild) Dimens {
|
||||||
|
|||||||
@@ -234,7 +234,8 @@ func textPath(ppem fixed.Int26_6, f *opentype, str text.String) ui.MacroOp {
|
|||||||
builder.Init(ops)
|
builder.Init(ops)
|
||||||
var x fixed.Int26_6
|
var x fixed.Int26_6
|
||||||
var advIdx int
|
var advIdx int
|
||||||
ops.Record()
|
var m ui.MacroOp
|
||||||
|
m.Record(ops)
|
||||||
for _, r := range str.String {
|
for _, r := range str.String {
|
||||||
if !unicode.IsSpace(r) {
|
if !unicode.IsSpace(r) {
|
||||||
segs, ok := f.LoadGlyph(ppem, r)
|
segs, ok := f.LoadGlyph(ppem, r)
|
||||||
@@ -287,5 +288,6 @@ func textPath(ppem fixed.Int26_6, f *opentype, str text.String) ui.MacroOp {
|
|||||||
advIdx++
|
advIdx++
|
||||||
}
|
}
|
||||||
builder.End()
|
builder.End()
|
||||||
return ops.Stop()
|
m.Stop()
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,16 +2,12 @@ package ui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"gioui.org/ui/internal/ops"
|
"gioui.org/ui/internal/ops"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ops holds a list of serialized Ops.
|
// Ops holds a list of serialized Ops.
|
||||||
type Ops struct {
|
type Ops struct {
|
||||||
// Stack of macro start indices.
|
|
||||||
stack []pc
|
|
||||||
version int
|
version int
|
||||||
// Serialized ops.
|
// Serialized ops.
|
||||||
data []byte
|
data []byte
|
||||||
@@ -61,9 +57,10 @@ type PushOp struct{}
|
|||||||
type PopOp struct{}
|
type PopOp struct{}
|
||||||
|
|
||||||
type MacroOp struct {
|
type MacroOp struct {
|
||||||
ops *Ops
|
recording bool
|
||||||
version int
|
ops *Ops
|
||||||
pc pc
|
version int
|
||||||
|
pc pc
|
||||||
}
|
}
|
||||||
|
|
||||||
type opMacroDef struct {
|
type opMacroDef struct {
|
||||||
@@ -82,14 +79,6 @@ func (p PopOp) Add(o *Ops) {
|
|||||||
o.Write([]byte{byte(ops.TypePop)})
|
o.Write([]byte{byte(ops.TypePop)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record starts recording a macro. Multiple simultaneous
|
|
||||||
// recordings are supported. Stop ends the most recent.
|
|
||||||
func (o *Ops) Record() {
|
|
||||||
o.stack = append(o.stack, o.pc())
|
|
||||||
// Make room for a macro definition. Filled out in Stop.
|
|
||||||
o.Write(make([]byte, ops.TypeMacroDefLen))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (op *opAux) decode(data []byte) {
|
func (op *opAux) decode(data []byte) {
|
||||||
if ops.OpType(data[0]) != ops.TypeAux {
|
if ops.OpType(data[0]) != ops.TypeAux {
|
||||||
panic("invalid op")
|
panic("invalid op")
|
||||||
@@ -115,28 +104,9 @@ func (op *opMacroDef) decode(data []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the most recent recording and return the macro for later
|
|
||||||
// use.
|
|
||||||
func (o *Ops) Stop() MacroOp {
|
|
||||||
if len(o.stack) == 0 {
|
|
||||||
panic(errors.New("not recording a macro"))
|
|
||||||
}
|
|
||||||
start := o.stack[len(o.stack)-1]
|
|
||||||
o.stack = o.stack[:len(o.stack)-1]
|
|
||||||
pc := o.pc()
|
|
||||||
// Write the macro header reserved in Begin.
|
|
||||||
data := o.data[start.data : start.data+ops.TypeMacroDefLen]
|
|
||||||
data[0] = byte(ops.TypeMacroDef)
|
|
||||||
bo := binary.LittleEndian
|
|
||||||
bo.PutUint32(data[1:], uint32(pc.data))
|
|
||||||
bo.PutUint32(data[5:], uint32(pc.refs))
|
|
||||||
return MacroOp{ops: o, pc: start, version: o.version}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the Ops, preparing it for re-use.
|
// Reset the Ops, preparing it for re-use.
|
||||||
func (o *Ops) Reset() {
|
func (o *Ops) Reset() {
|
||||||
o.inAux = false
|
o.inAux = false
|
||||||
o.stack = o.stack[:0]
|
|
||||||
// Leave references to the GC.
|
// Leave references to the GC.
|
||||||
for i := range o.refs {
|
for i := range o.refs {
|
||||||
o.refs[i] = nil
|
o.refs[i] = nil
|
||||||
@@ -191,7 +161,35 @@ func (d *Ops) pc() pc {
|
|||||||
return pc{data: len(d.data), refs: len(d.refs)}
|
return pc{data: len(d.data), refs: len(d.refs)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *MacroOp) decode(data []byte, refs []interface{}) {
|
// Record a macro of operations.
|
||||||
|
func (m *MacroOp) Record(o *Ops) {
|
||||||
|
if m.recording {
|
||||||
|
panic("already recording")
|
||||||
|
}
|
||||||
|
m.recording = true
|
||||||
|
m.ops = o
|
||||||
|
m.pc = o.pc()
|
||||||
|
// Make room for a macro definition. Filled out in Stop.
|
||||||
|
m.ops.Write(make([]byte, ops.TypeMacroDefLen))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop recording the macro.
|
||||||
|
func (m *MacroOp) Stop() {
|
||||||
|
if !m.recording {
|
||||||
|
panic("not recording")
|
||||||
|
}
|
||||||
|
m.recording = false
|
||||||
|
pc := m.ops.pc()
|
||||||
|
// Fill out the macro definition reserved in Record.
|
||||||
|
data := m.ops.data[m.pc.data : m.pc.data+ops.TypeMacroDefLen]
|
||||||
|
data[0] = byte(ops.TypeMacroDef)
|
||||||
|
bo := binary.LittleEndian
|
||||||
|
bo.PutUint32(data[1:], uint32(pc.data))
|
||||||
|
bo.PutUint32(data[5:], uint32(pc.refs))
|
||||||
|
m.version = m.ops.version
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MacroOp) decode(data []byte, refs []interface{}) {
|
||||||
if ops.OpType(data[0]) != ops.TypeMacro {
|
if ops.OpType(data[0]) != ops.TypeMacro {
|
||||||
panic("invalid op")
|
panic("invalid op")
|
||||||
}
|
}
|
||||||
@@ -199,7 +197,7 @@ func (b *MacroOp) decode(data []byte, refs []interface{}) {
|
|||||||
dataIdx := int(bo.Uint32(data[1:]))
|
dataIdx := int(bo.Uint32(data[1:]))
|
||||||
refsIdx := int(bo.Uint32(data[5:]))
|
refsIdx := int(bo.Uint32(data[5:]))
|
||||||
version := int(bo.Uint32(data[9:]))
|
version := int(bo.Uint32(data[9:]))
|
||||||
*b = MacroOp{
|
*m = MacroOp{
|
||||||
ops: refs[0].(*Ops),
|
ops: refs[0].(*Ops),
|
||||||
pc: pc{
|
pc: pc{
|
||||||
data: dataIdx,
|
data: dataIdx,
|
||||||
@@ -209,17 +207,20 @@ func (b *MacroOp) decode(data []byte, refs []interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b MacroOp) Add(o *Ops) {
|
func (m MacroOp) Add(o *Ops) {
|
||||||
if b.ops == nil {
|
if m.recording {
|
||||||
|
panic("a recording is in progress")
|
||||||
|
}
|
||||||
|
if m.ops == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
data := make([]byte, ops.TypeMacroLen)
|
data := make([]byte, ops.TypeMacroLen)
|
||||||
data[0] = byte(ops.TypeMacro)
|
data[0] = byte(ops.TypeMacro)
|
||||||
bo := binary.LittleEndian
|
bo := binary.LittleEndian
|
||||||
bo.PutUint32(data[1:], uint32(b.pc.data))
|
bo.PutUint32(data[1:], uint32(m.pc.data))
|
||||||
bo.PutUint32(data[5:], uint32(b.pc.refs))
|
bo.PutUint32(data[5:], uint32(m.pc.refs))
|
||||||
bo.PutUint32(data[9:], uint32(b.version))
|
bo.PutUint32(data[9:], uint32(m.version))
|
||||||
o.Write(data, b.ops)
|
o.Write(data, m.ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset start reading from the op list.
|
// Reset start reading from the op list.
|
||||||
@@ -230,9 +231,6 @@ func (r *OpsReader) Reset(ops *Ops) {
|
|||||||
if ops == nil {
|
if ops == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if n := len(ops.stack); n > 0 {
|
|
||||||
panic(fmt.Errorf("%d Begin(s) not matched with End", n))
|
|
||||||
}
|
|
||||||
r.ops = ops
|
r.ops = ops
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user