textual icon indicating copy to clipboard operation
textual copied to clipboard

Repair broken embedded rich terminal example.

Open traveller1011 opened this issue 5 months ago • 4 comments

Part 1/2: Broken rich terminal example

Heads up - one of the embedded rich terminals examples (in the Animation section of the online Textual Guide) is seemingly malfunctioning.

I figure it may be worth looking into in case the root cause is something systemic that affects other rich terminal examples (none I saw though).

  • This particular example is small and focused, doesn't seem like one you would modify much
  • It almost certainly worked previously, or someone else would have reported it

For these reasons it seems plausible a systemic problem could be afoot.

The problem is here:

https://textual.textualize.io/guide/animation/#__tabbed_1_3

The symptoms are

  • the default blue circle tab is 100% fine
  • the red circled tabs all render as blank.

image

Part 2/2 - offsetting animate calls results in no animation at all

I don't think this is a bug. But nor did I see any remark in the documentation. And since we are talking about animations ill briefly share.

When you animate a button to become invisible over 2 second duration, then immediately reverse than animation to full opacity over another 2 second duration, no animation happens at all.

See the comments in the on_mount() method below:

class MenuSideBar(Container):
    CSS_PATH = MAIN_APP_STYLES

    button_events: Button

    def compose(self) -> ComposeResult:
        with VerticalScroll(id="sidebar_vscroll"):
            yield Button("Settings", id="btn_settings")
            yield Button("Accounts", id="btn_accounts")
            yield Button("Strategies", id="btn_strategies")
            yield Button("Instruments", id="btn_instruments")

            # randomly caching one button into self (to animate it for fun)
            self.button_events = Button("Events", id="btn_events")
            yield self.button_events

            yield Button("Charts", id="btn_charts")
            yield Button("System", id="btn_system")
            yield Button("Developer", id="btn_developer")
            yield Button("Bootup App", id="btn_start_background_services")
            yield Button("Exit", id="btn_exit")

    def on_mount(self):
        # TEXTUAL TEAM - see next two lines
        self.button_events.styles.animate("opacity", value=0.0, duration=2.0)     # <<< this works great running alone
        self.button_events.styles.animate("opacity", value=1.0, duration=2.0)     # <<< but add another animate here, and then no animation happens at all

I seriously am loving Textual, including the docs. Thanks you team Textual.

traveller1011 avatar Feb 04 '24 21:02 traveller1011

We found the following entries 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

github-actions[bot] avatar Feb 04 '24 21:02 github-actions[bot]

On point 2: it's because you're essentially overriding the first animation with the second. This is where you'd use on_complete. For example:

from functools import partial

from textual.app import App, ComposeResult
from textual.widgets import Button

class HideThenShowApp(App[None]):

    def compose(self) -> ComposeResult:
        yield Button("Watch me disappear then appear!")

    def on_mount(self) -> None:
        self.query_one(Button).styles.animate(
            "opacity",
            value=0.0,
            duration=2.0,
            on_complete=partial(
                self.query_one(Button).styles.animate,
                "opacity",
                value=1.0,
                duration=2.0
            )
        )

if __name__ == "__main__":
    HideThenShowApp().run()

Remember: the call to animate isn't blocking.

davep avatar Feb 05 '24 10:02 davep

Good spot regarding the broken examples in the docs! Just to clarify in case there's any confusion, these are only screenshots rather than "embedded terminals".

This has been reported and fixed once before, but there must have been a regression after changes to the code to generate the screenshots.

TomJGooding avatar Feb 05 '24 22:02 TomJGooding

Thank you both for writing back. Regarding point 2 animation-- i did figure out to use a callback several hours later... And instantly felt dumb reflecting about (this) earlier GH issue :)

    async def on_blur(self, _: events.Blur) -> None:
        # ....
        self.styles.animate("background", value="green", duration=1.0, on_complete=self._restore_orig_background_color)
        self.notify(f"Successfully updated {save_field} with new value: {new_value}")

    def _restore_orig_background_color(self):
        self.styles.animate("background", value=self._orig_styles_background, duration=1.0)

... what i did not figure out was your nifty use of partial, cheers to that idea.

ok i must return to building.

good afternoon and thanks again!

traveller1011 avatar Feb 06 '24 20:02 traveller1011

I spotted the PR didn't link to this issue, but the animation example will be fixed by #4226 once the updated docs have been deployed.

TomJGooding avatar Feb 27 '24 18:02 TomJGooding

As identified by Tom above, this is fixed by #4226 -- confirmed locally; just needs the docs to be published. Closing as done.

davep avatar Mar 11 '24 09:03 davep

Don't forget to star the repository!

Follow @textualizeio for Textual updates.

github-actions[bot] avatar Mar 11 '24 09:03 github-actions[bot]