mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Refactor Message.control and Tree Messages (#2602)
* 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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -65,7 +65,7 @@ def on(
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -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__()
|
||||
@@ -79,6 +78,11 @@ class Message:
|
||||
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?"""
|
||||
|
||||
@@ -69,9 +69,7 @@ class DirectoryTree(Tree[DirEntry]):
|
||||
`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:
|
||||
@@ -79,21 +77,15 @@ class DirectoryTree(Tree[DirEntry]):
|
||||
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.
|
||||
@@ -361,7 +353,7 @@ class DirectoryTree(Tree[DirEntry]):
|
||||
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()
|
||||
@@ -369,4 +361,4 @@ class DirectoryTree(Tree[DirEntry]):
|
||||
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))
|
||||
|
||||
@@ -227,20 +227,23 @@ class Select(Generic[SelectType], Vertical, can_focus=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]],
|
||||
|
||||
@@ -207,7 +207,7 @@ class TreeNode(Generic[TreeDataType]):
|
||||
"""
|
||||
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)
|
||||
@@ -240,7 +240,7 @@ class TreeNode(Generic[TreeDataType]):
|
||||
"""
|
||||
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)
|
||||
@@ -514,23 +514,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=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.
|
||||
@@ -539,23 +531,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=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.
|
||||
@@ -564,23 +548,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=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.
|
||||
@@ -589,23 +565,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=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,
|
||||
@@ -905,7 +873,7 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
||||
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
|
||||
|
||||
@@ -1236,7 +1204,7 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
||||
|
||||
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:
|
||||
@@ -1247,4 +1215,4 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
||||
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))
|
||||
|
||||
Reference in New Issue
Block a user