From 1013f84ffc67bdce04bf13eaf401ab5ced572bb0 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 17 Sep 2022 10:31:21 +0100 Subject: [PATCH] diagrams --- docs/guide/events.md | 32 +++++++++++++-- docs/images/events/bubble1.excalidraw.svg | 16 ++++++++ docs/images/events/bubble2.excalidraw.svg | 16 ++++++++ docs/images/events/bubble3.excalidraw.svg | 16 ++++++++ src/textual/message.py | 6 ++- src/textual/scroll_view.py | 16 ++++++++ src/textual/widget.py | 50 +++++++++++------------ 7 files changed, 122 insertions(+), 30 deletions(-) create mode 100644 docs/images/events/bubble1.excalidraw.svg create mode 100644 docs/images/events/bubble2.excalidraw.svg create mode 100644 docs/images/events/bubble3.excalidraw.svg diff --git a/docs/guide/events.md b/docs/guide/events.md index 9c4b54b49..77e40ce4e 100644 --- a/docs/guide/events.md +++ b/docs/guide/events.md @@ -51,14 +51,40 @@ Let's explore how Textual decides what method to call for a given event. ### Default behaviors -You may be familiar with using Python's [super](https://docs.python.org/3/library/functions.html#super) function to call a function defined in a base class. You will not have to do this for Textual event handlers as Textual will automatically call any handler methods defined in the base class *after* the current handler has run. This allows textual to run any default behavior for the given event. +You may be familiar with Python's [super](https://docs.python.org/3/library/functions.html#super) function to call a function defined in a base class. You will not have to do this for Textual event handlers as Textual will automatically call any handler methods defined in the base class. -For instance if a widget defines an `on_key` handler it will run when the user hits a key. Textual will also run `Widget.on_key`, which allows Textual to respond to any key bindings. This is generally desirable, but you can prevent Textual from running the base class handler by calling [prevent_default()][textual.message.Message.prevent_default] on the event object. +For instance if you define a custom widget, Textual will call its `on_key` handler when you hit a key. Textual will also run any `on_key` methods found in the widget's base classes, including `Widget.on_key` where key bindings are processed. Without this behavior, you would have to remember to call `super().on_key(event)` or key bindings would break. + +If you don't want this behavior you can call [prevent_default()][textual.message.Message.prevent_default] on the event object. This tells Textual not to call any handlers on base classes. -For the case of key events, you may want to prevent the default behavior for keys that you handle by calling `event.prevent_default()`, but allow the base class to handle all other keys. ### Bubbling +Messages have a `bubble` attribute. If this is set to `True` then events will be sent to their parent widget. Input events typically bubble so that a widget will have the opportunity to process events after its children. + +The following diagram shows an (abbreviated) DOM for a UI with a container and two buttons. With the "No" button [focused](#) it will receive the key event first. + +
+--8<-- "docs/images/events/bubble1.excalidraw.svg" +
+ +After Textual calls `Button.on_key` it _bubbles_ the event to its parent and call `Container.on_key` (if it exists). + +
+--8<-- "docs/images/events/bubble2.excalidraw.svg" +
+ +Then it will bubble to the container's parent (the App class). + +
+--8<-- "docs/images/events/bubble3.excalidraw.svg" +
+ +The App class is always the root of the DOM, so there is no where for the event to bubble to. + +#### Stopping bubbling + +Event handlers may stop this bubble behavior by calling the [stop()][textual.message.Message.stop] method on the event or message. You might want to do this if a widget has responded to the event in an authoritative way. For instance if a text input widget as responded to a key event you probably do not want it to also invoke a key binding. diff --git a/docs/images/events/bubble1.excalidraw.svg b/docs/images/events/bubble1.excalidraw.svg new file mode 100644 index 000000000..f4b79d101 --- /dev/null +++ b/docs/images/events/bubble1.excalidraw.svg @@ -0,0 +1,16 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1bbVPa2lx1MDAxNv7ur3C4X3pnarrfX85M54yioFSxVk+tPZ5xYlx1MDAxMiElJDRcdCDt9L/fXHUwMDE1UFx1MDAxMt5cdTAwMDIqcHBu80Eh2eysvfZ6nv2slZ2fW9vbhbjXclxuf2xcdTAwMTece8v0XFw7NLuFt8n5jlx1MDAxM0Zu4MMl0v9cdTAwMWVcdTAwMDXt0Oq3rMdxK/rj3bumXHUwMDE5Npy45ZmWY3TcqG16Udy23cCwguY7N3aa0Z/J36rZdN63gqZcdTAwMWSHRnqTXHUwMDFkx3bjIFx1MDAxY9zL8Zym48dcdTAwMTH0/jd8397+2f+bsc52zWbg2/3m/Vx1MDAwYql5nODxs9XA75uKOUKcMCT1sIVcdTAwMWLtw91ix4bLd2Cxk15JTlx1MDAxNXrRt6vuXHUwMDE34pu8yI/l/snt58reSXrbO9fzzuOeN3CEadXboZNejeIwaDiXrlx1MDAxZNeTu4+dXHUwMDFm/i5cbsBcdTAwMDfpr8KgXav7Tlx1MDAxNI38JmiZllx1MDAxYveSc1xiXHLPmn6t30d65j6ZIcVcciQ0JZprLDVVw6vJ77UhMeJcdTAwMTQrjSTmmo3bVVxmPJhcYrDrP6h/pJbdmlajXHUwMDA25vl22kZcdTAwMTFL48yYu4+jVdRgjFx1MDAxMlwiwVxmqlx1MDAxMeHDJnXHrdXjpFxyIYZCTCjJXHUwMDA3t8qY4vSnhGtFqVx1MDAxNul8JbdvXHUwMDFk2f3Q+GfcoXUzbD04rlx1MDAxMCVfMqYnVlx1MDAxZozHVTa2MpNOxFWl7Fx1MDAxZlQ+fyzvX1rfj3ul8/tw2NdIIMbOfVxcXHUwMDE4Xvj19ne3M7tcdTAwMWRp/XbRXHUwMDFiLmituL+6b1x1MDAxZvPDkPpnJdwrnXlfet3p1pphXHUwMDE4dDP9PnxKo6ndss1cdTAwMDEjYCEoSyiDS8SG1z3Xb8BFv+156bnAaqQkspUxeIK7RsafIS5G0fjZR+JcIohSXHUwMDA0WOApiOZcdTAwMTFX/vRtKnFplENcXFx1MDAwMlx1MDAxOVx1MDAwMlx1MDAxMyBcdTAwMGLBXHUwMDA2zPVcdTAwMTLiikPTj1pmXGJ8MIW85HzyXCJcdTAwMTNkRVx1MDAxMJFMJ3S2fLrKj05O5Vx1MDAxM6IzXHKCwI/P3Vx1MDAxZv2lUVx1MDAxOFx1MDAxYyuGiIBBaI24XHUwMDFjaVUym67XXHUwMDFimdd+XHUwMDE4g+W7rdab/2ZdXHUwMDFkOWDCYLlcdTAwMWRpvOu5tSTOXHUwMDBiXHUwMDE2XGbKXHRHIFx1MDAxMLsgXHUwMDA0hlxymq5te5lwtMBcdTAwMDJcdTAwMTP6XGaPXHUwMDE2WZOD0K25vuldjFx1MDAxOJhcdTAwMGLJXHUwMDAxJUzBpFwiszGJwfGYscyiNVx1MDAwZpP5JLWhmKRSXHUwMDFhhDIsZKJcdTAwMTVENjL6XHUwMDFkMGJwwCsgUilBJScrQyU1XHUwMDE0cCSTQlxugShXelxuKqk2XHUwMDE0xVopLjSGcJ5cdTAwMDAp5lxcwigofjpG+6Y+XHUwMDFio09bQTJ2mGG85/q269fgYrr0ParkRTDRR7HVTqzcXHUwMDAxhlx1MDAwNYBzjlxiU8BcdTAwMWNEZFx1MDAxYdXMVlx1MDAxMvRcdTAwMDZcdTAwMTeKSFx1MDAwNbHNlCZYPDRcdTAwMTiuwFx1MDAwNce355tUvPlcdTAwMDbS8NI8s8t2T/rt3a87++VZJjGsMdZIYyqJXHUwMDEyRLFcdKswg+mHmcNEXHUwMDEzglx1MDAwNPydMMszo7hcdTAwMTg0m25cZs7/XHUwMDE4uH487uS+N3dcdTAwMTO011x1MDAxZNNcdTAwMWW/XG7Dyl5cdTAwMWKnhVbS46h4TD9tp7Dpf1x1MDAxOX7+5+3U1juzozk5JuI47W8r+39cdTAwMTajhY5cdTAwMTVcdTAwMGbwPIXVXGK4eFx1MDAxNq1cdTAwMDGSXHRcdTAwMDaxsbjSyJ/nXHJlNaKUQSVcdTAwMTJIJ1x1MDAwYp5iZIzVNJBcdTAwMWWiSFx1MDAwM2q1TtbF1WlccpHOxZDGVKp8XHUwMDFleFx1MDAwYphVipHVZi2pkGp8iM5kpV5FOLBkLL+dWl9PXp5cXHjNXHUwMDFmn2/+wlx1MDAxZr2DYlxye3Xkur1ytJhcXM/t97LyudM9ZvsnxyG3yz3SJmxfLKFfcmlcdTAwMWZcdTAwMWSWXHUwMDFh1onaZfii6Z1cdTAwMWX4X2tL6HdF7n1d3TbE5VGn1PqEb9pRvdHhJXRXtf/vnPuCXGZ2vebOy+On33BBa0vlxoUon3+7u6yfdSp+3Tv+XHUwMDE27CzBXHUwMDBi91fki/zavjmpoHL5XHUwMDE2k2bN6Z0tqT7AJFx1MDAxMZCOrro+QIhW46dcdTAwMWZXbYq51ELRxXOR/LDY1FVb07xVXHUwMDFiUjJDrmnV5lNW7Uxq9LBqKyk4XHUwMDE4K+g6K1x1MDAwMkxohTR6QjxOr1xiLFpcdTAwMDEoPqbnb6795IJrv79OKvReULsuXFz704tcdTAwMDOZPHGkOOA5d6PR/6TSwFx1MDAxYy06Xlx1MDAxYZhr+fM1NkWKzkIrRlxcI0GzYTFcdTAwMGaunVx1MDAxYoJlLf7c2bPo0W3ZP2qflXv/Llxc+Ty0YkFcZqIxpDmSUsGoXHUwMDFhRSucMrhmSlx1MDAwMVx1MDAxMFx1MDAwNWFMrlx1MDAwZaxcdTAwMTkwpFx1MDAxMluMg5VgjDBkY5lq31o09sVheFOMnfaN3K1Wrq7qny5+XHUwMDFjfvitsZelsVfk3tfV7ao09uvywqo09uvygqf3iuq2XFxkRSGc84tcdTAwMGb3tVJpg72w/JRgXlx1MDAwNjN9IGm3XHUwMDBmn3JcdTAwMTSYwpqwpyiwXFyhMSsjoCSjcMc1XHUwMDA2wVRRgejiXHUwMDFhI3/+NlVjyHyNodelMdRcdTAwMTSNISc0htKYScroXG52NMxcdTAwMGJH/IRwfFlCsNeO48B/k5xcdTAwMWLo6uvClVx1MDAxM11cdTAwMTfeXHUwMDBlvnXM0DX9XHUwMDE4pHbUtixcdTAwMTjd7CxBjna+pCxhjphcdTAwMWXPXHUwMDEynjecXFxE56dcdTAwMGV49lNHjFx1MDAwNYQ8hPvimf7ljYjrxdZt1W+ffqrY9ztcdTAwMDeXZ/VNz/SpVlx1MDAwNoaoXHUwMDE1QkHSz4SczFx1MDAxZJCAbjjTjJOV7lx1MDAwNVgsecCISkQ5ZWtOXHUwMDFl0MfK4Un7qnL48axcdTAwMTL39lx1MDAwZXo8OPF/J1x1MDAwZstKXHUwMDFlVuTe19XtqpKH1+WFVSVcdTAwMGavy1x1MDAwYqtKXHUwMDFlXpdcdTAwMTde8DjhmTnJ9IGk3T58yntKwUEkp09cdTAwMTBWlpPgmTlcdFGCXHUwMDEzQcjie1x1MDAwYvKnb0O1XHUwMDBiQzRfu+i1aZdcdTAwMDWTXHUwMDEypSmiXHUwMDAyr0C6LDNcdTAwMWWXnpRUgylcIt5cdTAwMDG8huvOSOZo9Fx1MDAwNTKSeWPJXHUwMDA188z9j1jJmc9cdTAwMWMx0kJLxjPhPVx1MDAwZs75tLmhcKaKXHUwMDE5QiCtklx1MDAwMoLi2YpK/6Gjklx1MDAwNlx1MDAxNZJizYHeOFErrDFgXGaWXGJGXHUwMDE4p5RQwtkkulx1MDAwNTe45lopRGjyglx1MDAwN1x1MDAxZFx1MDAwNztnyXNi8ZyNRM/fXHUwMDAw+Vx1MDAwMrAvuFx1MDAwMXLh3YbIYJgqrFx1MDAwNeVIJvOVaTPYaUhcZlxmPoZlilxuLlx1MDAxNOTakztcclx1MDAxN9pcdTAwMDCZXHUwMDBm6lx1MDAxMZO4XHUwMDEwyVx1MDAwZUBcdTAwMDSrXHUwMDA1pJFcbk/YXHUwMDA0M4+0XHUwMDA0vIE9SMBcZuNcdJte0+7H2ZGcXHUwMDFjXHUwMDEzMZx2t5X9/1xmOpstTmBcdTAwMDKoktn8fVx1MDAxZZvlXHUwMDE3pjeVzSQxINDAXHUwMDEzXGYpxHXqj1x1MDAwMZkpQzCMOaeKXHUwMDBi/qJXw+ZQXHUwMDE5NVx1MDAxOMijxFx1MDAwNM4kKKUpVEZcZlx1MDAwMcJcdTAwMDR0iVJcdTAwMTIxltnv/Vh0oUpcYs1AvKyXzJgmXHUwMDE5sfQvktlcdTAwMGVQXHUwMDA3lVx1MDAwMCTMQEpKJsgkdYCjKbhZUVxuLCM0aM7n0Vl+1XTMqMQmXHUwMDA07UEkSEz0hFEw/UQgcCeiXHUwMDE45CdWr5rOdmaHc3JMXHUwMDA28lx1MDAxM1x0LbdcXCwzr7OOcVx1MDAxYeeYwaLCXHUwMDE3L1x1MDAxNvNcdTAwMWatfetL7XDvwlx1MDAxM7FC3S46vmttOqdcdEZcckWJgHDjXHUwMDEyKzZZK9ZUKFhQYGXNvlT2nPddmSWcO87YJKVcdTAwMTGR9pxcdTAwMTaKM1vQXHUwMDFlOEtCqqVhTp7xXGJoXHUwMDFlZ1xyw2pKyaLt69L9j6/V71cq+u53j3ixcVJ9eSWkKE87ptM+/G7+1Y0vT2k1qsYzXHUwMDFl+i6pXHUwMDEyMn0gabePiJrN36BcdTAwMDKUeMrjsFxccM6qhEiSkzrBIVx1MDAwNVx1MDAxNotcdTAwMDMzf/o2XHUwMDE2mCpcdTAwMGaYmsHStCRg5qpccsKnQJNMpEZcdTAwMThcdTAwMDNXcs7Uup/OPjFcdTAwMWPTWU9cdTAwMGIhmUeGI4WQdJCPhVx1MDAxMKeT2GR8cHpvXHUwMDFhTu/9deHiujDjXHUwMDA1Tj3y46W9wDlnkVx1MDAxOa92TDd4gMmtXHUwMDA3oFx1MDAxN8xW6zxcdTAwMDa/XHUwMDBlXHUwMDA1XGZMnWs/OCf1ZaHjOt29Kbx+1z+SXvs4T1x1MDAwMOUkXHUwMDEz9/PX1q//XHUwMDAxXHUwMDA3vCMgIn0= + + + + App()Container( id="dialog")Button( "Yes", variant="success")Button( "No", variant="error")events.Key(key="T") \ No newline at end of file diff --git a/docs/images/events/bubble2.excalidraw.svg b/docs/images/events/bubble2.excalidraw.svg new file mode 100644 index 000000000..e3e4d2079 --- /dev/null +++ b/docs/images/events/bubble2.excalidraw.svg @@ -0,0 +1,16 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1cXG1T4spcdTAwMTL+7q+wOF/2Vq3ZeX85VVu3XHUwMDE01PXdVVddr6e2YohcdTAwMTBcdFx0Jlx1MDAwMcSt/e+ngyxJeFx0iODi3U1ZXHUwMDAymaHT09P9zNOdXHTfV1ZXXHUwMDBiUadhXHUwMDE3/l4t2Fx1MDAwZpbpOuXAbFx1MDAxN97H51t2XHUwMDEwOr5cdTAwMDdNpPs59JuB1e1ZjaJG+PeHXHUwMDBmdTOo2VHDNS3baDlh03TDqFl2fMPy61x1MDAxZpzIrof/jf9cdTAwMWaadftjw6+Xo8BILrJml53IXHUwMDBmnq5lu3bd9qJcdTAwMTCk/1x1MDAwZj6vrn7v/k9pV3bMuu+Vu927XHKJekKiwbOHvtdVVWpMJNOc9js4YVx0Llx1MDAxNtllaL1cdTAwMDWF7aQlPlVwS+dccr0vNre3qvdRdHrepHf1teSqt47rnkZcdTAwMWT3yVx1MDAwZaZVbVx1MDAwNnbSXHUwMDFhRoFfsy+cclSFdjxwvv+90Fx1MDAwN1x1MDAxMyTfXG78ZqXq2WGY+Y7fMC0n6sTnUDI+06t0ZSRnXHUwMDFl4lx1MDAxZVx1MDAxOFx1MDAxYlgozjiTQlLBkvF2es1cXCiKNSWSQC86oFnRd2EmQLO/UPdIdLsxrVpcdTAwMDVcdTAwMTT0yklcdTAwMWZFLI1To27/XHUwMDFjr6JcdTAwMDZjlFx1MDAxMEmJplx1MDAxYVx1MDAxMd7vUrWdSjWK+1x1MDAxMGIoxISS/OlSKSPZ3UlRQlDCiEh0jK/f2Cl3neOfQZtWzaDRs10hjD+kdI/V3lx1MDAxY/SstHel5t1sX3ok2tza31x1MDAxMZfhiSutVl3gvqyMK0b2Q1ToN/x4nyf24XBcdTAwMTe7Zpl9uSi192osujQv9uhosWZcdTAwMTD47WnlLkjd31xcbKb3+2kvmIjtvUuctNkom09Yg8GtXHUwMDE54kRwOPrtruPVoNFrum5yzrdqXHQ8raT0XHUwMDFkXHUwMDAyxYyeKUTkaixcIjKlkYbwTHSYhIj5Vl5aRFx1MDAxNLmIKIjBJII5QfLliFx1MDAxOFx1MDAwNaZcdTAwMTc2zFx1MDAwMHBmXHUwMDA0KsrJqEiGUJAqzVxilkLPXHUwMDFmXHUwMDA15+mdiVx1MDAxN/hedOo82l1ZXHUwMDA2x4ohXCJcdTAwMTCRWiMuM722zLrjdjJcdTAwMTPbdWPQfL3RePeftKVDXHUwMDFiVOjK5JnO665Tif28YMGg7CBcdTAwMTNcdTAwMDKRXHUwMDAzXGaj36HulMtuylx1MDAxZi3QwFx1MDAwNJnBzjSrvVx1MDAxZjhcdTAwMTXHM92zjIK5IfmE4iNiUlx1MDAwYjYuJqmG6eaYTc9S8peVJY1JgpBBXHUwMDE0xKRElFx0hjHLxCSh2kCEMM41XHUwMDA355dcXCwsJpGhpeSKgzaMyVx1MDAxMVx1MDAwMcm4QVx1MDAxNVx1MDAxMlxuaU0wk1SKwVx1MDAwMMVUUIlcdTAwMTVHM/CUrqazRiggXGKZJULDyFxmolxyxys7Xlx1MDAwNVx1MDAxYZN17yf5niZcIroxbDXDrlxyXHUwMDExo1xu0JMpXHUwMDAwUoKFZDzVrWI24oXIoFx1MDAxOMGUY1x1MDAwNeingIj3OvRcdTAwMTfggu2VJyvFOo9cdTAwMWN92l5v75OrWqd0XCK+XFw0ySil1kArXHJTg5HATFxizaRcdTAwMWVWXG5TQ1x1MDAxMVx1MDAwNViHOcFYa4yHtHLNMCr69bpcdTAwMTOB9Y99x4tcdTAwMDat3DXnelx1MDAxY+xV2yxcdTAwMGa2wqjSbYOo0IglZilp8m41XHSb7of++3/ej+492pnjY9iNXHUwMDEzYSvp13FoXHUwMDE22Fb0XHUwMDE0zCNcdTAwMTCNUDpcdTAwMTbSMIQvl1qpXHUwMDA0KiZhWv4kLymmQXppYIUhX0GUUKF1lmdcdTAwMTCtXGZCMSyGXHUwMDE4QStTfECzOfJcZpFgVFx1MDAxZseUXHUwMDFhwi2CtITVJoV6r5Jfbd7W6N3mbadxb53csk7rlG6ffVre/Opi97zV3melg/2Al7c7pElYScxBLrko73zaqllcdTAwMDdqneGzunu06V1V5iB3QeZ9W2Jr4mKntdU4wd+aYbXW4lvo9rD8x7hLLfaRblx1MDAxZu/fsiNyXiu5XHUwMDFi9p44q1x1MDAxZOzOo0Bycllj1YOz/a/0+HHnq/ulxYLSi+ROKlx1MDAwZYw2UFwi9ueCm0PuuEB44cVcdTAwMDFC2fhlWyhcdTAwMTmTXGKS5J2Tlu18v1jWZZuSvGWbXHUwMDAyRZSvtGzzXHUwMDExy3YqZe4v20RLyqRIxvtcblx1MDAwNVx1MDAwMaZcdTAwMTTCXHUwMDFhP8MjR1x1MDAxN1x1MDAwNKYtXHUwMDAwXHUwMDE0f2bn7669uMEpf7yOK/+uX7kuXFx7o2tcdTAwMDOcZOT0U3/Xvs36/7MqXHUwMDAzXHUwMDEz2OhgZWCi5rPTbHDG8fc3XGLTXGLy0OnD9ZN9ZNPHc+fh6/bxSXX7xrNcdTAwMWXto19cdTAwMWKufGK0XHUwMDFhXHUwMDE4XHUwMDExXHUwMDAx2CgohFx1MDAwMYCTyEQrXHUwMDEz3Fx1MDAxMMCyIVx1MDAxOedap1x1MDAwYlhzXHUwMDBmVo2Gg1VcctdcdTAwMDY0xZhS9dr3ME7XnMvS/tq3b0FJ31xir3VPXHUwMDAzbP3h2PPi2Fx1MDAwYjLv21x1MDAxMrsojv22rOBeXHUwMDE2vfXO1n2FXHUwMDE3afXIosXjqIh+PyvojaK62S6yolx1MDAxMPbp2d5DZWurvbxWWFSqMXd1J2VcdTAwMWGjL5iI7b2bJ6/LpS/jMlxySphcdTAwMWE8nTBcdTAwMTeluKY0YbqTmEu+mZeTuYgsc8lmXHUwMDE5TKLX4i1qXHUwMDA0b1x1MDAxOXFPQ1NcdTAwMWRXilOT8n+YZGw0o8j33sXnnrj6deGrXHUwMDFkXlx1MDAxN94/fWqZgWN6XHUwMDEx0PewaVkwuvGZh8xcbp9T5jGBoVx1MDAwZmZcdTAwMWWzXHInN54npCNCjlx1MDAwYmrOXHUwMDE44/g5NzLXLiufxVWntLPjXHUwMDFjuvbnzm7n7mHpq1x1MDAwN4RcbkNThFx1MDAxNCVcXGlAuYG4hnxcdTAwMDTBeYw4U9BXysVcdTAwMDX2dFx0XHSDMVx0qVx1MDAxN1A7yKWK+uiIq8+HzZ3L5teaf2Fe3W3JP+nIvNKRXHUwMDA1mfeNiV1QOvK2rLCodOSNWWFB6cjbssL8b3wsSN1JWc7oXHUwMDBiJmJ775Ygy+Fjs1x1MDAxY6KB4Ovn3E7JN/OyXHUwMDEyXCKGc1x0XHUwMDExJDqvRYimzHRcdTAwMDRcdTAwMTJUKM5cdTAwMTdQoV3qTOfQXHUwMDFmkVx1MDAxOdiAXHUwMDAzwWunOVx1MDAxM5j/XHUwMDE0ac6kseRG89h9mlx1MDAwNOHxt0fBwbHkWj5j93QuXHUwMDFjL2s8XHUwMDEzajBcdLFEhGSMZm+3UKVcZsA0QZiIN/nSXHUwMDA1XHUwMDA2M8aGXHUwMDEwglx1MDAxMcYpJYAtbDi2IdeK94tCZFx1MDAwMdBcIonpUKgrgCNGOZmhqDH7Rs1cdTAwMTeE+pRcdTAwMWI1p95cdTAwMTOJXGaGYfhgXHUwMDAyKjhHhKhUp6dcdTAwMWSRxMBgZULiXHUwMDFlQilGSa/HM/dp5sd0RicuXHUwMDA0LFx1MDAxNTzeXHRMJUpcdTAwMTC6r1x1MDAxM8w90lJoXHT6IFx1MDAwMXP8tndpjvfl+Fx1MDAxOPLiRNxK+vXZaIY104Onkz2aSkpYtNn0ezTzS+jLWYMlYHkpkFx1MDAwNk+iUjCW2lx1MDAxM/lcdTAwMDRn2oh3XG5cdTAwMGLEqKZcdTAwMDIrNqDYPPFcZmBVXHUwMDExrVx1MDAxMEw2k0IlO1x1MDAxN1x1MDAxMjwjhlx1MDAwMColMFdKXCLGdKoq3Fx1MDAwMzREXHUwMDAwk1x1MDAxNVEzlHNmXHUwMDA3NPjHuUx86Vx1MDAxN1x1MDAwMtpcdTAwMWGgXHUwMDA3zKRgmDGAdSZIqtNcdTAwMTN4gJ0pWFlRXG44I7RmM248z6/FXHUwMDBl6Fx1MDAxNKuEgFx1MDAxZmDALZxQ/tXUvnNcIrrPXHUwMDFjUayUxupNXHUwMDAz2tp4b46PYT9+JqTlXHUwMDE2oWFix6NcdTAwMWFnXHUwMDA0ol1PX4Qu31x1MDAxY1/c3947l6XPx7e6yuT5oW3+WlSjk1BccixvSLA6XHUwMDAx6ytcdTAwMDbeNLwnRlx1MDAwYlx1MDAwZcu6XHUwMDEyWCP2omdp/mKWsG85Y8OQRkSCpklcdTAwMDE6wbVcdTAwMWVmcZhcdTAwMTNccvrMsOl8XHUwMDEyZPXdakTNorTl7IR8XHUwMDE37Z5cdTAwMWNcdTAwMWY+3lhHlebGWvHlJZaiPGqZdvPTvfmlXHUwMDFkXVx1MDAxY9HD8DDam0OJZe7qTiqxjL7glNo6n3evLm4qdrBn1qnliK90s/FtOiv8XHUwMDA0gDz6XGZ/iWstqHQj5djKXHJGgoLLajZ9qpc/fctcbiMyXHUwMDE3RjQ3WFx1MDAxYUZcdTAwMTaX7KWraMmDscPpXHUwMDFjQLtcdTAwMDI6J39B5Wam5+5SlVx1MDAxYoIyZ/uVm2QoPys3divWydizO+9qdufjdeHsujDmyVid+fLcnoydsCZcdTAwMGWWZ0YrPPtcdTAwMDKvUyvWYE1cdTAwMTWmgrDnZC3ty9ZR5+BTZJ5vr31ztrfq7EBtLntcclx1MDAwNlJcdTAwMTFDQqIo4u0jXFxcdTAwMTA+UIVBkDJcbowhhWNAhNGLXHUwMDAy8+VcdTAwMGI8dIOo1LM8r/6SXHUwMDA13lx1MDAxNlx1MDAxYid3ev2uuVtad+W3dus4OKsv71x1MDAwMr8gdecudlx1MDAxMm9cdTAwMTh9wd+HNyg9dkc+iZ+Fxlx1MDAxMLfT3/LJn76lhSeRXHUwMDBiT5RcdTAwMWJoXvA0XHUwMDE33iBjXHUwMDEywyVdwHOvf3hDwlx1MDAxYiastXPgXHJja52pZ6NcdTAwMDb3pXFcdTAwMDSrXHUwMDEzXHUwMDE208dkPkg9KybJq8UkV8JAkGjHv66VpfFcdTAwMWNcdTAwMTkqrktROX6TqS3iavDsgSjhXHUwMDFhXHUwMDA0UTzqXHUwMDA3brgwQC/IXHUwMDFmXHUwMDA0RfG2XzlcXNVkQmtMkX7d2zRwSZz6XHUwMDE1g/lXNfN59Gr6llxiXHUwMDAxnGRIi/hX0SBcdTAwMTVcdTAwMWLxc1x1MDAxYVx1MDAxOEBVXHUwMDAzmGI4YmuyXodnVjXzY3RAJ+B1Or6nT1x1MDAwNJNsSCNhXHUwMDAwwnVnlOk4W6ZDXHUwMDFhvama5rBcdTAwMGZ3T1x1MDAwZrtvXCJpJf36bFwiMb6MyblShKR/X2ZcdTAwMTJmSeteXHUwMDFkXFzV/eKRf3/X1vqiendcdTAwMTUuP2ZJXHUwMDAz+Fx1MDAwM9aKgWdjNlx1MDAwMFxcSFx1MDAxYZpJQYVWWDGxuC3yPFlcdTAwMWJcdTAwMTJcdTAwMTYxjFI0vlx1MDAxZFx0gfeqv8slXHUwMDA00UrNhFJTsIjhfSM3zZub9Fx1MDAxMp+mXHIq03vavSCR31x1MDAxOMdcdTAwMTgyo1x1MDAxOKRcdTAwMDc9TZ5ia6VcdTAwMTe3XHUwMDA1s9E4jcBCfYiDSXDKvWEm8lxuLcdub4zIdm+7Ryy1XHUwMDFir3Fk2PFcdTAwMTR8/7Hy419iJnwqIn0= + + + + App()Container( id="dialog")Button( "Yes", variant="success")Button( "No", variant="error")events.Key(key="T")events.Key(key="T")bubble \ No newline at end of file diff --git a/docs/images/events/bubble3.excalidraw.svg b/docs/images/events/bubble3.excalidraw.svg new file mode 100644 index 000000000..929c598e3 --- /dev/null +++ b/docs/images/events/bubble3.excalidraw.svg @@ -0,0 +1,16 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1cXGtT4khcdTAwMTf+7q+w2C/zVlxy2b5ftmrrLcW7jo6COs7rllx1MDAxNSBChkAwXHReZmv/+3tcdTAwMWGVhFuISlx1MDAxY5hZqlx1MDAxNEiak5PTfZ5+zunT+XtldbVcdTAwMTA9dJ3CXHUwMDFmq1x1MDAwNee+ZntuPbDvXG5cdTAwMWbN8VsnXGJdv1x1MDAwM6dI/3vo94Jav2UzirrhXHUwMDFmv//etoOWXHUwMDEzdT275li3btizvTDq1V3fqvnt393IaYf/Nf9cdTAwMGbttvNn12/Xo8CKL1J06m7kXHUwMDA3j9dyPKftdKJcdTAwMTCk/1x1MDAwZr6vrv7d/5/Qru7abb9T7zfvn4jV41qPXHUwMDFlPfQ7fVUxXHUwMDEzjEmtadzCXHI34GqRU4fT16CxXHUwMDEznzGHXG6ojIvf9s7X179cXInKlVq7O1x1MDAwZsVtfNlr1/PK0YP3aFxiu9bsXHUwMDA1Tnw2jFx1MDAwMr/lnLv1qGmuPnJ88LvQXHUwMDA3XHUwMDFixL9cbvxeo9lxwnDoN37XrrnRgzmG0OCo3Wn0ZcRH7uFbXHUwMDExXHUwMDEzaSmENKeMM0mRXHUwMDFhnO5cdTAwMGKg3FJMacSoXHUwMDE2TGE9oljJ96AnQLHfUP9cdTAwMTWrVrVrrVx1MDAwNujXqcdtXHUwMDE0qWmcuOm759tV1GKMXHUwMDEyXCIpXHUwMDAxiyPCXHUwMDA3TZqO22hGplxyIaAnXHUwMDEzSvLHSyVs5PT7XHUwMDA0K0k04VxcxWeMXHUwMDAy3d16f3T8NWrTplx1MDAxZHSfbFdcYs2XhPJG783RoZVcdTAwMWNeiX7vKSEu9q/0fveb+vL15vtR8M0hXHUwMDAzWUNjMXLuo8LgxD9cdTAwMWb/XHUwMDE1+5OIXHUwMDFkav0x61x1MDAwNbNqe1x1MDAxON3ely/cov50c1rdOTt5cL5cdTAwMWNM1tZcdTAwMGVcdTAwMDL/LiH36VM89nvduv1cYmFYXGLKXHUwMDEwJ4pSJVx1MDAwN+c9t9OCk52e58XH/ForRr2VhMJjYDt0/0mkRWIq0lwixlx1MDAxOEZcdTAwMDLFTj9cdTAwMGJp07tvcZGWpCGtXHUwMDEyluSYXHUwMDAwyLI3I21cdTAwMTTYnbBrXHUwMDA3XHUwMDAwX1x1MDAxM9BWzkZbMo6uSFxuQeBcdTAwMTexYnND13lcdTAwMGXPeFx1MDAxNPidqOx+71x1MDAwZjFhcaxcdTAwMThcIlx1MDAwMlx1MDAxMZjTXHUwMDExl0Ottuy26z1cZnVsf1x1MDAxY4Pma93uh/8kTVx1MDAxZDqgQl8mXHUwMDFmarzmuVxyM9BcdTAwMGI1uCknXHUwMDE48oHIXHUwMDA16jJo0HbrdS8xXHUwMDFla6CBXHIyg90sLMJcdTAwMGbchtuxvcqQgqk++YhcdFx1MDAxM5xcdTAwMTIjoqZ5pVwiSjMmMM7ulKkotahOSYVFXGJFhHCFNNA9OeSURFBcdTAwMTg5XHUwMDAwTkxcdTAwMDKxwFx1MDAwNLP8vNKSWGOsuFx1MDAxMshcZnky7pSMWFRQSsFxXHUwMDE1VShBTZ99VGJGKMOJsZnZR/uqvtZHh9DsXHUwMDA1Plx1MDAxYUZ2XHUwMDEwrbuduttpwMl47nvm9Vl8ou/FtZ7Rsogs8HDJlFSAsIxz6FiVaNewu8aOXHUwMDE2xoJhasBWgcXJU4PBLFxccDr12Vpt75+e7rqk93n74bh1tlx1MDAxM52dlMtfJmlcdTAwMDVKXHUwMDAxeFKBoH9cdTAwMTRHXHUwMDA24GPMXHUwMDFkaKUtpChcdTAwMTdcdTAwMTJTrVx1MDAxMKFyTCnPXHUwMDBlo5LfbrtcdTAwMTFY/7PvdqJRK/fNuWbcvenY9dGzcFPJc6O40DVcdTAwMTKHyW78aTX2m/6Xwee/Pk5sXZw6nM1rbCDH4laS79NcdTAwMTAtcGrRoz9PQDVCKVx1MDAxZj38jGpcdTAwMDQpTVx1MDAwNNeUZoa19F5eVFjDhFqSUcBcdTAwMDPKTPzGYpNcdTAwMThcdFx1MDAxNDNLc1x0IVx1MDAxZPSO0CxHsiFi4jdcdTAwMDAyXHUwMDE1g8VcdTAwMTNyaXBVhlx1MDAxOMmBXFykMWv/vHh60z2tdtTBcfPue2BfXHUwMDE0OXt7eNEtOieSbGh3l2m13ztsse2dvWyEPVXu+d7Z7d1cdTAwMDHb+HRcdTAwMTDw+vZcdTAwMDPpXHUwMDExtiHmIJec13d3tlq1T2qN4UrbO9rsfG3MQW5O5l0usS1xvnu71T3BV72w2brlW+j6sP7LXHUwMDE591xyMexPZIWoe7XT2LzSzmZQxcX6bVx1MDAxOHp7wVx1MDAxY6yAnMrmJ8+XjaPm/c7+4cmmT727RbTurDzJ5Fx1MDAwYsZin+nBVDLKNFx1MDAwN1x1MDAxZVx1MDAxZpPnnPJcdTAwMTnAsqeSXGYstCTwJ7OTjHQ7LyzJwCqVZFBksfchXHUwMDE5fFx1MDAwMslIXHUwMDA0+U8kXHUwMDAzYjiTxGBxv7xDXHUwMDA243FA4lx1MDAxN1xmyMlcdTAwMTmMrFx1MDAxOYvSczrhw2XHnHDrf16aNVx1MDAxMM9vXFxcdTAwMTYuO5OTXHUwMDE5nFxmyVx1MDAxOeQqPOd6ePi/KJUxgzqPpjJmap7qqakxXHUwMDAxxZRMc1dcdTAwMDXhq2RMyMzeeuje4K1GZ/3+XHUwMDAwVa+/XHUwMDFmSeqVSvVcdTAwMWbrrXyms1x1MDAxMqYtRSDiRVx1MDAwNEtBtFx1MDAxYXZWpiAmY1oyyblcdTAwMDY2LvJzVo3GnVWJUWdlSkAkjNk7R1x1MDAwNM4pr9Jcbrxkp7jdunlYXHUwMDBi+MbVv1x1MDAxMcG8XCKCnMy7XFxi84pcYpbLXG55RVx1MDAwNMtlXHUwMDA1T6+XVHW7xEpCOOXK/n1ja2tcdTAwMWXMPSd181xuYJal02bFL5MvXHUwMDE4i3369MPjXHUwMDE3Stj00lx1MDAxN4kp5YLq7Iwo3c5cdTAwMGLLiFg6I5LvxYjUXHUwMDA0RiTHXHUwMDE4kVx1MDAxMlx1MDAxYVEt1E9cdTAwMWS+rPeiyO98MMdcdTAwMWWjgMvChVx1MDAxM15cdTAwMTY+Pn67tVx1MDAwM9fuRFx1MDAxMFx1MDAxOIS9Wlxy7m56TCOHhc8pppnB/UdjmtfdTqpLz1xidMRUvyZaM1xm4Xj2Olx1MDAwYvX5aHf9+MK9q9p2WN6ufPnUPLtf/LRcdTAwMDS1wF9cdTAwMTGXmGBNhGZqxK+xpTA3a5ZcdTAwMTD0UKHy8+uMkY5Qmisk3rls7ZrUKO6dXHUwMDE0XHUwMDBm6qeyhDtei9sg9N9IZ06RTk7mXS6xeUU6y2WFvFwineWyQl6RznJZIa+VmmWxwqxcdTAwMDBq8lx1MDAwNWOxT59cdTAwMTYggOIpXHUwMDAxlOSSMMmy71x1MDAxZEi386IyLTWDaIn3XCJa2Vx1MDAwMijGNCNKi18tgDr0J1x1MDAwNFx1MDAxY1x1MDAwZaBL8N7R04yAXCJD9DTrXlKdeWolLEE4bTlcdTAwMTczRjnPXHUwMDFlN6WD/KJ6M5FcdTAwMTbjlFIpkWCE0kSioe/OiFuYXHUwMDEwrCQ2ldRU8vz8XHUwMDE5Y0tcYlDC6ENcdTAwMDBq2bh7XHUwMDBibnHNtTK1klx1MDAxYUlMR71cdTAwMWSASVxipKR8ube/vlx1MDAxNvbls09Cj2m1sHFcdTAwMWQpw5RcdTAwMTNcdTAwMTiLVEwpbSVcdTAwMTZcdTAwMDazXHUwMDExYlpcYqVcdTAwMThN1F1mqV59ajy7XHUwMDEyNtZcdKzMIYBFlMGYQDHqXHUwMDBldILORFpcbi1BXHUwMDFmJKDT8DSdJsPDmE7LVFxiO30om9fYII7FrSTfX17ar6fndylcZiCzuzE7nqVn/Vx1MDAxN1x1MDAxNc+oNs6AXHUwMDE52JxcdTAwMTKAcFx1MDAxZM+hj3gmLKpcdTAwMDW4kaaaijw33GBqXHUwMDAxXHUwMDAz0lxuQWczKdSE2n5BLKEpXHUwMDEywJeURKBsXHUwMDAyXZ/YXHUwMDBil4hcdTAwMDPAvGJBfEHxrFxi4EFNQVx1MDAwZXRcdTAwMGUnkokkWD1iXHUwMDA3XHUwMDE4joLZlFmQXHUwMDEwQidKjHLCM6OTUcmsXHRggC1cdTAwMWOXJMeARi1cIlx1MDAxMNhcdTAwMDdRrJTGappOk5PFS41nxemD2bzGh/FcdTAwMGJcdTAwMTEtNbut6PRdhH1cdTAwMTcnmGRHtcqD2yxcdTAwMWbcOXelXHUwMDEz51t5reGExW/7P1x1MDAxNtXoLFAjXHUwMDE0XHUwMDBmr1mNRFxcxvxYXHUwMDEyafBcZiVrml6zXZvVhHPNXHUwMDE5XHUwMDFiRzSSXGLm4sx2XGZcdTAwMTPP+5GwMpumKMlhP9JgXFxNyFrUrs+PXHUwMDBmZH2v2brxvuCLw+8n9tbW25MhJXl0azu9nVx1MDAxYvv0Ljo/oofhYbQ/WeyLcjc5qTt3sbNyN5MvXHUwMDE4i31cdTAwMDaAlNlcdTAwMDaQN7FoklPuRsrpqVx1MDAxYlxmsIY4kLXMMJJu5kWFXHUwMDExkVx1MDAwMiPgs1x1MDAxNk7AyJtQJJVcdTAwMTlcdTAwMTE+XHUwMDAxR8hYKIcl41xuLvRcdTAwMDNcdTAwMTI3r6I+icRcckFDR1x1MDAwN4mb+FaeXHUwMDEzN86t0cnad1x1MDAxZT60nIc/L1x1MDAwYpXLwpStx3rox3PbejxjQlx1MDAxY83OTFb49bO7ToT5Y25JsKZYJ1x1MDAxZe0xyy29mzL7vHn/0Gxvbbf13s5xuOuvL7hbXHUwMDAy+lhcXDFNuJkzXHUwMDA14SNcdTAwMDX1hFimWFx1MDAxOUJ/XHUwMDA2nFx1MDAxOck37UZ++/RuXCIrjV61cP2W2f1KoIvazvrx1jndq57tn7T8489cdTAwMWKLO7vnpO6yiJ1FXHUwMDFhJl8wo7a9av18h1UrN3tFtibaR9VquSmz9VlcdTAwMDYyXCI1obk/XHUwMDE5RemU3cpcdTAwMTBgccpU9pgmvftcdTAwMTZcdTAwMTX1eCrqcWzJuaHePOhcYjFpXHUwMDAxjvi7Plx0XHUwMDA1hiPl6K1PQlkmOjJjXHUwMDA2z5uOYESmZ1x1MDAxYrCCQFx1MDAwMebj7Cu862u0pfhOY/v+rHTmS1x1MDAxNnpnQWvRc6jY5EiVwIRcIoa0XHUwMDEymlxyuSZcdTAwMTbKXHUwMDEyZiVcXFJcdTAwMTO64eRcIsyPICRcXDNO2KtcdTAwMTZ430JIPt/qYD3c6V03v29ffN3arGzc3PdcdTAwMTaXkOSk7nKJ3f3aq5xViN495Vx1MDAxN2frd07P35XeXCJcdTAwMWF3XHUwMDE2f5p8wV+HP+lEknPsXHUwMDE5nlx1MDAxOFQwXHUwMDBm1MmM0undt6gojXEqSmtl4bmh9Fxc8jlcdTAwMTA2coRkXHUwMDFlmztTs4uYs7dW4ixcdTAwMTODmsE55sCgpi5AJ+w84pVSUayZVNl3XHUwMDE3paPUi5ySvJtT9ndcdTAwMTcxyoCPYE6EVMOrz1x1MDAxNElLcCxcdTAwMTXSgmutpu8ucoSUb/FJ80g0ZtZhOFZUMIU4nvDAR6YsXHUwMDAwXHUwMDBlwqniXHUwMDEwclJBx6rnXGaESCQ1eueCXHUwMDFhXHUwMDA1XHUwMDE4zl/jtFx1MDAxOVx1MDAxZi6XXHUwMDFlZqxcdTAwMGU/xo3AZKKRYFx1MDAxY1BUUJoo5nheXHUwMDFiZsCIuVx1MDAwNlNKhVx1MDAxOcGDko5cdTAwMTc+XFwu3XVXh1x1MDAxNqxcdTAwMTElSsFVXHUwMDExNzU/motxtWBcdTAwMDZgWkPgypVCMFewMa2Walx1MDAxMTptTPdcdTAwMWKMXHUwMDBm51jmSvL9pXRcdTAwMDMnZrNcdTAwMTFgY0pTpCnLXHUwMDBlbFx1MDAwN8726VXpdLN4XqX8XHUwMDFi2S6R7drJwlx1MDAwM5tcdTAwMTRcdTAwMTYxS/9gdCBcdTAwMTRkeO2ISPPgOU7MRkXoIMzyq1x1MDAxMkzkX2KuMVY2Y8aAIFi9K9VcdTAwMTCCU07zWjtcdTAwMWEv+q32qtUkXHUwMDBmSHJcdTAwMGI11DprIW/kd6fRiqG7XHUwMDE45Vx1MDAxME+aPPrWypNcdTAwMDdcdTAwMTfsbrdcdTAwMWOBhVx1MDAwNoBcdTAwMDed4NafbjOWV7h1nbv1XHSZgev+y0jt+6vxXGbHdMHf/6z8839f4TJcdTAwMTMifQ== + + + + App()Container( id="dialog")Button( "Yes", variant="success")Button( "No", variant="error")events.Key(key="T")events.Key(key="T")events.Key(key="T")bubble \ No newline at end of file diff --git a/src/textual/message.py b/src/textual/message.py index 63be90749..a936af780 100644 --- a/src/textual/message.py +++ b/src/textual/message.py @@ -71,10 +71,11 @@ class Message: @property def handler_name(self) -> str: + """The name of the handler associated with this message.""" # Property to make it read only return self._handler_name - def set_forwarded(self) -> None: + def _set_forwarded(self) -> None: """Mark this event as being forwarded.""" self._forwarded = True @@ -90,7 +91,8 @@ class Message: return False def prevent_default(self, prevent: bool = True) -> Message: - """Suppress the default action. + """Suppress the default action(s). This will prevent handlers in any base classes + from being called. Args: prevent (bool, optional): True if the default action should be suppressed, diff --git a/src/textual/scroll_view.py b/src/textual/scroll_view.py index cf61f13e2..dc0842ce1 100644 --- a/src/textual/scroll_view.py +++ b/src/textual/scroll_view.py @@ -71,6 +71,22 @@ class ScrollView(Widget): def watch_virtual_size(self, virtual_size: Size) -> None: self._scroll_update(virtual_size) + def watch_show_horizontal_scrollbar(self, value: bool) -> None: + """Watch function for show_horizontal_scrollbar attribute. + + Args: + value (bool): Show horizontal scrollbar flag. + """ + self.refresh(layout=True) + + def watch_show_vertical_scrollbar(self, value: bool) -> None: + """Watch function for show_vertical_scrollbar attribute. + + Args: + value (bool): Show vertical scrollbar flag. + """ + self.refresh(layout=True) + def _size_updated( self, size: Size, virtual_size: Size, container_size: Size ) -> None: diff --git a/src/textual/widget.py b/src/textual/widget.py index 861dcbe54..cfa3d2f28 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -234,10 +234,10 @@ class Widget(DOMNode): Args: value (bool): Show horizontal scrollbar flag. """ - self.refresh(layout=True) - # if not value: - # # reset the scroll position if the scrollbar is hidden. - # self.scroll_to(0, 0, animate=False) + # self.refresh(layout=True) + if not value: + # reset the scroll position if the scrollbar is hidden. + self.scroll_to(0, 0, animate=False) def watch_show_vertical_scrollbar(self, value: bool) -> None: """Watch function for show_vertical_scrollbar attribute. @@ -245,10 +245,10 @@ class Widget(DOMNode): Args: value (bool): Show vertical scrollbar flag. """ - self.refresh(layout=True) - # if not value: - # # reset the scroll position if the scrollbar is hidden. - # self.scroll_to(0, 0, animate=False) + # self.refresh(layout=True) + if not value: + # reset the scroll position if the scrollbar is hidden. + self.scroll_to(0, 0, animate=False) def mount(self, *anon_widgets: Widget, **widgets: Widget) -> None: """Mount child widgets (making this widget a container). @@ -507,7 +507,7 @@ class Widget(DOMNode): elif overflow_y == "auto": show_vertical = self.virtual_size.height > height - if show_vertical and not show_horizontal: + if show_vertical and not show_horizontal and overflow_x == "auto": show_horizontal = ( self.virtual_size.width + styles.scrollbar_size_vertical > width ) @@ -853,7 +853,7 @@ class Widget(DOMNode): y (int | None, optional): Y coordinate (row) to scroll to, or None for no change. Defaults to None. animate (bool, optional): Animate to new scroll position. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if the scroll position changed, otherwise False. @@ -895,8 +895,8 @@ class Widget(DOMNode): scroll_y = self.scroll_y self.scroll_target_y = self.scroll_y = y scrolled_y = scroll_y != self.scroll_y - if scrolled_x or scrolled_y: - self.refresh(repaint=False, layout=True) + # if scrolled_x or scrolled_y: + # self.refresh(repaint=False, layout=False) return scrolled_x or scrolled_y @@ -916,7 +916,7 @@ class Widget(DOMNode): y (int | None, optional): Y distance (rows) to scroll, or ``None`` for no change. Defaults to None. animate (bool, optional): Animate to new scroll position. Defaults to False. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if the scroll position changed, otherwise False. @@ -941,7 +941,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -962,7 +962,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -986,7 +986,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1008,7 +1008,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1030,7 +1030,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1052,7 +1052,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1074,7 +1074,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1099,7 +1099,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1124,7 +1124,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1151,7 +1151,7 @@ class Widget(DOMNode): Args: animate (bool, optional): Animate scroll. Defaults to True. speed (float | None, optional): Speed of scroll if animate is True. Or None to use duration. - duration (float | None, optional): Duration of animation, if animate is True and speed is False. + duration (float | None, optional): Duration of animation, if animate is True and speed is None. Returns: bool: True if any scrolling was done. @@ -1408,8 +1408,8 @@ class Widget(DOMNode): self._container_size = container_size if self.is_scrollable: self._scroll_update(virtual_size) - self.refresh(layout=True) - self.scroll_to(self.scroll_x, self.scroll_y) + # self.refresh(layout=True) + # self.scroll_to(self.scroll_x, self.scroll_y) else: self.refresh()