diff --git a/widget/editor.go b/widget/editor.go index 9bc656fa..31045f25 100644 --- a/widget/editor.go +++ b/widget/editor.go @@ -462,8 +462,8 @@ func (e *Editor) Focused() bool { return e.focused } -// Layout lays out the editor. -func (e *Editor) Layout(gtx layout.Context, sh text.Shaper, font text.Font, size unit.Value) layout.Dimensions { +// Layout lays out the editor. If content is not nil, it is laid out on top. +func (e *Editor) Layout(gtx layout.Context, sh text.Shaper, font text.Font, size unit.Value, content layout.Widget) layout.Dimensions { textSize := fixed.I(gtx.Px(size)) if e.font != font || e.textSize != textSize { e.invalidate() @@ -497,10 +497,10 @@ func (e *Editor) Layout(gtx layout.Context, sh text.Shaper, font text.Font, size } e.makeValid() - return e.layout(gtx) + return e.layout(gtx, content) } -func (e *Editor) layout(gtx layout.Context) layout.Dimensions { +func (e *Editor) layout(gtx layout.Context, content layout.Widget) layout.Dimensions { // Adjust scrolling for new viewport and layout. e.scrollRel(0, 0) @@ -576,6 +576,9 @@ func (e *Editor) layout(gtx layout.Context) layout.Dimensions { e.caret.on = e.focused && (!blinking || dt%timePerBlink < timePerBlink/2) } + if content != nil { + content(gtx) + } return layout.Dimensions{Size: e.viewSize, Baseline: e.dims.Baseline} } diff --git a/widget/editor_test.go b/widget/editor_test.go index 56e76311..d66192eb 100644 --- a/widget/editor_test.go +++ b/widget/editor_test.go @@ -39,7 +39,7 @@ func TestEditor(t *testing.T) { e.SetCaret(0, 0) // shouldn't panic assertCaret(t, e, 0, 0, 0) e.SetText("æbc\naøå•") - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) assertCaret(t, e, 0, 0, 0) e.moveEnd(selectionClear) assertCaret(t, e, 0, 3, len("æbc")) @@ -65,12 +65,12 @@ func TestEditor(t *testing.T) { e.MoveCaret(-3, -3) assertCaret(t, e, 1, 1, len("æbc\na")) e.Mask = '*' - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) assertCaret(t, e, 1, 1, len("æbc\na")) e.MoveCaret(-3, -3) assertCaret(t, e, 0, 2, len("æb")) e.Mask = '\U0001F92B' - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) e.moveEnd(selectionClear) assertCaret(t, e, 0, 3, len("æbc")) @@ -99,7 +99,7 @@ func TestEditorDimensions(t *testing.T) { cache := text.NewCache(gofont.Collection()) fontSize := unit.Px(10) font := text.Font{} - dims := e.Layout(gtx, cache, font, fontSize) + dims := e.Layout(gtx, cache, font, fontSize, nil) if dims.Size.X == 0 { t.Errorf("EditEvent was not reflected in Editor width") } @@ -145,7 +145,7 @@ func TestEditorCaretConsistency(t *testing.T) { e := &Editor{ Alignment: a, } - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) consistent := func() error { t.Helper() @@ -167,7 +167,7 @@ func TestEditorCaretConsistency(t *testing.T) { switch mutation { case setText: e.SetText(str) - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) case moveRune: e.MoveCaret(int(distance), int(distance)) case moveLine: @@ -232,7 +232,7 @@ func TestEditorMoveWord(t *testing.T) { fontSize := unit.Px(10) font := text.Font{} e.SetText(t) - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) return e } for ii, tt := range tests { @@ -314,7 +314,7 @@ func TestEditorDeleteWord(t *testing.T) { fontSize := unit.Px(10) font := text.Font{} e.SetText(t) - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) return e } for ii, tt := range tests { @@ -367,7 +367,7 @@ g123456789g selected := func(start, end int) string { // Layout once with no events; populate e.lines. gtx.Queue = nil - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) _ = e.Events() // throw away any events from this layout // Build the selection events @@ -389,7 +389,7 @@ g123456789g } gtx.Queue = tq - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) for _, evt := range e.Events() { switch evt.(type) { case SelectEvent: @@ -428,7 +428,7 @@ g123456789g gtx.Constraints = layout.Exact(image.Pt(36, 36)) // Keep existing selection gtx.Queue = nil - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) if e.caret.end.lineCol != tst.startPos || e.caret.start.lineCol != tst.endPos { t.Errorf("Test %d pt2: Expected %#v, %#v; got %#v, %#v", @@ -454,7 +454,7 @@ func TestSelectMove(t *testing.T) { // Layout once to populate e.lines and get focus. gtx.Queue = newQueue(key.FocusEvent{Focus: true}) - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) testKey := func(keyName string) { // Select 345 @@ -465,7 +465,7 @@ func TestSelectMove(t *testing.T) { // Press the key gtx.Queue = newQueue(key.Event{State: key.Press, Name: keyName}) - e.Layout(gtx, cache, font, fontSize) + e.Layout(gtx, cache, font, fontSize, nil) if expected, got := "", e.SelectedText(); expected != got { t.Errorf("KeyName %s, expected %q, got %q", keyName, expected, got) diff --git a/widget/material/editor.go b/widget/material/editor.go index 690793a8..ff713e20 100644 --- a/widget/material/editor.go +++ b/widget/material/editor.go @@ -58,20 +58,22 @@ func (e EditorStyle) Layout(gtx layout.Context) layout.Dimensions { if h := dims.Size.Y; gtx.Constraints.Min.Y < h { gtx.Constraints.Min.Y = h } - dims = e.Editor.Layout(gtx, e.shaper, e.Font, e.TextSize) - disabled := gtx.Queue == nil - if e.Editor.Len() > 0 { - paint.ColorOp{Color: blendDisabledColor(disabled, e.SelectionColor)}.Add(gtx.Ops) - e.Editor.PaintSelection(gtx) - paint.ColorOp{Color: blendDisabledColor(disabled, e.Color)}.Add(gtx.Ops) - e.Editor.PaintText(gtx) - } else { - call.Add(gtx.Ops) - } - if !disabled { - paint.ColorOp{Color: e.Color}.Add(gtx.Ops) - e.Editor.PaintCaret(gtx) - } + dims = e.Editor.Layout(gtx, e.shaper, e.Font, e.TextSize, func(gtx layout.Context) layout.Dimensions { + disabled := gtx.Queue == nil + if e.Editor.Len() > 0 { + paint.ColorOp{Color: blendDisabledColor(disabled, e.SelectionColor)}.Add(gtx.Ops) + e.Editor.PaintSelection(gtx) + paint.ColorOp{Color: blendDisabledColor(disabled, e.Color)}.Add(gtx.Ops) + e.Editor.PaintText(gtx) + } else { + call.Add(gtx.Ops) + } + if !disabled { + paint.ColorOp{Color: e.Color}.Add(gtx.Ops) + e.Editor.PaintCaret(gtx) + } + return dims + }) return dims }