Skip to content

Commit

Permalink
Add DataTable.move_cursor (#2479)
Browse files Browse the repository at this point in the history
* Add 'DataTable.move_cursor'.

Related issues: #2472.

* Fix #2471.

* Simplify cursor changes.

* Address review feedback.

Related comments: https://github.com/Textualize/textual/pull/2479\#discussion_r1185016002
  • Loading branch information
rodrigogiraoserrao authored May 8, 2023
1 parent 14850d5 commit 819b2f1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 19 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- run_worker exclusive parameter is now `False` by default https://github.com/Textualize/textual/pull/2470
- Added `always_update` as an optional argument for `reactive.var`


### Added

- Method `DataTable.move_cursor` https://github.com/Textualize/textual/issues/2472

## [0.23.0] - 2023-05-03

### Fixed
Expand Down
47 changes: 40 additions & 7 deletions src/textual/widgets/_data_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ class DataTable(ScrollView, Generic[CellType], can_focus=True):
cursor_coordinate: Reactive[Coordinate] = Reactive(
Coordinate(0, 0), repaint=False, always_update=True
)
"""Current cursor [`Coordinate`][textual.coordinate.Coordinate].
This can be set programmatically or changed via the method
[`move_cursor`][textual.widgets.DataTable.move_cursor].
"""
hover_coordinate: Reactive[Coordinate] = Reactive(
Coordinate(0, 0), repaint=False, always_update=True
)
Expand Down Expand Up @@ -953,7 +958,41 @@ def watch_cursor_coordinate(
elif self.cursor_type == "column":
self.refresh_column(old_coordinate.column)
self._highlight_column(new_coordinate.column)
self._scroll_cursor_into_view()
# If the coordinate was changed via `move_cursor`, give priority to its
# scrolling because it may be animated.
self.call_next(self._scroll_cursor_into_view)

def move_cursor(
self,
*,
row: int | None = None,
column: int | None = None,
animate: bool = False,
) -> None:
"""Move the cursor to the given position.
Example:
```py
datatable = app.query_one(DataTable)
datatable.move_cursor(row=4, column=6)
# datatable.cursor_coordinate == Coordinate(4, 6)
datatable.move_cursor(row=3)
# datatable.cursor_coordinate == Coordinate(3, 6)
```
Args:
row: The new row to move the cursor to.
column: The new column to move the cursor to.
animate: Whether to animate the change of coordinates.
"""
cursor_row, cursor_column = self.cursor_coordinate
if row is not None:
cursor_row = row
if column is not None:
cursor_column = column
destination = Coordinate(cursor_row, cursor_column)
self.cursor_coordinate = destination
self._scroll_cursor_into_view(animate=animate)

def _highlight_coordinate(self, coordinate: Coordinate) -> None:
"""Apply highlighting to the cell at the coordinate, and post event."""
Expand Down Expand Up @@ -2055,7 +2094,6 @@ def action_page_down(self) -> None:
self.cursor_coordinate = Coordinate(
row_index + rows_to_scroll - 1, column_index
)
self._scroll_cursor_into_view()
else:
super().action_page_down()

Expand All @@ -2079,7 +2117,6 @@ def action_page_up(self) -> None:
self.cursor_coordinate = Coordinate(
row_index - rows_to_scroll + 1, column_index
)
self._scroll_cursor_into_view()
else:
super().action_page_up()

Expand All @@ -2090,7 +2127,6 @@ def action_scroll_home(self) -> None:
if self.show_cursor and (cursor_type == "cell" or cursor_type == "row"):
row_index, column_index = self.cursor_coordinate
self.cursor_coordinate = Coordinate(0, column_index)
self._scroll_cursor_into_view()
else:
super().action_scroll_home()

Expand All @@ -2101,7 +2137,6 @@ def action_scroll_end(self) -> None:
if self.show_cursor and (cursor_type == "cell" or cursor_type == "row"):
row_index, column_index = self.cursor_coordinate
self.cursor_coordinate = Coordinate(self.row_count - 1, column_index)
self._scroll_cursor_into_view()
else:
super().action_scroll_end()

Expand All @@ -2110,7 +2145,6 @@ def action_cursor_up(self) -> None:
cursor_type = self.cursor_type
if self.show_cursor and (cursor_type == "cell" or cursor_type == "row"):
self.cursor_coordinate = self.cursor_coordinate.up()
self._scroll_cursor_into_view()
else:
# If the cursor doesn't move up (e.g. column cursor can't go up),
# then ensure that we instead scroll the DataTable.
Expand All @@ -2121,7 +2155,6 @@ def action_cursor_down(self) -> None:
cursor_type = self.cursor_type
if self.show_cursor and (cursor_type == "cell" or cursor_type == "row"):
self.cursor_coordinate = self.cursor_coordinate.down()
self._scroll_cursor_into_view()
else:
super().action_scroll_down()

Expand Down
35 changes: 23 additions & 12 deletions tests/test_data_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -996,23 +996,34 @@ def test_key_string_lookup():
async def test_scrolling_cursor_into_view():
"""Regression test for https://github.com/Textualize/textual/issues/2459"""

class TableApp(App):
class ScrollingApp(DataTableApp):
CSS = "DataTable { height: 100%; }"

def compose(self):
yield DataTable()

def on_mount(self) -> None:
table = self.query_one(DataTable)
table.add_column("n")
table.add_rows([(n,) for n in range(300)])

def key_c(self):
self.query_one(DataTable).cursor_coordinate = Coordinate(200, 0)

app = TableApp()
app = ScrollingApp()

async with app.run_test() as pilot:
table = app.query_one(DataTable)
table.add_column("n")
table.add_rows([(n,) for n in range(300)])

await pilot.press("c")
await pilot.pause()
assert app.query_one(DataTable).scroll_y > 100
assert table.scroll_y > 100


async def test_move_cursor():
app = DataTableApp()

async with app.run_test():
table = app.query_one(DataTable)
table.add_columns(*"These are some columns in your nice table".split())
table.add_rows(["These are some columns in your nice table".split()] * 10)

table.move_cursor(row=4, column=6)
assert table.cursor_coordinate == Coordinate(4, 6)
table.move_cursor(row=3)
assert table.cursor_coordinate == Coordinate(3, 6)
table.move_cursor(column=3)
assert table.cursor_coordinate == Coordinate(3, 3)

0 comments on commit 819b2f1

Please sign in to comment.