mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
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:
+21
-16
@@ -52,21 +52,21 @@ type Editor struct {
|
|||||||
// all characters are allowed.
|
// all characters are allowed.
|
||||||
Filter string
|
Filter string
|
||||||
|
|
||||||
eventKey int
|
eventKey int
|
||||||
font text.Font
|
font text.Font
|
||||||
shaper *text.Shaper
|
shaper *text.Shaper
|
||||||
textSize fixed.Int26_6
|
textSize fixed.Int26_6
|
||||||
blinkStart time.Time
|
blinkStart time.Time
|
||||||
focused bool
|
focused bool
|
||||||
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
|
||||||
dims layout.Dimensions
|
dims layout.Dimensions
|
||||||
requestFocus bool
|
requestFocus bool
|
||||||
|
|
||||||
// offIndex is an index of rune index to byte offsets.
|
// offIndex is an index of rune index to byte offsets.
|
||||||
offIndex []offEntry
|
offIndex []offEntry
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-20
@@ -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,27 +126,41 @@ 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} {
|
||||||
defer func() {
|
t.Run(fmt.Sprintf("SingleLine: %v Alignment: %v ZeroMinConstraint: %v", singleLine, alignment, zeroMin), func(t *testing.T) {
|
||||||
if err := recover(); err != nil {
|
defer func() {
|
||||||
t.Error(err)
|
if err := recover(); err != nil {
|
||||||
|
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 = singleLine
|
||||||
e.SingleLine = lineMode
|
e.Alignment = alignment
|
||||||
e.Alignment = alignment
|
e.SetText(sentence)
|
||||||
e.SetText(sentence)
|
e.SetCaret(0, 0)
|
||||||
e.SetCaret(0, 0)
|
dims := e.Layout(gtx, cache, font, fontSize, nil)
|
||||||
e.Layout(gtx, cache, font, fontSize, nil)
|
if dims.Size.X < gtx.Constraints.Min.X || dims.Size.Y < gtx.Constraints.Min.Y {
|
||||||
e.SetCaret(runes, runes)
|
t.Errorf("expected min size %#+v, got %#+v", gtx.Constraints.Min, dims.Size)
|
||||||
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 halfway := float32(gtx.Constraints.Min.X) * .5; !singleLine && alignment == text.Middle && !zeroMin && coords.X != halfway {
|
||||||
t.Errorf("caret coordinates %v exceed constraints %v", coords, gtx.Constraints.Max)
|
t.Errorf("expected caret X to be %f, got %f", halfway, coords.X)
|
||||||
}
|
}
|
||||||
})
|
e.SetCaret(runes, runes)
|
||||||
|
e.Layout(gtx, cache, font, fontSize, nil)
|
||||||
|
coords = e.CaretCoords()
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user