From 9f2bef6b398f538588423affc4dcc905174a5126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 5 Oct 2026 13:01:49 -0400 Subject: [PATCH] Data: review r2 fixes --- carousel.go | 12 +++++- carousel_test.go | 26 ++++++++++++ data_table.go | 16 +++++-- data_table_test.go | 40 +++++++++++++++++- docs/components/071-data-table.md | 2 +- docs/components/080-carousel.md | 2 +- testdata/snapshots/darwin/data_table-dark.png | Bin 14614 -> 14602 bytes .../snapshots/darwin/data_table-light.png | Bin 14162 -> 14151 bytes tree.go | 14 +++++- tree_table.go | 7 ++- tree_table_test.go | 17 ++++++++ tree_test.go | 18 ++++++++ 12 files changed, 143 insertions(+), 11 deletions(-) diff --git a/carousel.go b/carousel.go index 05f4587..2b27b87 100644 --- a/carousel.go +++ b/carousel.go @@ -36,6 +36,8 @@ func (v CarouselView) Changed() bool { return v.changed } type carouselState struct { paused bool next time.Time + // dotFocus leaves the arrows to the dots' focus group. + dotFocus bool } // Carousel shows slide *index of n with previous, next and position controls. @@ -86,6 +88,7 @@ func Carousel(c *ui.Context, index *int, n int, opts CarouselOptions, slide func c.After(st.next.Sub(now)) } switch { + case st.dotFocus: case v.Shortcut(0, ui.KeyLeft): goTo(*index - 1) case v.Shortcut(0, ui.KeyRight): @@ -113,10 +116,17 @@ func Carousel(c *ui.Context, index *int, n int, opts CarouselOptions, slide func } }) ui.Row(c).Justify(ui.Center).AlignItems(ui.Center).Gap(u * 2).Children(func() { + st.dotFocus = false ui.Row(c).Gap(u).FocusGroup(ui.Horizontal).Children(func() { for i := range n { - if carouselDot(c, i, n, i == *index).Clicked() { + dot := carouselDot(c, i, n, i == *index) + if dot.Focused() { + st.dotFocus = true + } + // The arrows move the focus among the dots; the slide follows it. + if dot.Clicked() || dot.Focused() && i != *index { goTo(i) + c.Invalidate() } } }) diff --git a/carousel_test.go b/carousel_test.go index aae5119..59d8435 100644 --- a/carousel_test.go +++ b/carousel_test.go @@ -146,3 +146,29 @@ func TestCarouselEmptyAutoplayKeys(t *testing.T) { t.Fatalf("index %d", index) } } + +func TestCarouselDotsFollowArrows(t *testing.T) { + h := &carouselHarness{} + tt := ui.NewTester(h.view, 420, 280) + for range 10 { + if tt.Focused("Slide 1 of 4") { + break + } + tt.Key(0, ui.KeyTab) + } + if !tt.Focused("Slide 1 of 4") { + t.Fatal("Tab never reached the first dot") + } + tt.Key(0, ui.KeyRight) + if h.index != 1 || !tt.Focused("Slide 2 of 4") { + t.Fatalf("Right: index %d, focus on dot 2 %v", h.index, tt.Focused("Slide 2 of 4")) + } + tt.Key(0, ui.KeyEnter) + if h.index != 1 { + t.Fatalf("Enter on the focused dot moved to %d", h.index) + } + tt.Key(0, ui.KeyEnd) + if h.index != 3 || !tt.Focused("Slide 4 of 4") { + t.Fatalf("End: index %d", h.index) + } +} diff --git a/data_table.go b/data_table.go index 86ca4d6..508b20a 100644 --- a/data_table.go +++ b/data_table.go @@ -137,7 +137,7 @@ func DataTable[R any, K comparable](c *ui.Context, s *DataTableState[K], rows [] v.retry = dataPlaceholder(c, opts.Status, opts.Error, empty, msg(c, "list.empty")) return } - vis, cols := dataTableColumns(c, s, opts) + vis, cols := dataTableColumns(dataRowUnit(c), s, opts) s.rows.Key = func(i int) any { return opts.Key(rows[view[i]]) } s.rows.Label = func(i int) string { return opts.Columns[vis[0]].Text(rows[view[i]]) } s.rows.Selected, s.rows.Sort, s.rows.Columns = &s.cursor, &s.Sort, s.Layout @@ -146,7 +146,8 @@ func DataTable[R any, K comparable](c *ui.Context, s *DataTableState[K], rows [] s.rows.Selection = &s.Selection } // Rows reach the data-row height of the density. - restore := dataSelectTheme(c, d.ControlHeight()/8) + unit := dataRowUnit(c) + restore := dataSelectTheme(c, unit) head := s.Sort e := ui.Table(c, &s.rows, cols, len(view), func(row, col int) { r := rows[view[row]] @@ -265,8 +266,15 @@ func dataTableMenu[R any, K comparable](opts DataTableOptions[R, K]) []tableColu return cols } -func dataTableColumns[R any, K comparable](c *ui.Context, s *DataTableState[K], opts DataTableOptions[R, K]) ([]int, []ui.TableColumn) { - w := Density(c).ControlHeight() +// dataRowUnit is the table spacing unit: rows reach the density's height and fit scaled text. +func dataRowUnit(c *ui.Context) float32 { + // MyGo rows and the header are 8 units high with 1.5 units of padding above and below. + return max(Density(c).ControlHeight()/8, FontSize(c, theme.BodySize)*theme.LineHeight/5) +} + +func dataTableColumns[R any, K comparable](unit float32, s *DataTableState[K], opts DataTableOptions[R, K]) ([]int, []ui.TableColumn) { + // The check box keeps its full hit width inside MyGo's 2.5-unit cell padding. + w := theme.MinHitSize + 5*unit cols := []ui.TableColumn{{ID: dataTableMarkID, Width: w, Fixed: true, Align: ui.Center}} var vis []int for i, col := range opts.Columns { diff --git a/data_table_test.go b/data_table_test.go index dbbe47d..c153dee 100644 --- a/data_table_test.go +++ b/data_table_test.go @@ -26,6 +26,7 @@ type tableHarness struct { changes int sorts int c *ui.Context + density theme.Density seen map[string]int } @@ -44,7 +45,7 @@ func newTableHarness(rows []relic) *tableHarness { } func (h *tableHarness) view(c *ui.Context) { - Use(c, Settings{Mode: Light}) + Use(c, Settings{Mode: Light, Density: h.density}) h.c, h.seen = c, map[string]int{} ui.Column(c).Padding(10).Gap(8).Children(func() { cols := h.opts @@ -363,3 +364,40 @@ func TestDataTableSelectionColors(t *testing.T) { t.Fatalf("selected row background %v, want Selection %v", got, want) } } + +func TestDataTableCompactLargeText(t *testing.T) { + h := newTableHarness(relics()) + h.opts.Multiple = true + h.density = theme.Compact + tt := ui.NewTester(h.view, 600, 700) + tt.SetPreferences(ui.Preferences{TextScale: 2}) + head, _ := tt.Find("Name") + row, _ := tt.Find("Censer") // the first row, labeled by its first column + if head.Y+head.H > row.Y-1 { + t.Fatalf("header text %v runs past the header into row %v", head, row) + } + box, ok := tt.Find("Select row") + if !ok || box.W < theme.MinHitSize || box.H < theme.MinHitSize || box.X < row.X { + t.Fatalf("check box hit area %v in row %v", box, row) + } + if name, _ := tt.Find("Name"); box.X+box.W > name.X { + t.Fatalf("check box %v overlaps the Name column at %v", box, name.X) + } +} + +func TestDataTableCheckBoxHitWidth(t *testing.T) { + for _, d := range []theme.Density{theme.Compact, theme.Default} { + h := newTableHarness(relics()) + h.opts.Multiple = true + h.density = d + tt := ui.NewTester(h.view, 400, 360) + box, _ := tt.Find("Select row") + if box.W < theme.MinHitSize || box.H < theme.MinHitSize { + t.Fatalf("%v: check box hit area %v", d, box) + } + tt.ClickAt(box.X+1, box.Y+box.H/2) // its left edge still toggles + if h.st.Selection.Len() != 1 { + t.Fatalf("%v: left edge of the hit area missed", d) + } + } +} diff --git a/docs/components/071-data-table.md b/docs/components/071-data-table.md index 1a3505e..68ab9d8 100644 --- a/docs/components/071-data-table.md +++ b/docs/components/071-data-table.md @@ -51,7 +51,7 @@ ui.Render(view, 400, 300, 1) ## 状态 -默认、表头悬停、排序箭头(升/降)、行悬停、选中行(Selection 背景 + Text 文字;单选首列 AccentText 菱形,多选首列勾选框)、聚焦(表格外焦点环)、加载、追加加载、失败、空、无匹配。数据行高度不低于当前密度的数据行高(28/36/44 DIP)。 +默认、表头悬停、排序箭头(升/降)、行悬停、选中行(Selection 背景 + Text 文字;单选首列 AccentText 菱形,多选首列勾选框)、聚焦(表格外焦点环)、加载、追加加载、失败、空、无匹配。数据行与表头高度不低于当前密度的数据行高(28/36/44 DIP),并随文本缩放增高;多选勾选框保留完整的 28 × 28 DIP 命中区域。 ## 事件 diff --git a/docs/components/080-carousel.md b/docs/components/080-carousel.md index 51cc923..e9db9e3 100644 --- a/docs/components/080-carousel.md +++ b/docs/components/080-carousel.md @@ -39,7 +39,7 @@ ui.Render(view, 400, 300, 1) ## 键盘操作 - 焦点位于组件内时:←/→ 上一项、下一项;Home/End 第一项、最后一项。 -- 位置指示为一个焦点组:方向键在指示点间移动,Enter/Space 跳转。 +- 位置指示为一个焦点组:方向键在指示点间移动,当前项随焦点切换;此时方向键不再由整个组件处理。 - Tab 依次到达上一项、下一项、位置指示与暂停按钮。 ## 限制 diff --git a/testdata/snapshots/darwin/data_table-dark.png b/testdata/snapshots/darwin/data_table-dark.png index cda8438da141680e2daab7123fae87b5d406a083..87ab18b2e742b86c607798056b32db645a6ef14c 100644 GIT binary patch delta 10469 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 delta 10893 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%0D)Jj|lJ78c`}(ej}pPNya|vvRBL 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 LnnJmpS 0 { + t.end(c, v.changed) + } if v.changed { slog.Debug("mujica: tree changed", "row", t.cursor, "count", s.Selection.Len()) } diff --git a/tree_table.go b/tree_table.go index 6f09ab3..41e4ba7 100644 --- a/tree_table.go +++ b/tree_table.go @@ -124,6 +124,7 @@ func TreeTable[K comparable](c *ui.Context, s *TreeTableState[K], opts TreeTable v.Element = ui.Column(c).MinHeight(0).Gap(d.Unit() * 2) v.Children(func() { if len(opts.Roots) == 0 { + t.clear(&s.Selection) v.retry = dataPlaceholder(c, opts.Status, opts.Error, opts.Empty, msg(c, "list.empty")) return } @@ -137,7 +138,7 @@ func TreeTable[K comparable](c *ui.Context, s *TreeTableState[K], opts TreeTable roots := sorted(opts.Roots, &s.roots) head := s.Sort t.outline.List.Sort, t.outline.List.Columns = &s.Sort, s.Layout - restore := dataSelectTheme(c, d.ControlHeight()/8) + restore := dataSelectTheme(c, dataRowUnit(c)) e := ui.OutlineTable(c, &t.outline, cols, roots, children, func(item K, col int) { if col > 0 { opts.Columns[col].Cell(item) @@ -160,7 +161,9 @@ func TreeTable[K comparable](c *ui.Context, s *TreeTableState[K], opts TreeTable v.retry = dataFooter(c, opts.Status, opts.Error) }) v.sorted = s.Sort != before - t.end(c, v.changed) + if len(opts.Roots) > 0 { + t.end(c, v.changed) + } if v.sorted { slog.Debug("mujica: tree_table sort", "column", s.Sort.Column, "descending", s.Sort.Descending) } diff --git a/tree_table_test.go b/tree_table_test.go index 1013187..8a3c572 100644 --- a/tree_table_test.go +++ b/tree_table_test.go @@ -244,3 +244,20 @@ func TestTreeTableColumnMenuKeyboard(t *testing.T) { t.Fatalf("rows not sorted by size: %s", got) } } + +func TestTreeTableEmptyClearsSelection(t *testing.T) { + h := newTTHarness() + h.opts.Multiple = true + tt := ui.NewTester(h.view, 400, 360) + if err := tt.Click("Organ"); err != nil { + t.Fatal(err) + } + if k, ok := h.st.Selected(); !ok || k != "Organ" || h.st.Selection.Len() != 1 { + t.Fatalf("selected %q %v", k, ok) + } + h.opts.Roots = nil + tt.Frame() + if k, ok := h.st.Selected(); ok || h.st.Selection.Len() != 0 { + t.Fatalf("empty table still selects %q (%d chosen)", k, h.st.Selection.Len()) + } +} diff --git a/tree_test.go b/tree_test.go index 77354b2..e238b3a 100644 --- a/tree_test.go +++ b/tree_test.go @@ -252,3 +252,21 @@ func TestTreeSelectionFollowsLargeReorder(t *testing.T) { t.Fatalf("after reversing: selected %d %v at row %d", k, ok, st.tree.cursor) } } + +func TestTreeEmptyClearsSelection(t *testing.T) { + h := newTreeHarness() + tt := ui.NewTester(h.view, 400, 400) + if err := tt.Click("Sacristy"); err != nil { + t.Fatal(err) + } + h.opts.Roots = nil + tt.Frame() + if k, ok := h.st.Selected(); ok { + t.Fatalf("empty tree still selects %q", k) + } + h.opts.Roots = []string{"Nave", "Crypt", "Sacristy"} + tt.Frame() + if k, ok := h.st.Selected(); ok { + t.Fatalf("selection came back as %q", k) + } +}