layout: rename formatState to formatter

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-10-21 00:19:09 +02:00
parent 32d51dd9e6
commit c07b520157
+143 -143
View File
@@ -9,7 +9,7 @@ import (
"gioui.org/unit" "gioui.org/unit"
) )
type formatState struct { type formatter struct {
current int current int
orig string orig string
expr string expr string
@@ -71,7 +71,7 @@ func Format(gtx *Context, format string, widgets ...Widget) {
if format == "" { if format == "" {
return return
} }
state := formatState{ f := formatter{
orig: format, orig: format,
expr: format, expr: format,
} }
@@ -80,185 +80,185 @@ func Format(gtx *Context, format string, widgets ...Widget) {
if _, ok := err.(formatError); !ok { if _, ok := err.(formatError); !ok {
panic(err) panic(err)
} }
pos := len(state.orig) - len(state.expr) pos := len(f.orig) - len(f.expr)
msg := state.orig[:pos] + "✗" + state.orig[pos:] msg := f.orig[:pos] + "✗" + f.orig[pos:]
panic(fmt.Errorf("Format: %s:%d: %s", msg, pos, err)) panic(fmt.Errorf("Format: %s:%d: %s", msg, pos, err))
} }
}() }()
formatExpr(gtx, &state, widgets) formatExpr(gtx, &f, widgets)
} }
func formatExpr(gtx *Context, state *formatState, widgets []Widget) { func formatExpr(gtx *Context, f *formatter, widgets []Widget) {
switch peek(state) { switch peek(f) {
case '_': case '_':
formatWidget(gtx, state, widgets) formatWidget(gtx, f, widgets)
default: default:
formatLayout(gtx, state, widgets) formatLayout(gtx, f, widgets)
} }
} }
func formatLayout(gtx *Context, state *formatState, widgets []Widget) { func formatLayout(gtx *Context, f *formatter, widgets []Widget) {
name := parseName(state) name := parseName(f)
if name == "" { if name == "" {
errorf("missing layout name") errorf("missing layout name")
} }
expect(state, "(") expect(f, "(")
f := func() { fexpr := func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
} }
align, ok := dirFor(name) align, ok := dirFor(name)
if ok { if ok {
Align(align).Layout(gtx, f) Align(align).Layout(gtx, fexpr)
expect(state, ")") expect(f, ")")
return return
} }
switch name { switch name {
case "inset": case "inset":
in := parseInset(gtx, state, widgets) in := parseInset(gtx, f, widgets)
in.Layout(gtx, f) in.Layout(gtx, fexpr)
case "hflex": case "hflex":
formatFlex(gtx, Horizontal, state, widgets) formatFlex(gtx, Horizontal, f, widgets)
case "vflex": case "vflex":
formatFlex(gtx, Vertical, state, widgets) formatFlex(gtx, Vertical, f, widgets)
case "stack": case "stack":
formatStack(gtx, state, widgets) formatStack(gtx, f, widgets)
case "hmax": case "hmax":
cs := gtx.Constraints cs := gtx.Constraints
cs.Width.Min = cs.Width.Max cs.Width.Min = cs.Width.Max
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
case "vmax": case "vmax":
cs := gtx.Constraints cs := gtx.Constraints
cs.Height.Min = cs.Height.Max cs.Height.Min = cs.Height.Max
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
case "max": case "max":
cs := gtx.Constraints cs := gtx.Constraints
cs.Width.Min = cs.Width.Max cs.Width.Min = cs.Width.Max
cs.Height.Min = cs.Height.Max cs.Height.Min = cs.Height.Max
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
case "hmin": case "hmin":
cs := gtx.Constraints cs := gtx.Constraints
cs.Width.Max = cs.Width.Min cs.Width.Max = cs.Width.Min
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
case "vmin": case "vmin":
cs := gtx.Constraints cs := gtx.Constraints
cs.Height.Max = cs.Height.Min cs.Height.Max = cs.Height.Min
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
case "min": case "min":
cs := gtx.Constraints cs := gtx.Constraints
cs.Width.Max = cs.Width.Min cs.Width.Max = cs.Width.Min
cs.Height.Max = cs.Height.Min cs.Height.Max = cs.Height.Min
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
case "hcap": case "hcap":
w := parseValue(state) w := parseValue(f)
expect(state, ",") expect(f, ",")
cs := gtx.Constraints cs := gtx.Constraints
cs.Width.Max = cs.Width.Constrain(gtx.Px(w)) cs.Width.Max = cs.Width.Constrain(gtx.Px(w))
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
case "vcap": case "vcap":
h := parseValue(state) h := parseValue(f)
expect(state, ",") expect(f, ",")
cs := gtx.Constraints cs := gtx.Constraints
cs.Height.Max = cs.Height.Constrain(gtx.Px(h)) cs.Height.Max = cs.Height.Constrain(gtx.Px(h))
ctxLayout(gtx, cs, func() { ctxLayout(gtx, cs, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
default: default:
errorf("invalid layout %q", name) errorf("invalid layout %q", name)
} }
expect(state, ")") expect(f, ")")
} }
func formatWidget(gtx *Context, state *formatState, widgets []Widget) { func formatWidget(gtx *Context, f *formatter, widgets []Widget) {
expect(state, "_") expect(f, "_")
if i, max := state.current, len(widgets)-1; i > max { if i, max := f.current, len(widgets)-1; i > max {
errorf("widget index %d out of bounds [0;%d]", i, max) errorf("widget index %d out of bounds [0;%d]", i, max)
} }
if state.skip == 0 { if f.skip == 0 {
widgets[state.current]() widgets[f.current]()
} }
state.current++ f.current++
} }
func formatStack(gtx *Context, state *formatState, widgets []Widget) { func formatStack(gtx *Context, f *formatter, widgets []Widget) {
st := Stack{} st := Stack{}
// Parse alignment, if present. // Parse alignment, if present.
switch peek(state) { switch peek(f) {
case 'r', 'e', ')': case 'r', 'e', ')':
default: default:
name := parseName(state) name := parseName(f)
align, ok := dirFor(name) align, ok := dirFor(name)
if !ok { if !ok {
errorf("invalid stack alignment: %q", name) errorf("invalid stack alignment: %q", name)
} }
st.Alignment = align st.Alignment = align
expect(state, ",") expect(f, ",")
} }
var children []StackChild var children []StackChild
// First, lay out rigid children. // First, lay out rigid children.
backup := *state backup := *f
loop: loop:
for { for {
switch peek(state) { switch peek(f) {
case ')': case ')':
break loop break loop
case ',': case ',':
expect(state, ",") expect(f, ",")
case 'r': case 'r':
expect(state, "r(") expect(f, "r(")
children = append(children, st.Rigid(gtx, func() { children = append(children, st.Rigid(gtx, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
})) }))
expect(state, ")") expect(f, ")")
case 'e': case 'e':
expect(state, "e(") expect(f, "e(")
state.skip++ f.skip++
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
children = append(children, StackChild{}) children = append(children, StackChild{})
state.skip-- f.skip--
expect(state, ")") expect(f, ")")
default: default:
errorf("invalid flex child") errorf("invalid flex child")
} }
} }
// Then, lay out expanded children. // Then, lay out expanded children.
*state = backup *f = backup
child := 0 child := 0
for { for {
switch peek(state) { switch peek(f) {
case ')': case ')':
if state.skip == 0 { if f.skip == 0 {
st.Layout(gtx, children...) st.Layout(gtx, children...)
} }
return return
case ',': case ',':
expect(state, ",") expect(f, ",")
case 'r': case 'r':
expect(state, "r(") expect(f, "r(")
state.skip++ f.skip++
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
state.skip-- f.skip--
expect(state, ")") expect(f, ")")
child++ child++
case 'e': case 'e':
expect(state, "e(") expect(f, "e(")
children[child] = st.Expand(gtx, func() { children[child] = st.Expand(gtx, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
expect(state, ")") expect(f, ")")
child++ child++
default: default:
errorf("invalid flex child") errorf("invalid flex child")
@@ -266,13 +266,13 @@ loop:
} }
} }
func formatFlex(gtx *Context, axis Axis, state *formatState, widgets []Widget) { func formatFlex(gtx *Context, axis Axis, f *formatter, widgets []Widget) {
fl := Flex{Axis: axis} fl := Flex{Axis: axis}
// Parse alignment, if present. // Parse alignment, if present.
switch peek(state) { switch peek(f) {
case 'r', 'f', ')': case 'r', 'f', ')':
default: default:
name := parseName(state) name := parseName(f)
switch name { switch name {
case "start": case "start":
fl.Alignment = Start fl.Alignment = Start
@@ -285,64 +285,64 @@ func formatFlex(gtx *Context, axis Axis, state *formatState, widgets []Widget) {
default: default:
errorf("invalid flex alignment: %q", name) errorf("invalid flex alignment: %q", name)
} }
expect(state, ",") expect(f, ",")
} }
var children []FlexChild var children []FlexChild
// First, lay out rigid children. // First, lay out rigid children.
backup := *state backup := *f
loop: loop:
for { for {
switch peek(state) { switch peek(f) {
case ')': case ')':
break loop break loop
case ',': case ',':
expect(state, ",") expect(f, ",")
case 'r': case 'r':
expect(state, "r(") expect(f, "r(")
children = append(children, fl.Rigid(gtx, func() { children = append(children, fl.Rigid(gtx, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
})) }))
expect(state, ")") expect(f, ")")
case 'f': case 'f':
expect(state, "f(") expect(f, "f(")
parseFloat(state) parseFloat(f)
expect(state, ",") expect(f, ",")
state.skip++ f.skip++
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
children = append(children, FlexChild{}) children = append(children, FlexChild{})
state.skip-- f.skip--
expect(state, ")") expect(f, ")")
default: default:
errorf("invalid flex child") errorf("invalid flex child")
} }
} }
// Then, lay out flexible children. // Then, lay out flexible children.
*state = backup *f = backup
child := 0 child := 0
for { for {
switch peek(state) { switch peek(f) {
case ')': case ')':
if state.skip == 0 { if f.skip == 0 {
fl.Layout(gtx, children...) fl.Layout(gtx, children...)
} }
return return
case ',': case ',':
expect(state, ",") expect(f, ",")
case 'r': case 'r':
expect(state, "r(") expect(f, "r(")
state.skip++ f.skip++
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
state.skip-- f.skip--
expect(state, ")") expect(f, ")")
child++ child++
case 'f': case 'f':
expect(state, "f(") expect(f, "f(")
weight := parseFloat(state) weight := parseFloat(f)
expect(state, ",") expect(f, ",")
children[child] = fl.Flex(gtx, weight, func() { children[child] = fl.Flex(gtx, weight, func() {
formatExpr(gtx, state, widgets) formatExpr(gtx, f, widgets)
}) })
expect(state, ")") expect(f, ")")
child++ child++
default: default:
errorf("invalid flex child") errorf("invalid flex child")
@@ -350,15 +350,15 @@ loop:
} }
} }
func parseInset(gtx *Context, state *formatState, widgets []Widget) Inset { func parseInset(gtx *Context, f *formatter, widgets []Widget) Inset {
v1 := parseValue(state) v1 := parseValue(f)
if peek(state) == ',' { if peek(f) == ',' {
expect(state, ",") expect(f, ",")
return UniformInset(v1) return UniformInset(v1)
} }
v2 := parseValue(state) v2 := parseValue(f)
if peek(state) == ',' { if peek(f) == ',' {
expect(state, ",") expect(f, ",")
return Inset{ return Inset{
Top: v1, Top: v1,
Right: v2, Right: v2,
@@ -366,9 +366,9 @@ func parseInset(gtx *Context, state *formatState, widgets []Widget) Inset {
Left: v2, Left: v2,
} }
} }
v3 := parseValue(state) v3 := parseValue(f)
if peek(state) == ',' { if peek(f) == ',' {
expect(state, ",") expect(f, ",")
return Inset{ return Inset{
Top: v1, Top: v1,
Right: v2, Right: v2,
@@ -376,8 +376,8 @@ func parseInset(gtx *Context, state *formatState, widgets []Widget) Inset {
Left: v2, Left: v2,
} }
} }
v4 := parseValue(state) v4 := parseValue(f)
expect(state, ",") expect(f, ",")
return Inset{ return Inset{
Top: v1, Top: v1,
Right: v2, Right: v2,
@@ -386,12 +386,12 @@ func parseInset(gtx *Context, state *formatState, widgets []Widget) Inset {
} }
} }
func parseValue(state *formatState) unit.Value { func parseValue(f *formatter) unit.Value {
i := parseFloat(state) i := parseFloat(f)
if len(state.expr) < 2 { if len(f.expr) < 2 {
errorf("missing unit") errorf("missing unit")
} }
u := state.expr[:2] u := f.expr[:2]
var v unit.Value var v unit.Value
switch u { switch u {
case "dp": case "dp":
@@ -403,84 +403,84 @@ func parseValue(state *formatState) unit.Value {
default: default:
errorf("unknown unit") errorf("unknown unit")
} }
state.expr = state.expr[len(u):] f.expr = f.expr[len(u):]
return v return v
} }
func parseName(state *formatState) string { func parseName(f *formatter) string {
i := 0 i := 0
for ; i < len(state.expr); i++ { for ; i < len(f.expr); i++ {
c := state.expr[i] c := f.expr[i]
switch { switch {
case c == '(' || c == ',' || c == ')': case c == '(' || c == ',' || c == ')':
fname := state.expr[:i] fname := f.expr[:i]
state.expr = state.expr[i:] f.expr = f.expr[i:]
return fname return fname
case c < 'a' || 'z' < c: case c < 'a' || 'z' < c:
errorf("invalid character '%c' in layout name", c) errorf("invalid character '%c' in layout name", c)
} }
} }
state.expr = state.expr[i:] f.expr = f.expr[i:]
errorf("missing ( after layout function") errorf("missing ( after layout function")
return "" return ""
} }
func parseFloat(state *formatState) float32 { func parseFloat(f *formatter) float32 {
i := 0 i := 0
for ; i < len(state.expr); i++ { for ; i < len(f.expr); i++ {
c := state.expr[i] c := f.expr[i]
if (c < '0' || c > '9') && c != '.' { if (c < '0' || c > '9') && c != '.' {
break break
} }
} }
expr := state.expr[:i] expr := f.expr[:i]
v, err := strconv.ParseFloat(expr, 32) v, err := strconv.ParseFloat(expr, 32)
if err != nil { if err != nil {
errorf("invalid number %q", expr) errorf("invalid number %q", expr)
} }
state.expr = state.expr[i:] f.expr = f.expr[i:]
return float32(v) return float32(v)
} }
func parseInt(state *formatState) int { func parseInt(f *formatter) int {
i := 0 i := 0
for ; i < len(state.expr); i++ { for ; i < len(f.expr); i++ {
c := state.expr[i] c := f.expr[i]
if c < '0' || c > '9' { if c < '0' || c > '9' {
break break
} }
} }
expr := state.expr[:i] expr := f.expr[:i]
v, err := strconv.Atoi(expr) v, err := strconv.Atoi(expr)
if err != nil { if err != nil {
errorf("invalid number %q", expr) errorf("invalid number %q", expr)
} }
state.expr = state.expr[i:] f.expr = f.expr[i:]
return v return v
} }
func peek(state *formatState) rune { func peek(f *formatter) rune {
skipWhitespace(state) skipWhitespace(f)
if len(state.expr) == 0 { if len(f.expr) == 0 {
errorf("unexpected end") errorf("unexpected end")
} }
return rune(state.expr[0]) return rune(f.expr[0])
} }
func expect(state *formatState, str string) { func expect(f *formatter, str string) {
skipWhitespace(state) skipWhitespace(f)
n := len(str) n := len(str)
if len(state.expr) < n || state.expr[:n] != str { if len(f.expr) < n || f.expr[:n] != str {
errorf("expected %q", str) errorf("expected %q", str)
} }
state.expr = state.expr[n:] f.expr = f.expr[n:]
} }
func skipWhitespace(state *formatState) { func skipWhitespace(f *formatter) {
for len(state.expr) > 0 { for len(f.expr) > 0 {
switch state.expr[0] { switch f.expr[0] {
case '\t', '\n', '\v', '\f', '\r', ' ': case '\t', '\n', '\v', '\f', '\r', ' ':
state.expr = state.expr[1:] f.expr = f.expr[1:]
default: default:
return return
} }