Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoWidget error when mouse dragged outside terminal window #3789

Closed
TomJGooding opened this issue Nov 30, 2023 · 5 comments · Fixed by #3790
Closed

NoWidget error when mouse dragged outside terminal window #3789

TomJGooding opened this issue Nov 30, 2023 · 5 comments · Fixed by #3790

Comments

@TomJGooding
Copy link
Contributor

TomJGooding commented Nov 30, 2023

This is with Textual v0.43.2. To reproduce, with the app below grab the scrollbar with the mouse and then try quickly moving to the end of the document. It seems when the mouse is outside the terminal window, it will crash with a NoWidget error.

from textual.app import App, ComposeResult
from textual.containers import VerticalScroll
from textual.widgets import Markdown

TEXT = """I must not fear.
Fear is the mind-killer.
Fear is the little-death that brings total obliteration.
I will face my fear.
I will permit it to pass over me and through me.
And when it has gone past, I will turn the inner eye to see its path.
Where the fear has gone there will be nothing. Only I will remain."""


class ExampleApp(App):
    def compose(self) -> ComposeResult:
        with VerticalScroll():
            yield (Markdown(TEXT * 100))


if __name__ == "__main__":
    app = ExampleApp()
    app.run()
Traceback
╭───────────────────── Traceback (most recent call last) ──────────────────────╮
│ /home/tom/Projects/textual-sandbox/.venv/lib/python3.11/site-packages/textua │
│ l/app.py:2703 in on_event                                                    │
│                                                                              │
│   2700 │   │   │   │                                                         │
│   2701 │   │   │   │   if isinstance(event, events.MouseUp):                 │
│   2702 │   │   │   │   │   if self._mouse_down_widget is not None and (      │
│ ❱ 2703 │   │   │   │   │   │   self.get_widget_at(event.x, event.y)[0]       │
│   2704 │   │   │   │   │   │   is self._mouse_down_widget                    │
│   2705 │   │   │   │   │   ):                                                │
│   2706 │   │   │   │   │   │   click_event = events.Click.from_event(event)  │
│                                                                              │
│ ╭──────────────────────────── locals ────────────────────────────╮           │
│ │ event = MouseUp(x=87, y=35, button=1)                          │           │
│ │  self = ExampleApp(title='ExampleApp', classes={'-dark-mode'}) │           │
│ ╰────────────────────────────────────────────────────────────────╯           │
│                                                                              │
│ /home/tom/Projects/textual-sandbox/.venv/lib/python3.11/site-packages/textua │
│ l/app.py:2609 in get_widget_at                                               │
│                                                                              │
│   2606 │   │   Returns:                                                      │
│   2607 │   │   │   The widget and the widget's screen region.                │
│   2608 │   │   """                                                           │
│ ❱ 2609 │   │   return self.screen.get_widget_at(x, y)                        │
│   2610 │                                                                     │
│   2611 │   def bell(self) -> None:                                           │
│   2612 │   │   """Play the console 'bell'.                                   │
│                                                                              │
│ ╭─────────────────────────── locals ────────────────────────────╮            │
│ │ self = ExampleApp(title='ExampleApp', classes={'-dark-mode'}) │            │
│ │    x = 87                                                     │            │
│ │    y = 35                                                     │            │
│ ╰───────────────────────────────────────────────────────────────╯            │
│                                                                              │
│ /home/tom/Projects/textual-sandbox/.venv/lib/python3.11/site-packages/textua │
│ l/screen.py:289 in get_widget_at                                             │
│                                                                              │
│    286 │   │   Returns:                                                      │
│    287 │   │   │   Widget and screen region.                                 │
│    288 │   │   """                                                           │
│ ❱  289 │   │   return self._compositor.get_widget_at(x, y)                   │
│    290 │                                                                     │
│    291 │   def get_widgets_at(self, x: int, y: int) -> Iterable[tuple[Widget │
│    292 │   │   """Get all widgets under a given coordinate.                  │
│                                                                              │
│ ╭─────────── locals ───────────╮                                             │
(.venv) [tom@arch textual-sandbox]$ textual --version
textual, version 0.43.2
(.venv) [tom@arch textual-sandbox]$ textual run no_widget_scroll_bug.py 
╭──────────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────────╮
│ /home/tom/Projects/textual-sandbox/.venv/lib/python3.11/site-packages/textual/app.py:2704 in on_event                                                      │
│                                                                                                                                                            │
│   2701 │   │   │   │                                                                                                                                       │
│   2702 │   │   │   │   if isinstance(event, events.MouseUp):                                                                                               │
│   2703 │   │   │   │   │   if self._mouse_down_widget is not None and (                                                                                    │
│ ❱ 2704 │   │   │   │   │   │   self.get_widget_at(event.x, event.y)[0]                                                                                     │
│   2705 │   │   │   │   │   │   is self._mouse_down_widget                                                                                                  │
│   2706 │   │   │   │   │   ):                                                                                                                              │
│   2707 │   │   │   │   │   │   click_event = events.Click.from_event(event)                                                                                │
│                                                                                                                                                            │
│ ╭──────────────────────────── locals ────────────────────────────╮                                                                                         │
│ │ event = MouseUp(x=161, y=39, button=1)                         │                                                                                         │
│ │  self = ExampleApp(title='ExampleApp', classes={'-dark-mode'}) │                                                                                         │
│ ╰────────────────────────────────────────────────────────────────╯                                                                                         │
│                                                                                                                                                            │
│ /home/tom/Projects/textual-sandbox/.venv/lib/python3.11/site-packages/textual/app.py:2610 in get_widget_at                                                 │
│                                                                                                                                                            │
│   2607 │   │   Returns:                                                                                                                                    │
│   2608 │   │   │   The widget and the widget's screen region.                                                                                              │
│   2609 │   │   """                                                                                                                                         │
│ ❱ 2610 │   │   return self.screen.get_widget_at(x, y)                                                                                                      │
│   2611 │                                                                                                                                                   │
│   2612 │   def bell(self) -> None:                                                                                                                         │
│   2613 │   │   """Play the console 'bell'.                                                                                                                 │
│                                                                                                                                                            │
│ ╭─────────────────────────── locals ────────────────────────────╮                                                                                          │
│ │ self = ExampleApp(title='ExampleApp', classes={'-dark-mode'}) │                                                                                          │
│ │    x = 161                                                    │                                                                                          │
│ │    y = 39                                                     │                                                                                          │
│ ╰───────────────────────────────────────────────────────────────╯                                                                                          │
│                                                                                                                                                            │
│ /home/tom/Projects/textual-sandbox/.venv/lib/python3.11/site-packages/textual/screen.py:289 in get_widget_at                                               │
│                                                                                                                                                            │
│    286 │   │   Returns:                                                                         ╭─────────── locals ───────────╮                           │
│    287 │   │   │   Widget and screen region.                                                    │ self = Screen(id='_default') │                           │
│    288 │   │   """                                                                              │    x = 161                   │                           │
│ ❱  289 │   │   return self._compositor.get_widget_at(x, y)                                      │    y = 39                    │                           │
│    290 │                                                                                        ╰──────────────────────────────╯                           │
│    291 │   def get_widgets_at(self, x: int, y: int) -> Iterable[tuple[Widget, Region]]:                                                                    │
│    292 │   │   """Get all widgets under a given coordinate.                                                                                                │
│                                                                                                                                                            │
│ /home/tom/Projects/textual-sandbox/.venv/lib/python3.11/site-packages/textual/_compositor.py:787 in get_widget_at                                          │
│                                                                                                                                                            │
│    784 │   │   │   for widget, cropped_region, region in self.layers_visible[y]:                                                                           │
│    785 │   │   │   │   if contains(cropped_region, x, y) and widget.visible:                                                                               │
│    786 │   │   │   │   │   return widget, region                                                                                                           │
│ ❱  787 │   │   raise errors.NoWidget(f"No widget under screen coordinate ({x}, {y})")                                                                      │
│    788 │                                                                                                                                                   │
│    789def get_widgets_at(self, x: int, y: int) -> Iterable[tuple[Widget, Region]]:                                                                    │
│    790 │   │   """Get all widgets under a given coordinate.                                                                                                │
│                                                                                                                                                            │
│ ╭────────────────────────────────────────────────────────────────── locals ──────────────────────────────────────────────────────────────────╮             │
│ │       contains = <function Region.contains at 0x7f7b2474b2e0>                                                                              │             │
│ │ cropped_region = Region(x=0, y=0, width=158, height=45)                                                                                    │             │
│ │         region = Region(x=0, y=0, width=158, height=45)                                                                                    │             │
│ │           self = <Compositor                                                                                                               │             │
│ │                  │   size=Size(width=158, height=45)                                                                                       │             │
│ │                  │   widgets={                                                                                                             │             │
│ │                  │   │   VerticalScroll(),                                                                                                 │             │
│ │                  │   │   Markdown(),                                                                                                       │             │
│ │                  │   │   MarkdownParagraph(),                                                                                              │             │
│ │                  │   │   Screen(id='_default'),                                                                                            │             │
│ │                  │   │   ToastRack(id='textual-toastrack')                                                                                 │             │
│ │                  │   }                                                                                                                     │             │
│ │                  >                                                                                                                         │             │
│ │         widget = Screen(id='_default')                                                                                                     │             │
│ │              x = 161                                                                                                                       │             │
│ │              y = 39                                                                                                                        │             │
│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯             │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
NoWidget: No widget under screen coordinate (161, 39)
Copy link

We found the following entry in the FAQ which you may find helpful:

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

@TomJGooding TomJGooding changed the title NoWidget error with scolling NoWidget error with scrolling Nov 30, 2023
@TomJGooding TomJGooding changed the title NoWidget error with scrolling NoWidget error when mouse dragged outside terminal window Dec 1, 2023
@willmcgugan
Copy link
Collaborator

Thanks. What terminal is that?

I can't reproduce it. But I can see why it would happen. But it looks like the terminal is generating coords outside of the window, which iTerm doesn't seem to do.

Copy link

github-actions bot commented Dec 1, 2023

Don't forget to star the repository!

Follow @textualizeio for Textual updates.

@willmcgugan
Copy link
Collaborator

0.44.0 should fix that, but if you wouldn't mind giving it a shot to check...

@TomJGooding
Copy link
Contributor Author

Thanks Will, looks like that has fixed it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants