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
|
- 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
|
## [0.25.0] - 2023-05-17
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ def on(
|
|||||||
parsed_selectors: dict[str, tuple[SelectorSet, ...]] = {}
|
parsed_selectors: dict[str, tuple[SelectorSet, ...]] = {}
|
||||||
for attribute, css_selector in selectors.items():
|
for attribute, css_selector in selectors.items():
|
||||||
if attribute == "control":
|
if attribute == "control":
|
||||||
if message_type.control is None:
|
if message_type.control == Message.control:
|
||||||
raise OnDecoratorError(
|
raise OnDecoratorError(
|
||||||
"The message class must have a 'control' to match with the on decorator"
|
"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
|
verbose: ClassVar[bool] = False # Message is verbose
|
||||||
no_dispatch: ClassVar[bool] = False # Message may not be handled by client code
|
no_dispatch: ClassVar[bool] = False # Message may not be handled by client code
|
||||||
namespace: ClassVar[str] = "" # Namespace to disambiguate messages
|
namespace: ClassVar[str] = "" # Namespace to disambiguate messages
|
||||||
control: Widget | None = None
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.__post_init__()
|
self.__post_init__()
|
||||||
@@ -79,6 +78,11 @@ class Message:
|
|||||||
if namespace is not None:
|
if namespace is not None:
|
||||||
cls.namespace = namespace
|
cls.namespace = namespace
|
||||||
|
|
||||||
|
@property
|
||||||
|
def control(self) -> Widget | None:
|
||||||
|
"""The widget associated with this message, or None by default."""
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_forwarded(self) -> bool:
|
def is_forwarded(self) -> bool:
|
||||||
"""Has the message been forwarded?"""
|
"""Has the message been forwarded?"""
|
||||||
|
|||||||
@@ -69,9 +69,7 @@ class DirectoryTree(Tree[DirEntry]):
|
|||||||
`DirectoryTree` or in a parent widget in the DOM.
|
`DirectoryTree` or in a parent widget in the DOM.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, node: TreeNode[DirEntry], path: Path) -> None:
|
||||||
self, tree: DirectoryTree, node: TreeNode[DirEntry], path: Path
|
|
||||||
) -> None:
|
|
||||||
"""Initialise the FileSelected object.
|
"""Initialise the FileSelected object.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -79,21 +77,15 @@ class DirectoryTree(Tree[DirEntry]):
|
|||||||
path: The path of the file that was selected.
|
path: The path of the file that was selected.
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.tree: DirectoryTree = tree
|
|
||||||
"""The `DirectoryTree` that had a file selected."""
|
|
||||||
self.node: TreeNode[DirEntry] = node
|
self.node: TreeNode[DirEntry] = node
|
||||||
"""The tree node of the file that was selected."""
|
"""The tree node of the file that was selected."""
|
||||||
self.path: Path = path
|
self.path: Path = path
|
||||||
"""The path of the file that was selected."""
|
"""The path of the file that was selected."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def control(self) -> DirectoryTree:
|
def control(self) -> Tree[DirEntry]:
|
||||||
"""The `DirectoryTree` that had a file selected.
|
"""The `Tree` that had a file selected."""
|
||||||
|
return self.node.tree
|
||||||
This is an alias for [`FileSelected.tree`][textual.widgets.DirectoryTree.FileSelected.tree]
|
|
||||||
which is used by the [`on`][textual.on] decorator.
|
|
||||||
"""
|
|
||||||
return self.tree
|
|
||||||
|
|
||||||
path: var[str | Path] = var["str | Path"](PATH("."), init=False, always_update=True)
|
path: var[str | Path] = var["str | Path"](PATH("."), init=False, always_update=True)
|
||||||
"""The path that is the root of the directory tree.
|
"""The path that is the root of the directory tree.
|
||||||
@@ -361,7 +353,7 @@ class DirectoryTree(Tree[DirEntry]):
|
|||||||
if not dir_entry.loaded:
|
if not dir_entry.loaded:
|
||||||
self._add_to_load_queue(event.node)
|
self._add_to_load_queue(event.node)
|
||||||
else:
|
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:
|
def _on_tree_node_selected(self, event: Tree.NodeSelected) -> None:
|
||||||
event.stop()
|
event.stop()
|
||||||
@@ -369,4 +361,4 @@ class DirectoryTree(Tree[DirEntry]):
|
|||||||
if dir_entry is None:
|
if dir_entry is None:
|
||||||
return
|
return
|
||||||
if not self._safe_is_dir(dir_entry.path):
|
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.
|
"""Posted when the select value was changed.
|
||||||
|
|
||||||
This message can be handled using a `on_select_changed` method.
|
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.
|
Initialize the Changed message.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.control = control
|
self.select = select
|
||||||
"""The select control."""
|
"""The select widget."""
|
||||||
self.value = value
|
self.value = value
|
||||||
"""The value of the Select when it changed."""
|
"""The value of the Select when it changed."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def control(self) -> Select:
|
||||||
|
"""The Select that sent the message."""
|
||||||
|
return self.select
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
options: Iterable[tuple[str, SelectType]],
|
options: Iterable[tuple[str, SelectType]],
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ class TreeNode(Generic[TreeDataType]):
|
|||||||
"""
|
"""
|
||||||
self._expanded = True
|
self._expanded = True
|
||||||
self._updates += 1
|
self._updates += 1
|
||||||
self._tree.post_message(Tree.NodeExpanded(self._tree, self))
|
self._tree.post_message(Tree.NodeExpanded(self))
|
||||||
if expand_all:
|
if expand_all:
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
child._expand(expand_all)
|
child._expand(expand_all)
|
||||||
@@ -240,7 +240,7 @@ class TreeNode(Generic[TreeDataType]):
|
|||||||
"""
|
"""
|
||||||
self._expanded = False
|
self._expanded = False
|
||||||
self._updates += 1
|
self._updates += 1
|
||||||
self._tree.post_message(Tree.NodeCollapsed(self._tree, self))
|
self._tree.post_message(Tree.NodeCollapsed(self))
|
||||||
if collapse_all:
|
if collapse_all:
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
child._collapse(collapse_all)
|
child._collapse(collapse_all)
|
||||||
@@ -514,23 +514,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
parent node in the DOM.
|
parent node in the DOM.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
|
||||||
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
|
|
||||||
) -> None:
|
|
||||||
self.tree = tree
|
|
||||||
"""The tree that sent the message."""
|
|
||||||
self.node: TreeNode[EventTreeDataType] = node
|
self.node: TreeNode[EventTreeDataType] = node
|
||||||
"""The node that was collapsed."""
|
"""The node that was collapsed."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def control(self) -> Tree[EventTreeDataType]:
|
def control(self) -> Tree[EventTreeDataType]:
|
||||||
"""The tree that sent the message.
|
"""The tree that sent the message."""
|
||||||
|
return self.node.tree
|
||||||
This is an alias for [`NodeCollapsed.tree`][textual.widgets.Tree.NodeCollapsed.tree]
|
|
||||||
and is used by the [`on`][textual.on] decorator.
|
|
||||||
"""
|
|
||||||
return self.tree
|
|
||||||
|
|
||||||
class NodeExpanded(Generic[EventTreeDataType], Message, bubble=True):
|
class NodeExpanded(Generic[EventTreeDataType], Message, bubble=True):
|
||||||
"""Event sent when a node is expanded.
|
"""Event sent when a node is expanded.
|
||||||
@@ -539,23 +531,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
parent node in the DOM.
|
parent node in the DOM.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
|
||||||
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
|
|
||||||
) -> None:
|
|
||||||
self.tree = tree
|
|
||||||
"""The tree that sent the message."""
|
|
||||||
self.node: TreeNode[EventTreeDataType] = node
|
self.node: TreeNode[EventTreeDataType] = node
|
||||||
"""The node that was expanded."""
|
"""The node that was expanded."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def control(self) -> Tree[EventTreeDataType]:
|
def control(self) -> Tree[EventTreeDataType]:
|
||||||
"""The tree that sent the message.
|
"""The tree that sent the message."""
|
||||||
|
return self.node.tree
|
||||||
This is an alias for [`NodeExpanded.tree`][textual.widgets.Tree.NodeExpanded.tree]
|
|
||||||
and is used by the [`on`][textual.on] decorator.
|
|
||||||
"""
|
|
||||||
return self.tree
|
|
||||||
|
|
||||||
class NodeHighlighted(Generic[EventTreeDataType], Message, bubble=True):
|
class NodeHighlighted(Generic[EventTreeDataType], Message, bubble=True):
|
||||||
"""Event sent when a node is highlighted.
|
"""Event sent when a node is highlighted.
|
||||||
@@ -564,23 +548,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
parent node in the DOM.
|
parent node in the DOM.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
|
||||||
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
|
|
||||||
) -> None:
|
|
||||||
self.tree = tree
|
|
||||||
"""The tree that sent the message."""
|
|
||||||
self.node: TreeNode[EventTreeDataType] = node
|
self.node: TreeNode[EventTreeDataType] = node
|
||||||
"""The node that was highlighted."""
|
"""The node that was highlighted."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def control(self) -> Tree[EventTreeDataType]:
|
def control(self) -> Tree[EventTreeDataType]:
|
||||||
"""The tree that sent the message.
|
"""The tree that sent the message."""
|
||||||
|
return self.node.tree
|
||||||
This is an alias for [`NodeHighlighted.tree`][textual.widgets.Tree.NodeHighlighted.tree]
|
|
||||||
and is used by the [`on`][textual.on] decorator.
|
|
||||||
"""
|
|
||||||
return self.tree
|
|
||||||
|
|
||||||
class NodeSelected(Generic[EventTreeDataType], Message, bubble=True):
|
class NodeSelected(Generic[EventTreeDataType], Message, bubble=True):
|
||||||
"""Event sent when a node is selected.
|
"""Event sent when a node is selected.
|
||||||
@@ -589,23 +565,15 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
parent node in the DOM.
|
parent node in the DOM.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(self, node: TreeNode[EventTreeDataType]) -> None:
|
||||||
self, tree: Tree[EventTreeDataType], node: TreeNode[EventTreeDataType]
|
|
||||||
) -> None:
|
|
||||||
self.tree = tree
|
|
||||||
"""The tree that sent the message."""
|
|
||||||
self.node: TreeNode[EventTreeDataType] = node
|
self.node: TreeNode[EventTreeDataType] = node
|
||||||
"""The node that was selected."""
|
"""The node that was selected."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def control(self) -> Tree[EventTreeDataType]:
|
def control(self) -> Tree[EventTreeDataType]:
|
||||||
"""The tree that sent the message.
|
"""The tree that sent the message."""
|
||||||
|
return self.node.tree
|
||||||
This is an alias for [`NodeSelected.tree`][textual.widgets.Tree.NodeSelected.tree]
|
|
||||||
and is used by the [`on`][textual.on] decorator.
|
|
||||||
"""
|
|
||||||
return self.tree
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -905,7 +873,7 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
node._selected = True
|
node._selected = True
|
||||||
self._cursor_node = node
|
self._cursor_node = node
|
||||||
if previous_node != node:
|
if previous_node != node:
|
||||||
self.post_message(self.NodeHighlighted(self, node))
|
self.post_message(self.NodeHighlighted(node))
|
||||||
else:
|
else:
|
||||||
self._cursor_node = None
|
self._cursor_node = None
|
||||||
|
|
||||||
@@ -1236,7 +1204,7 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
|
|
||||||
Note:
|
Note:
|
||||||
If `auto_expand` is `True` use of this action on a non-leaf node
|
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.
|
selected event.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@@ -1247,4 +1215,4 @@ class Tree(Generic[TreeDataType], ScrollView, can_focus=True):
|
|||||||
node = line.path[-1]
|
node = line.path[-1]
|
||||||
if self.auto_expand:
|
if self.auto_expand:
|
||||||
self._toggle_node(node)
|
self._toggle_node(node)
|
||||||
self.post_message(self.NodeSelected(self, node))
|
self.post_message(self.NodeSelected(node))
|
||||||
|
|||||||
Reference in New Issue
Block a user