Skip to content

Commit

Permalink
Export table scrolling methods
Browse files Browse the repository at this point in the history
 - ScrollTo, ScrollToEnd, ScrollToStart
 - addresses fyne-io#1892
  • Loading branch information
nealmcc committed Jul 10, 2021
1 parent 8619fce commit 19457da
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 0 deletions.
44 changes: 44 additions & 0 deletions widget/table.go
Expand Up @@ -151,6 +151,50 @@ func (t *Table) UnselectAll() {
}
}

// ScrollTo will scroll to the given cell without changing the selection.
// Attempting to scroll beyond the limits of the table will scroll to
// the edge of the table instead.
//
// Since: 2.1
func (t *Table) ScrollTo(id TableCellID) {
if t.Length == nil {
return
}

rows, cols := t.Length()
if id.Row >= rows {
id.Row = rows - 1
}

if id.Col >= cols {
id.Col = cols - 1
}

t.scrollTo(id)
}

// ScrollToEnd will scroll to the last cell in the table
//
// Since: 2.1
func (t *Table) ScrollToEnd() {
if t.Length == nil {
return
}

rows, cols := t.Length()
t.scrollTo(TableCellID{
Row: rows - 1,
Col: cols - 1,
})
}

// ScrollToStart will scroll to the first cell in the table
//
// Since: 2.1
func (t *Table) ScrollToStart() {
t.scrollTo(TableCellID{0, 0})
}

func (t *Table) scrollTo(id TableCellID) {
if t.scroll == nil {
return
Expand Down
159 changes: 159 additions & 0 deletions widget/table_test.go
Expand Up @@ -189,6 +189,165 @@ func TestTable_Refresh(t *testing.T) {
assert.Equal(t, "replaced", cellRenderer.(*tableCellsRenderer).Objects()[7].(*Label).Text)
}

func TestTable_ScrollTo(t *testing.T) {
test.NewApp()
defer test.NewApp()

// for this test the separator thickness is 0
test.ApplyTheme(t, &separatorThicknessZeroTheme{test.Theme()})

// we will test a 20 row x 5 column table where each cell is 50x50
const (
maxRows int = 20
maxCols int = 5
width float32 = 50
height float32 = 50
)

templ := canvas.NewRectangle(color.Gray16{})
templ.SetMinSize(fyne.Size{Width: width, Height: height})

table := NewTable(
func() (int, int) { return maxRows, maxCols },
func() fyne.CanvasObject { return templ },
func(TableCellID, fyne.CanvasObject) {})

w := test.NewWindow(table)
defer w.Close()

// these position expectations have a built-in assumption that the window
// is smaller than the size of a single table cell.
expectedOffset := func(row, col float32) fyne.Position {
return fyne.Position{
X: col * width,
Y: row * height,
}
}

tt := []struct {
name string
in TableCellID
want fyne.Position
}{
{
"row 0, col 0",
TableCellID{},
expectedOffset(0, 0),
},
{
"row 0, col 1",
TableCellID{Row: 0, Col: 1},
expectedOffset(0, 1),
},
{
"row 1, col 0",
TableCellID{Row: 1, Col: 0},
expectedOffset(1, 0),
},
{
"row 1, col 1",
TableCellID{Row: 1, Col: 1},
expectedOffset(1, 1),
},
{
"second last element",
TableCellID{Row: maxRows - 2, Col: maxCols - 2},
expectedOffset(float32(maxRows)-2, float32(maxCols)-2),
},
{
"last element",
TableCellID{Row: maxRows - 1, Col: maxCols - 1},
expectedOffset(float32(maxRows)-1, float32(maxCols)-1),
},
{
"row 0, col 0 (scrolling backwards)",
TableCellID{},
expectedOffset(0, 0),
},
{
"row 99, col 99 (scrolling beyond the end)",
TableCellID{Row: 99, Col: 99},
expectedOffset(float32(maxRows)-1, float32(maxCols)-1),
},
{
"row -1, col -1 (scrolling before the start)",
TableCellID{Row: -1, Col: -1},
expectedOffset(0, 0),
},
}

for _, tc := range tt {
tc := tc
t.Run(tc.name, func(t *testing.T) {
table.ScrollTo(tc.in)
assert.Equal(t, tc.want, table.offset)
assert.Equal(t, tc.want, table.scroll.Offset)
})
}
}

func TestTable_ScrollToEnd(t *testing.T) {
test.NewApp()
defer test.NewApp()

// we will test a 20 row x 5 column table where each cell is 50x50
// this table has a separator thickness of 1
const (
maxRows int = 20
maxCols int = 5
width float32 = 50
height float32 = 50
)

templ := canvas.NewRectangle(color.Gray16{})
templ.SetMinSize(fyne.Size{Width: width, Height: height})

table := NewTable(
func() (int, int) { return maxRows, maxCols },
func() fyne.CanvasObject { return templ },
func(TableCellID, fyne.CanvasObject) {})

w := test.NewWindow(table)
defer w.Close()

table.ScrollToEnd()

// element size of 50, plus separator thickness of 1
want := fyne.Position{X: 4 * (50 + 1), Y: 19 * (50 + 1)}
assert.Equal(t, want, table.offset)
assert.Equal(t, want, table.scroll.Offset)
}

func TestTable_ScrollToStart(t *testing.T) {
test.NewApp()
defer test.NewApp()

const (
maxRows int = 20
maxCols int = 5
width float32 = 50
height float32 = 50
)

templ := canvas.NewRectangle(color.Gray16{})
templ.SetMinSize(fyne.Size{Width: width, Height: height})

table := NewTable(
func() (int, int) { return maxRows, maxCols },
func() fyne.CanvasObject { return templ },
func(TableCellID, fyne.CanvasObject) {})

w := test.NewWindow(table)
defer w.Close()

table.scrollTo(TableCellID{12, 3})
table.ScrollToStart()

want := fyne.Position{}
assert.Equal(t, want, table.offset)
assert.Equal(t, want, table.scroll.Offset)
}

func TestTable_Selection(t *testing.T) {
test.NewApp()
defer test.NewApp()
Expand Down

0 comments on commit 19457da

Please sign in to comment.