Repository: Textualize/textual

Issue:
Disabled widgets prevent mouse scrolling
# Context

My application used to disable entire Collapsible Contents, which is how I noticed this issue in the first place.

Notes:

- in this issue, "scrolling" and "scroll using the mouse" are both short for "scrolling using the mouse scroll wheel or any similar device"
- this issue is similar to https://github.com/Textualize/textual/issues/1912 but applies to enabled containers.

# Expectations

When an enabled scrollable container contains disabled widgets, disabled widgets should not prevent scrolling the container.

# Current behaviour

The MRE below reflects the issue. It alternates enabled and disabled widgets in a way that prevents effective scrolling.

![textual-scroll-mre](https://github.com/Textualize/textual/assets/18504173/747e5063-a4bc-485d-bf23-0638dfad9d27)

```python
#!/usr/bin/env python3
from textual.app import App, ComposeResult
from textual.widgets import Static

class MyBoringWidget(Static, can_focus=True):
    DEFAULT_CSS = "MyBoringWidget { height: 90%; background: $primary; border: tall yellow; }"

class ScrollMRE(App):
    DEFAULT_CSS = "Static { text-align: center; }"
    def compose(self) -> ComposeResult:
        instructions = 'Place your cursor in the middle of the app and try scrolling to the bottom using the mouse'
        yield Static(instructions)
        for i in range(10):
            yield MyBoringWidget(disabled=bool(i%2))
            yield Static(instructions)

if __name__ == "__main__":
    app = ScrollMRE()
    app.run()
```

# Textual Diagnostics

## Versions

| Name    | Value  |
|---------|--------|
| Textual | 0.52.1 |
| Rich    | 13.7.0 |

## Python

| Name           | Value                                              |
|----------------|----------------------------------------------------|
| Version        | 3.11.8                                             |
| Implementation | CPython                                            |
| Compiler       | GCC 13.2.0                                         |
| Executable     | ~/whatever/venv/bin/python3 |

## Operating System

| Name    | Value                                               |
|---------|-----------------------------------------------------|
| System  | Linux                                               |
| Release | 6.6.15-amd64                                        |
| Version | #1 SMP PREEMPT_DYNAMIC Debian 6.6.15-2 (2024-02-04) |

## Terminal

| Name                 | Value          |
|----------------------|----------------|
| Terminal Application | tmux (3.4)     |
| TERM                 | xterm-256color |
| COLORTERM            | truecolor      |
| FORCE_COLOR          | *Not set*      |
| NO_COLOR             | *Not set*      |

## Rich Console options

| Name           | Value                |
|----------------|----------------------|
| size           | width=232, height=54 |
| legacy_windows | False                |
| min_width      | 1                    |
| max_width      | 232                  |
| is_terminal    | False                |
| encoding       | utf-8                |
| max_height     | 54                   |
| justify        | None                 |
| overflow       | None                 |
| no_wrap        | False                |
| highlight      | None                 |
| markup         | None                 |
| height         | None                 |



Discussion:
We found the following entries in the [FAQ](https://textual.textualize.io/FAQ/) which you may find helpful:


- [How do I center a widget in a screen?](https://textual.textualize.io/FAQ/#how-do-i-center-a-widget-in-a-screen)
- [Does Textual support images?](https://textual.textualize.io/FAQ/#does-textual-support-images)
- [How do I fix WorkerDeclarationError?](https://textual.textualize.io/FAQ/#how-do-i-fix-workerdeclarationerror)

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by [FAQtory](https://github.com/willmcgugan/faqtory)
Scrolling with the scrollbar works. This issue relates to scrolling with the wheel / gestures.

Resolving patch:
diff --git a/src/textual/widget.py b/src/textual/widget.py
--- a/src/textual/widget.py
+++ b/src/textual/widget.py
@@ -3567,8 +3567,12 @@ def check_message_enabled(self, message: Message) -> bool:
         message_type = type(message)
         if self._is_prevented(message_type):
             return False
-        # Otherwise, if this is a mouse event, the widget receiving the
-        # event must not be disabled at this moment.
+        # Mouse scroll events should always go through, this allows mouse
+        # wheel scrolling to pass through disabled widgets.
+        if isinstance(message, (events.MouseScrollDown, events.MouseScrollUp)):
+            return True
+        # Otherwise, if this is any other mouse event, the widget receiving
+        # the event must not be disabled at this moment.
         return (
             not self._self_or_ancestors_disabled
             if isinstance(message, (events.MouseEvent, events.Enter, events.Leave))


Test patch: