diff --git a/CHANGELOG.md b/CHANGELOG.md index a38e02b4..950b6ac2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,9 @@ had changed in them - which is the gap this file exists to close. ### Fixed +- **The Nodes panel shows its filter once.** The panel drew the table's + filter in its own box and the table drew it again underneath, so typing + showed the text twice with two carets. - **Adding a scheduled send no longer repeats the ones already said.** Any `schedule.add` made every one-shot send whose moment had passed go out again. diff --git a/internal/ui/comp/buttonfloor_test.go b/internal/ui/comp/buttonfloor_test.go index c3f9835f..ab55ac1a 100644 --- a/internal/ui/comp/buttonfloor_test.go +++ b/internal/ui/comp/buttonfloor_test.go @@ -37,3 +37,23 @@ func TestAButtonNeverMeasuresZero(t *testing.T) { } } } + +// A table whose caller draws the filter does not draw it again: one editor +// laid out twice is two boxes with the same text and two carets (#770). +func TestATableDoesNotDrawAFilterItsCallerOwns(t *testing.T) { + th := theme.New(theme.Dark, theme.Default, + text.NewShaper(text.WithCollection(brandfont.Collection()))) + gtx := layout.Context{ + Ops: new(op.Ops), + Metric: unit.Metric{PxPerDp: 1, PxPerSp: 1}, + Constraints: layout.Constraints{Max: image.Pt(400, 100)}, + } + tb := &Table{} + if d := tb.searchRow(th, gtx); d.Size.Y == 0 { + t.Fatal("a table with its own search drew no search box") + } + tb.OwnFilter = true + if d := tb.searchRow(th, gtx); d.Size.Y != 0 { + t.Errorf("the table drew the caller's filter again, %d px tall", d.Size.Y) + } +} diff --git a/internal/ui/comp/table.go b/internal/ui/comp/table.go index 923aab45..741e1a62 100644 --- a/internal/ui/comp/table.go +++ b/internal/ui/comp/table.go @@ -65,6 +65,10 @@ type Table struct { SortDesc bool // FilterHint is what the search box says when it is empty. FilterHint string + // OwnFilter is set by a caller that draws Filter in a box of its own, so + // the table does not draw it again: one editor laid out twice is two boxes + // showing the same text, each with a caret (#770). + OwnFilter bool // OnCell is called when a Menu column's cell is clicked, with the row's // key and the column index. OnCell func(key string, col int) @@ -164,7 +168,7 @@ func (tb *Table) Layout(t *theme.Theme, gtx layout.Context, onSelect func(key st // drew. The filtering worked; there was simply no way to type into it, // so every table in the interface looked as though it had no search. layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return tb.search(t, gtx) + return tb.searchRow(t, gtx) }), layout.Rigid(func(gtx layout.Context) layout.Dimensions { return tb.header(t, gtx) }), layout.Rigid(HRule(t)), diff --git a/internal/ui/comp/tablerows.go b/internal/ui/comp/tablerows.go index 41458744..0c805719 100644 --- a/internal/ui/comp/tablerows.go +++ b/internal/ui/comp/tablerows.go @@ -268,6 +268,14 @@ func numericValue(s string) float64 { return v } +// searchRow is the filter box, unless the caller draws it. +func (tb *Table) searchRow(t *theme.Theme, gtx layout.Context) layout.Dimensions { + if tb.OwnFilter { + return layout.Dimensions{} + } + return tb.search(t, gtx) +} + // search is the filter box above the header. // // Its hint says what it matches on rather than "search", because a box that diff --git a/internal/ui/workbench/nodeview/nodespanel.go b/internal/ui/workbench/nodeview/nodespanel.go index 07ae2825..19772283 100644 --- a/internal/ui/workbench/nodeview/nodespanel.go +++ b/internal/ui/workbench/nodeview/nodespanel.go @@ -86,6 +86,7 @@ func (np *Panel) Draw(t *theme.Theme, gtx layout.Context, s *state.Snapshot) lay // The table's own editor, drawn with the field's chrome. One // widget at one address, which is what focus is keyed on. np.filter.Hint = "filter by name or kind" + np.tbl.OwnFilter = true return np.filter.LayoutEditor(t, gtx, &np.tbl.Filter) }), layout.Rigid(layout.Spacer{Height: t.Sp.S}.Layout),