widget: track minWidth of editor for alignment

This commit extends the editor to keep track of its own minimum constraint
and to provide that value to the text shaper for the purpose of aligning
text. Without this, the shaper does not know how much of the width of the
editor to use for alignment purposes.

Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
Chris Waldon
2022-12-19 10:09:00 -05:00
committed by Elias Naur
parent 5d1d1df206
commit fe5878bc63
2 changed files with 55 additions and 36 deletions
+7 -2
View File
@@ -61,7 +61,7 @@ type Editor struct {
rr editBuffer rr editBuffer
maskReader maskReader maskReader maskReader
lastMask rune lastMask rune
maxWidth int maxWidth, minWidth int
viewSize image.Point viewSize image.Point
valid bool valid bool
regions []region regions []region
@@ -547,10 +547,15 @@ func (e *Editor) Layout(gtx layout.Context, lt *text.Shaper, font text.Font, siz
if e.SingleLine { if e.SingleLine {
maxWidth = math.MaxInt maxWidth = math.MaxInt
} }
minWidth := gtx.Constraints.Min.X
if maxWidth != e.maxWidth { if maxWidth != e.maxWidth {
e.maxWidth = maxWidth e.maxWidth = maxWidth
e.invalidate() e.invalidate()
} }
if minWidth != e.minWidth {
e.minWidth = minWidth
e.invalidate()
}
if lt != e.shaper { if lt != e.shaper {
e.shaper = lt e.shaper = lt
e.invalidate() e.invalidate()
@@ -891,7 +896,7 @@ func (e *Editor) layoutText(lt *text.Shaper) {
Font: e.font, Font: e.font,
PxPerEm: e.textSize, PxPerEm: e.textSize,
Alignment: e.Alignment, Alignment: e.Alignment,
}, 0, e.maxWidth, e.locale, r) }, e.minWidth, e.maxWidth, e.locale, r)
for glyph, ok := it.processGlyph(lt.NextGlyph()); ok; glyph, ok = it.processGlyph(lt.NextGlyph()) { for glyph, ok := it.processGlyph(lt.NextGlyph()); ok; glyph, ok = it.processGlyph(lt.NextGlyph()) {
e.index.Glyph(glyph) e.index.Glyph(glyph)
} }
+20 -6
View File
@@ -115,7 +115,7 @@ func TestEditorZeroDimensions(t *testing.T) {
func TestEditorConfigurations(t *testing.T) { func TestEditorConfigurations(t *testing.T) {
gtx := layout.Context{ gtx := layout.Context{
Ops: new(op.Ops), Ops: new(op.Ops),
Constraints: layout.Exact(image.Pt(100, 100)), Constraints: layout.Exact(image.Pt(300, 300)),
Locale: english, Locale: english,
} }
cache := text.NewShaper(gofont.Collection()) cache := text.NewShaper(gofont.Collection())
@@ -126,29 +126,43 @@ func TestEditorConfigurations(t *testing.T) {
// Ensure that both ends of the text are reachable in all permutations // Ensure that both ends of the text are reachable in all permutations
// of settings that influence layout. // of settings that influence layout.
for _, lineMode := range []bool{true, false} { for _, singleLine := range []bool{true, false} {
for _, alignment := range []text.Alignment{text.Start, text.Middle, text.End} { for _, alignment := range []text.Alignment{text.Start, text.Middle, text.End} {
t.Run(fmt.Sprintf("SingleLine: %v Alignment: %v", lineMode, alignment), func(t *testing.T) { for _, zeroMin := range []bool{true, false} {
t.Run(fmt.Sprintf("SingleLine: %v Alignment: %v ZeroMinConstraint: %v", singleLine, alignment, zeroMin), func(t *testing.T) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
t.Error(err) t.Error(err)
} }
}() }()
if zeroMin {
gtx.Constraints.Min = image.Point{}
} else {
gtx.Constraints.Min = gtx.Constraints.Max
}
e := new(Editor) e := new(Editor)
e.SingleLine = lineMode e.SingleLine = singleLine
e.Alignment = alignment e.Alignment = alignment
e.SetText(sentence) e.SetText(sentence)
e.SetCaret(0, 0) e.SetCaret(0, 0)
e.Layout(gtx, cache, font, fontSize, nil) dims := e.Layout(gtx, cache, font, fontSize, nil)
if dims.Size.X < gtx.Constraints.Min.X || dims.Size.Y < gtx.Constraints.Min.Y {
t.Errorf("expected min size %#+v, got %#+v", gtx.Constraints.Min, dims.Size)
}
coords := e.CaretCoords()
if halfway := float32(gtx.Constraints.Min.X) * .5; !singleLine && alignment == text.Middle && !zeroMin && coords.X != halfway {
t.Errorf("expected caret X to be %f, got %f", halfway, coords.X)
}
e.SetCaret(runes, runes) e.SetCaret(runes, runes)
e.Layout(gtx, cache, font, fontSize, nil) e.Layout(gtx, cache, font, fontSize, nil)
coords := e.CaretCoords() coords = e.CaretCoords()
if int(coords.X) > gtx.Constraints.Max.X || int(coords.Y) > gtx.Constraints.Max.Y { if int(coords.X) > gtx.Constraints.Max.X || int(coords.Y) > gtx.Constraints.Max.Y {
t.Errorf("caret coordinates %v exceed constraints %v", coords, gtx.Constraints.Max) t.Errorf("caret coordinates %v exceed constraints %v", coords, gtx.Constraints.Max)
} }
}) })
} }
} }
}
} }
func TestEditor(t *testing.T) { func TestEditor(t *testing.T) {