Skip to content

Commit 8a16ddf

Browse files
authored
SelectionList events changes (#4759)
* Dont prevent SelectionToggled messages in bulk SelectionList methods. Its important for callers to know on a per-option basis if one was toggled, and is a reasonable expectation. Also update docs to reflect this.. * Update CHANGELOG
1 parent 0d25607 commit 8a16ddf

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2727
- Fixed `Tree` and `DirectoryTree` horizontal scrolling off-by-2 https://github.com/Textualize/textual/pull/4744
2828
- Fixed text-opacity in component styles https://github.com/Textualize/textual/pull/4747
2929
- Ensure `Tree.select_node` sends `NodeSelected` message https://github.com/Textualize/textual/pull/4753
30+
- `SelectionList.SelectionToggled` will now be sent for each option when a bulk toggle is performed (e.g. `toggle_all`). Previously no messages were sent at all. https://github.com/Textualize/textual/pull/4759
3031

3132
### Changed
3233

src/textual/widgets/_selection_list.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,16 @@ class SelectionHighlighted(SelectionMessage[MessageSelectionType]):
202202
class SelectionToggled(SelectionMessage[MessageSelectionType]):
203203
"""Message sent when a selection is toggled.
204204
205+
This is only sent when the value is *explicitly* toggled e.g.
206+
via `toggle` or `toggle_all`, or via user interaction.
207+
If you programmatically set a value to be selected, this message will
208+
not be sent, even if it happens to be the opposite of what was
209+
originally selected (i.e. setting a True to a False or vice-versa).
210+
211+
Since this message indicates a toggle occurring at a per-option level,
212+
a message will be sent for each option that is toggled, even when a
213+
bulk action is performed (e.g. via `toggle_all`).
214+
205215
Can be handled using `on_selection_list_selection_toggled` in a subclass of
206216
[`SelectionList`][textual.widgets.SelectionList] or in a parent node in the DOM.
207217
"""
@@ -210,6 +220,13 @@ class SelectionToggled(SelectionMessage[MessageSelectionType]):
210220
class SelectedChanged(Generic[MessageSelectionType], Message):
211221
"""Message sent when the collection of selected values changes.
212222
223+
This is sent regardless of whether the change occurred via user interaction
224+
or programmatically the the `SelectionList` API.
225+
226+
When a bulk change occurs, such as through `select_all` or `deselect_all`,
227+
only a single `SelectedChanged` message will be sent (rather than one per
228+
option).
229+
213230
Can be handled using `on_selection_list_selected_changed` in a subclass of
214231
[`SelectionList`][textual.widgets.SelectionList] or in a parent node in the DOM.
215232
"""
@@ -316,10 +333,10 @@ def _apply_to_all(self, state_change: Callable[[SelectionType], bool]) -> Self:
316333
# Keep track of if anything changed.
317334
changed = False
318335

319-
# Next we run through everything and apply the change, preventing
320-
# the toggled and changed messages because the caller really isn't
321-
# going to be expecting a message storm from this.
322-
with self.prevent(self.SelectedChanged, self.SelectionToggled):
336+
# Apply the state change function to all options.
337+
# We don't send a SelectedChanged for each option, and instead
338+
# send a single SelectedChanged afterwards if any values change.
339+
with self.prevent(self.SelectedChanged):
323340
for selection in self._options:
324341
changed = (
325342
state_change(cast(Selection[SelectionType], selection).value)

tests/selection_list/test_selection_messages.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ async def test_toggle_all() -> None:
101101
await pilot.pause()
102102
assert pilot.app.messages == [
103103
("SelectionHighlighted", 0),
104+
("SelectionToggled", 0),
105+
("SelectionToggled", 1),
106+
("SelectionToggled", 2),
107+
("SelectionToggled", 3),
108+
("SelectionToggled", 4),
109+
("SelectionToggled", 5),
110+
("SelectionToggled", 6),
111+
("SelectionToggled", 7),
112+
("SelectionToggled", 8),
113+
("SelectionToggled", 9),
104114
("SelectedChanged", None),
105115
]
106116

0 commit comments

Comments
 (0)