From 99399184acdf9d6e65b98cbcb7b641429fd7a496 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sun, 8 Oct 2023 12:52:30 -0500 Subject: [PATCH] widget: remove assumption that Context.Queue is an interface We're about to make Context.Queue a concrete type, and this change replaces code that relies on Queue being an interface. Signed-off-by: Elias Naur --- widget/editor_test.go | 157 +++++++++++++++++++++----------------- widget/selectable_test.go | 20 +++-- 2 files changed, 98 insertions(+), 79 deletions(-) diff --git a/widget/editor_test.go b/widget/editor_test.go index b341dc3d..ca368b0c 100644 --- a/widget/editor_test.go +++ b/widget/editor_test.go @@ -20,9 +20,9 @@ import ( "gioui.org/font" "gioui.org/font/gofont" "gioui.org/font/opentype" - "gioui.org/io/event" "gioui.org/io/key" "gioui.org/io/pointer" + "gioui.org/io/router" "gioui.org/io/system" "gioui.org/layout" "gioui.org/op" @@ -96,17 +96,14 @@ func assertContents(t *testing.T, e *Editor, contents string, selectionStart, se // TestEditorReadOnly ensures that mouse and keyboard interactions with readonly // editors do nothing but manipulate the text selection. func TestEditorReadOnly(t *testing.T) { + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Constraints: layout.Constraints{ Max: image.Pt(100, 100), }, Locale: english, - } - gtx.Queue = &testQueue{ - events: []event.Event{ - key.FocusEvent{Focus: true}, - }, + Queue: r, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) fontSize := unit.Sp(10) @@ -118,12 +115,20 @@ func TestEditorReadOnly(t *testing.T) { if cStart != cEnd { t.Errorf("unexpected initial caret positions") } - e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + e.Focus() + layoutEditor := func() layout.Dimensions { + return e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + } + layoutEditor() + r.Frame(gtx.Ops) + gtx.Ops.Reset() + layoutEditor() + r.Frame(gtx.Ops) // Select everything. gtx.Ops.Reset() - gtx.Queue = &testQueue{events: []event.Event{key.Event{Name: "A", Modifiers: key.ModShortcut}}} - e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Queue(key.Event{Name: "A", Modifiers: key.ModShortcut}) + layoutEditor() textContent := e.Text() cStart2, cEnd2 := e.Selection() if cStart2 > cEnd2 { @@ -138,7 +143,7 @@ func TestEditorReadOnly(t *testing.T) { // Type some new characters. gtx.Ops.Reset() - gtx.Queue = &testQueue{events: []event.Event{key.EditEvent{Range: key.Range{Start: cStart2, End: cEnd2}, Text: "something else"}}} + r.Queue(key.EditEvent{Range: key.Range{Start: cStart2, End: cEnd2}, Text: "something else"}) e.Update(gtx) textContent2 := e.Text() if textContent2 != textContent { @@ -147,8 +152,8 @@ func TestEditorReadOnly(t *testing.T) { // Try to delete selection. gtx.Ops.Reset() - gtx.Queue = &testQueue{events: []event.Event{key.Event{Name: key.NameDeleteBackward}}} - dims := e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Queue(key.Event{Name: key.NameDeleteBackward}) + dims := layoutEditor() textContent2 = e.Text() if textContent2 != textContent { t.Errorf("readonly editor modified by delete key.Event") @@ -157,14 +162,14 @@ func TestEditorReadOnly(t *testing.T) { // Click and drag from the middle of the first line // to the center. gtx.Ops.Reset() - gtx.Queue = &testQueue{events: []event.Event{ + r.Queue( pointer.Event{ Kind: pointer.Press, Buttons: pointer.ButtonPrimary, Position: f32.Pt(float32(dims.Size.X)*.5, 5), }, pointer.Event{ - Kind: pointer.Drag, + Kind: pointer.Move, Buttons: pointer.ButtonPrimary, Position: layout.FPt(dims.Size).Mul(.5), }, @@ -173,7 +178,7 @@ func TestEditorReadOnly(t *testing.T) { Buttons: pointer.ButtonPrimary, Position: layout.FPt(dims.Size).Mul(.5), }, - }} + ) e.Update(gtx) cStart3, cEnd3 := e.Selection() if cStart3 == cStart2 || cEnd3 == cEnd2 { @@ -496,22 +501,22 @@ func TestEditorLigature(t *testing.T) { func TestEditorDimensions(t *testing.T) { e := new(Editor) - tq := &testQueue{ - events: []event.Event{ - key.EditEvent{Text: "A"}, - }, - } + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Constraints: layout.Constraints{Max: image.Pt(100, 100)}, - Queue: tq, + Queue: r, Locale: english, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) fontSize := unit.Sp(10) font := font.Font{} + e.Focus() + e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) + r.Queue(key.EditEvent{Text: "A"}) dims := e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) - if dims.Size.X == 0 { + if dims.Size.X < 5 { t.Errorf("EditEvent was not reflected in Editor width") } } @@ -882,9 +887,11 @@ f 2 4 6 8 f g 2 4 6 8 g `) + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Locale: english, + Queue: r, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) font := font.Font{} @@ -895,30 +902,30 @@ g 2 4 6 8 g // Layout once with no events; populate e.lines. gtx.Queue = nil e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) - _ = e.Events() // throw away any events from this layout + e.Events() // throw away any events from this layout + e.Focus() + r.Frame(gtx.Ops) + gtx.Queue = r // Build the selection events startPos := e.text.closestToRune(start) endPos := e.text.closestToRune(end) - tq := &testQueue{ - events: []event.Event{ - pointer.Event{ - Buttons: pointer.ButtonPrimary, - Kind: pointer.Press, - Source: pointer.Mouse, - Time: tim, - Position: f32.Pt(textWidth(e, startPos.lineCol.line, 0, startPos.lineCol.col), textBaseline(e, startPos.lineCol.line)), - }, - pointer.Event{ - Kind: pointer.Release, - Source: pointer.Mouse, - Time: tim, - Position: f32.Pt(textWidth(e, endPos.lineCol.line, 0, endPos.lineCol.col), textBaseline(e, endPos.lineCol.line)), - }, + r.Queue( + pointer.Event{ + Buttons: pointer.ButtonPrimary, + Kind: pointer.Press, + Source: pointer.Mouse, + Time: tim, + Position: f32.Pt(textWidth(e, startPos.lineCol.line, 0, startPos.lineCol.col), textBaseline(e, startPos.lineCol.line)), }, - } + pointer.Event{ + Kind: pointer.Release, + Source: pointer.Mouse, + Time: tim, + Position: f32.Pt(textWidth(e, endPos.lineCol.line, 0, endPos.lineCol.col), textBaseline(e, endPos.lineCol.line)), + }, + ) tim += time.Second // Avoid multi-clicks. - gtx.Queue = tq e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) for _, evt := range e.Events() { @@ -980,19 +987,27 @@ func TestSelectMove(t *testing.T) { e := new(Editor) e.SetText(`0123456789`) + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Locale: english, + Queue: r, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) font := font.Font{} fontSize := unit.Sp(10) // Layout once to populate e.lines and get focus. - gtx.Queue = newQueue(key.FocusEvent{Focus: true}) + e.Focus() e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) + // Set up selecton so the Editor key handler filters for all 4 directional keys. + e.SetCaret(3, 6) + gtx.Ops.Reset() + e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) - testKey := func(keyName string) { + for _, keyName := range []string{key.NameLeftArrow, key.NameRightArrow, key.NameUpArrow, key.NameDownArrow} { // Select 345 e.SetCaret(3, 6) if expected, got := "345", e.SelectedText(); expected != got { @@ -1000,18 +1015,15 @@ func TestSelectMove(t *testing.T) { } // Press the key - gtx.Queue = newQueue(key.Event{State: key.Press, Name: keyName}) + r.Queue(key.Event{State: key.Press, Name: keyName}) + gtx.Ops.Reset() e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) if expected, got := "", e.SelectedText(); expected != got { t.Errorf("KeyName %s, expected %q, got %q", keyName, expected, got) } } - - testKey(key.NameLeftArrow) - testKey(key.NameRightArrow) - testKey(key.NameUpArrow) - testKey(key.NameDownArrow) } func TestEditor_Read(t *testing.T) { @@ -1064,17 +1076,22 @@ func TestEditor_MaxLen(t *testing.T) { } e.SetText("2345678") + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Constraints: layout.Exact(image.Pt(100, 100)), - Queue: newQueue( - key.EditEvent{Range: key.Range{Start: 0, End: 2}, Text: "1234"}, - key.SelectionEvent{Start: 4, End: 4}, - ), + Queue: r, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) fontSize := unit.Sp(10) font := font.Font{} + e.Focus() + e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) + r.Queue( + key.EditEvent{Range: key.Range{Start: 0, End: 2}, Text: "1234"}, + key.SelectionEvent{Start: 4, End: 4}, + ) e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) if got, want := e.Text(), "12345678"; got != want { @@ -1095,17 +1112,22 @@ func TestEditor_Filter(t *testing.T) { } e.SetText("2345678") + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Constraints: layout.Exact(image.Pt(100, 100)), - Queue: newQueue( - key.EditEvent{Range: key.Range{Start: 0, End: 0}, Text: "ab1"}, - key.SelectionEvent{Start: 4, End: 4}, - ), + Queue: r, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) fontSize := unit.Sp(10) font := font.Font{} + e.Focus() + e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) + r.Queue( + key.EditEvent{Range: key.Range{Start: 0, End: 0}, Text: "ab1"}, + key.SelectionEvent{Start: 4, End: 4}, + ) e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) if got, want := e.Text(), "12345678"; got != want { @@ -1120,16 +1142,21 @@ func TestEditor_Submit(t *testing.T) { e := new(Editor) e.Submit = true + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Constraints: layout.Exact(image.Pt(100, 100)), - Queue: newQueue( - key.EditEvent{Range: key.Range{Start: 0, End: 0}, Text: "ab1\n"}, - ), + Queue: r, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) fontSize := unit.Sp(10) font := font.Font{} + e.Focus() + e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) + r.Queue( + key.EditEvent{Range: key.Range{Start: 0, End: 0}, Text: "ab1\n"}, + ) e.Layout(gtx, cache, font, fontSize, op.CallOp{}, op.CallOp{}) if got, want := e.Text(), "ab1"; got != want { @@ -1164,15 +1191,3 @@ func textBaseline(e *Editor, lineNum int) float32 { start := e.text.closestToLineCol(lineNum, 0) return float32(start.y) } - -type testQueue struct { - events []event.Event -} - -func newQueue(e ...event.Event) *testQueue { - return &testQueue{events: e} -} - -func (q *testQueue) Events(_ event.Tag) []event.Event { - return q.events -} diff --git a/widget/selectable_test.go b/widget/selectable_test.go index 0e4d751a..bd8b8542 100644 --- a/widget/selectable_test.go +++ b/widget/selectable_test.go @@ -8,6 +8,7 @@ import ( "gioui.org/font" "gioui.org/font/gofont" "gioui.org/io/key" + "gioui.org/io/router" "gioui.org/layout" "gioui.org/op" "gioui.org/text" @@ -33,9 +34,11 @@ func TestSelectableZeroValue(t *testing.T) { // Verify that an existing selection is dismissed when you press arrow keys. func TestSelectableMove(t *testing.T) { + r := new(router.Router) gtx := layout.Context{ Ops: new(op.Ops), Locale: english, + Queue: r, } cache := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection())) fnt := font.Font{} @@ -44,13 +47,18 @@ func TestSelectableMove(t *testing.T) { str := `0123456789` // Layout once to populate e.lines and get focus. - gtx.Queue = newQueue(key.FocusEvent{Focus: true}) s := new(Selectable) + s.Focus() s.SetText(str) + // Set up selection so the Selectable filters for all 4 directional keys. s.Layout(gtx, cache, font.Font{}, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) + s.SetCaret(3, 6) + s.Layout(gtx, cache, font.Font{}, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) - testKey := func(keyName string) { + for _, keyName := range []string{key.NameLeftArrow, key.NameRightArrow, key.NameUpArrow, key.NameDownArrow} { // Select 345 s.SetCaret(3, 6) if start, end := s.Selection(); start != 3 || end != 6 { @@ -61,19 +69,15 @@ func TestSelectableMove(t *testing.T) { } // Press the key - gtx.Queue = newQueue(key.Event{State: key.Press, Name: keyName}) + r.Queue(key.Event{State: key.Press, Name: keyName}) s.SetText(str) s.Layout(gtx, cache, fnt, fontSize, op.CallOp{}, op.CallOp{}) + r.Frame(gtx.Ops) if expected, got := "", s.SelectedText(); expected != got { t.Errorf("KeyName %s, expected %q, got %q", keyName, expected, got) } } - - testKey(key.NameLeftArrow) - testKey(key.NameRightArrow) - testKey(key.NameUpArrow) - testKey(key.NameDownArrow) } func TestSelectableConfigurations(t *testing.T) {