Skip to content

Commit

Permalink
Merge pull request #5052 from Textualize/tree-fix
Browse files Browse the repository at this point in the history
fix tree issues
  • Loading branch information
willmcgugan authored Sep 25, 2024
2 parents 0deb1dc + 955d6aa commit 7be8a31
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 328 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Add

- Added `x_axis` and `y_axis` parameters to `Widget.scroll_to_region` https://github.com/Textualize/textual/pull/5047
- Added `Tree.move_cursor_to_line` https://github.com/Textualize/textual/pull/5052

### Changed

- Tree will no longer scroll the X axis when moving the cursor https://github.com/Textualize/textual/pull/5047
- DirectoryTree will no longer select the first node https://github.com/Textualize/textual/pull/5052

### Fixed

- Fixed widgets occasionally not getting Resize events https://github.com/Textualize/textual/pull/5048
- Fixed tree regression https://github.com/Textualize/textual/pull/5052

## [0.80.1] - 2024-09-24

Expand Down
5 changes: 4 additions & 1 deletion src/textual/widgets/_directory_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,12 @@ async def watch_path(self) -> None:
If the path is changed the directory tree will be repopulated using
the new value as the root.
"""
has_cursor = self.cursor_node is not None
self.reset_node(self.root, str(self.path), DirEntry(self.PATH(self.path)))
await self.reload()
self.move_cursor(self.root, animate=False)
if has_cursor:
self.cursor_line = 0
self.scroll_to(0, 0, animate=False)

def process_label(self, label: TextType) -> Text:
"""Process a str or Text into a label. May be overridden in a subclass to modify how labels are rendered.
Expand Down
47 changes: 38 additions & 9 deletions src/textual/widgets/_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
"""Show the root of the tree."""
hover_line = var(-1)
"""The line number under the mouse pointer, or -1 if not under the mouse pointer."""
cursor_line = var(-1)
cursor_line = var(-1, always_update=True)
"""The line with the cursor, or -1 if no cursor."""
show_guides = reactive(True)
"""Enable display of tree guide lines."""
Expand Down Expand Up @@ -846,7 +846,7 @@ def render_label(

if node._allow_expand:
prefix = (
self.ICON_NODE if node.is_expanded else self.ICON_NODE_EXPANDED,
self.ICON_NODE_EXPANDED if node.is_expanded else self.ICON_NODE,
base_style + TOGGLE_STYLE,
)
else:
Expand Down Expand Up @@ -930,6 +930,24 @@ def move_cursor(
animate=animate and abs(self.cursor_line - previous_cursor_line) > 1,
)

def move_cursor_to_line(self, line: int, animate=False) -> None:
"""Move the cursor to the given line.
Args:
line: The line number (negative indexes are offsets from the last line).
animate: Enable scrolling animation.
Raises:
IndexError: If the line doesn't exist.
"""
if self.cursor_line == line:
return
try:
node = self._tree_lines[line].node
except IndexError:
raise IndexError(f"No line no. {line} in the tree")
self.move_cursor(node, animate=animate)

def select_node(self, node: TreeNode[TreeDataType] | None) -> None:
"""Move the cursor to the given node and select it, or reset cursor.
Expand Down Expand Up @@ -1079,22 +1097,33 @@ def watch_hover_line(self, previous_hover_line: int, hover_line: int) -> None:

def watch_cursor_line(self, previous_line: int, line: int) -> None:
previous_node = self._get_node(previous_line)
# Refresh previous cursor node
node = self._get_node(line)

if self.cursor_node is not None:
self.cursor_node._selected = False

if previous_node is not None:
self._refresh_node(previous_node)
previous_node._selected = False

if node is not None:
node._selected = True
self._cursor_node = node
else:
self._cursor_node = None

node = self._get_node(line)
if previous_line == line:
# No change, so no need for refresh
return

# Refresh previous cursor node
if previous_node is not None:
self._refresh_node(previous_node)

# Refresh new node
if node is not None:
self._refresh_node(node)
node._selected = True
self._cursor_node = node
if previous_node != node:
self.post_message(self.NodeHighlighted(node))
else:
self._cursor_node = None

def watch_guide_depth(self, guide_depth: int) -> None:
self._invalidate()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 7be8a31

Please sign in to comment.