Skip to content

Commit

Permalink
Refactor Message.control and Tree Messages (#2602)
Browse files Browse the repository at this point in the history
* refactor(message): make control a property

* refactor(_tree): remove tree parameter on messages

* refactor(_directory_tree): remove tree parameter on message

* fix: tree message calls

* fix(_select): make Changed.control a property

* refactor(_on): control check

* refactor(_select): rename Changed.widget to select

* docs: changelog entry
  • Loading branch information
aaronst authored May 25, 2023
1 parent 3ab315b commit 20d19d9
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 70 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Textual will now scroll focused widgets to center if not in view

## Unreleased

### Changed

- `Message.control` is now a property instead of a class variable. https://github.com/Textualize/textual/issues/2528
- `Tree` and `DirectoryTree` Messages no longer accept a `tree` parameter, using `self.node.tree` instead. https://github.com/Textualize/textual/issues/2529

## [0.25.0] - 2023-05-17

### Changed
Expand Down
2 changes: 1 addition & 1 deletion src/textual/_on.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def switch_to_home(self) -> None:
parsed_selectors: dict[str, tuple[SelectorSet, ...]] = {}
for attribute, css_selector in selectors.items():
if attribute == "control":
if message_type.control is None:
if message_type.control == Message.control:
raise OnDecoratorError(
"The message class must have a 'control' to match with the on decorator"
)
Expand Down
6 changes: 5 additions & 1 deletion src/textual/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class Message:
verbose: ClassVar[bool] = False # Message is verbose
no_dispatch: ClassVar[bool] = False # Message may not be handled by client code
namespace: ClassVar[str] = "" # Namespace to disambiguate messages
control: Widget | None = None

def __init__(self) -> None:
self.__post_init__()
Expand Down Expand Up @@ -79,6 +78,11 @@ def __init_subclass__(
if namespace is not None:
cls.namespace = namespace

@property
def control(self) -> Widget | None:
"""The widget associated with this message, or None by default."""
return None

@property
def is_forwarded(self) -> bool:
"""Has the message been forwarded?"""
Expand Down
20 changes: 6 additions & 14 deletions src/textual/widgets/_directory_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,23 @@ class FileSelected(Message, bubble=True):
`DirectoryTree` or in a parent widget in the DOM.
"""

def __init__(
self, tree: DirectoryTree, node: TreeNode[DirEntry], path: Path
) -> None:
def __init__(self, node: TreeNode[DirEntry], path: Path) -> None:
"""Initialise the FileSelected object.
Args:
node: The tree node for the file that was selected.
path: The path of the file that was selected.
"""
super().__init__()
self.tree: DirectoryTree = tree
"""The `DirectoryTree` that had a file selected."""
self.node: TreeNode[DirEntry] = node
"""The tree node of the file that was selected."""
self.path: Path = path
"""The path of the file that was selected."""

@property
def control(self) -> DirectoryTree:
"""The `DirectoryTree` that had a file selected.
This is an alias for [`FileSelected.tree`][textual.widgets.DirectoryTree.FileSelected.tree]
which is used by the [`on`][textual.on] decorator.
"""
return self.tree
def control(self) -> Tree[DirEntry]:
"""The `Tree` that had a file selected."""
return self.node.tree

path: var[str | Path] = var["str | Path"](PATH("."), init=False, always_update=True)
"""The path that is the root of the directory tree.
Expand Down Expand Up @@ -361,12 +353,12 @@ def _on_tree_node_expanded(self, event: Tree.NodeExpanded) -> None:
if not dir_entry.loaded:
self._add_to_load_queue(event.node)
else:
self.post_message(self.FileSelected(self, event.node, dir_entry.path))
self.post_message(self.FileSelected(event.node, dir_entry.path))

def _on_tree_node_selected(self, event: Tree.NodeSelected) -> None:
event.stop()
dir_entry = event.node.data
if dir_entry is None:
return
if not self._safe_is_dir(dir_entry.path):
self.post_message(self.FileSelected(self, event.node, dir_entry.path))
self.post_message(self.FileSelected(event.node, dir_entry.path))
13 changes: 8 additions & 5 deletions src/textual/widgets/_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,20 +227,23 @@ class Changed(Message, bubble=True):
"""Posted when the select value was changed.
This message can be handled using a `on_select_changed` method.
"""

def __init__(self, control: Select, value: SelectType | None) -> None:
def __init__(self, select: Select, value: SelectType | None) -> None:
"""
Initialize the Changed message.
"""
super().__init__()
self.control = control
"""The select control."""
self.select = select
"""The select widget."""
self.value = value
"""The value of the Select when it changed."""

@property
def control(self) -> Select:
"""The Select that sent the message."""
return self.select

def __init__(
self,
options: Iterable[tuple[str, SelectType]],
Expand Down
66 changes: 17 additions & 49 deletions src/textual/widgets/_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def _expand(self, expand_all: bool) -> None:
"""
self._expanded = True
self._updates += 1
self._tree.post_message(Tree.NodeExpanded(self._tree, self))
self._tree.post_message(Tree.NodeExpanded(self))
if expand_all:
for child in self.children:
child._expand(expand_all)
Expand Down Expand Up @@ -240,7 +240,7 @@ def _collapse(self, collapse_all: bool) -> None:
"""
self._expanded = False
self._updates += 1
self._tree.post_message(Tree.NodeCollapsed(self._tree, self))
self._tree.post_message(Tree.NodeCollapsed(self))
if collapse_all:
for child in self.children:
child._collapse(collapse_all)
Expand Down Expand Up @@ -514,23 +514,15 @@ class NodeCollapsed(Generic[EventTreeDataType], Message, bubble=True):
parent node in the DOM.
"""

def __init__(
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
) -> None:
self.tree = tree
"""The tree that sent the message."""
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
self.node: TreeNode[EventTreeDataType] = node
"""The node that was collapsed."""
super().__init__()

@property
def control(self) -> Tree[EventTreeDataType]:
"""The tree that sent the message.
This is an alias for [`NodeCollapsed.tree`][textual.widgets.Tree.NodeCollapsed.tree]
and is used by the [`on`][textual.on] decorator.
"""
return self.tree
"""The tree that sent the message."""
return self.node.tree

class NodeExpanded(Generic[EventTreeDataType], Message, bubble=True):
"""Event sent when a node is expanded.
Expand All @@ -539,23 +531,15 @@ class NodeExpanded(Generic[EventTreeDataType], Message, bubble=True):
parent node in the DOM.
"""

def __init__(
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
) -> None:
self.tree = tree
"""The tree that sent the message."""
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
self.node: TreeNode[EventTreeDataType] = node
"""The node that was expanded."""
super().__init__()

@property
def control(self) -> Tree[EventTreeDataType]:
"""The tree that sent the message.
This is an alias for [`NodeExpanded.tree`][textual.widgets.Tree.NodeExpanded.tree]
and is used by the [`on`][textual.on] decorator.
"""
return self.tree
"""The tree that sent the message."""
return self.node.tree

class NodeHighlighted(Generic[EventTreeDataType], Message, bubble=True):
"""Event sent when a node is highlighted.
Expand All @@ -564,23 +548,15 @@ class NodeHighlighted(Generic[EventTreeDataType], Message, bubble=True):
parent node in the DOM.
"""

def __init__(
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
) -> None:
self.tree = tree
"""The tree that sent the message."""
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
self.node: TreeNode[EventTreeDataType] = node
"""The node that was highlighted."""
super().__init__()

@property
def control(self) -> Tree[EventTreeDataType]:
"""The tree that sent the message.
This is an alias for [`NodeHighlighted.tree`][textual.widgets.Tree.NodeHighlighted.tree]
and is used by the [`on`][textual.on] decorator.
"""
return self.tree
"""The tree that sent the message."""
return self.node.tree

class NodeSelected(Generic[EventTreeDataType], Message, bubble=True):
"""Event sent when a node is selected.
Expand All @@ -589,23 +565,15 @@ class NodeSelected(Generic[EventTreeDataType], Message, bubble=True):
parent node in the DOM.
"""

def __init__(
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
) -> None:
self.tree = tree
"""The tree that sent the message."""
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
self.node: TreeNode[EventTreeDataType] = node
"""The node that was selected."""
super().__init__()

@property
def control(self) -> Tree[EventTreeDataType]:
"""The tree that sent the message.
This is an alias for [`NodeSelected.tree`][textual.widgets.Tree.NodeSelected.tree]
and is used by the [`on`][textual.on] decorator.
"""
return self.tree
"""The tree that sent the message."""
return self.node.tree

def __init__(
self,
Expand Down Expand Up @@ -905,7 +873,7 @@ def watch_cursor_line(self, previous_line: int, line: int) -> None:
node._selected = True
self._cursor_node = node
if previous_node != node:
self.post_message(self.NodeHighlighted(self, node))
self.post_message(self.NodeHighlighted(node))
else:
self._cursor_node = None

Expand Down Expand Up @@ -1236,7 +1204,7 @@ def action_select_cursor(self) -> None:
Note:
If `auto_expand` is `True` use of this action on a non-leaf node
will cause both an expand/collapse event to occour, as well as a
will cause both an expand/collapse event to occur, as well as a
selected event.
"""
try:
Expand All @@ -1247,4 +1215,4 @@ def action_select_cursor(self) -> None:
node = line.path[-1]
if self.auto_expand:
self._toggle_node(node)
self.post_message(self.NodeSelected(self, node))
self.post_message(self.NodeSelected(node))

0 comments on commit 20d19d9

Please sign in to comment.