peterbrittain / asciimatics

A cross platform package to do curses-like operations, plus higher level APIs and widgets to create text UIs and ASCII art animations
Apache License 2.0
3.61k stars 238 forks source link

Stop animation conditionally #338

Closed snooppr closed 2 years ago

snooppr commented 2 years ago

Sorry to write as a feature request.

Can you help me figure out how to stop the animation (not with the 'x-q' keys, but by condition, for example, after playing the last frame of the scene). Looking at the documentation, I see that the 'StopApplication' exception needs to be thrown, but I don't understand the logic.

How do I fix the code so that the animation closes after the "I'm" scene? For example.

#!/usr/bin/env python3

from asciimatics.renderers import FigletText, Fire
from asciimatics.scene import Scene
from asciimatics.screen import Screen
from asciimatics.effects import Print
from asciimatics.exceptions import ResizeScreenError
from pyfiglet import Figlet
import sys

def demo(screen):
    scenes = []

    effects = [
        Print(screen,
              Fire(screen.height, 80, "*" * 70, 0.8, 60, screen.colours,
                   bg=screen.colours >= 256),
              0,
              speed=1,
              transparent=False),
        Print(screen,
              FigletText("Help!", "banner3"),
              (screen.height - 4) // 2,
              colour=Screen.COLOUR_BLACK,
              speed=1,
              stop_frame=30),
        Print(screen,
              FigletText("I'm", "banner3"),
              (screen.height - 4) // 2,
              colour=Screen.COLOUR_BLACK,
              speed=1,
              start_frame=30,
              stop_frame=50),
        Print(screen,
              FigletText("on", "banner3"),
              (screen.height - 4) // 2,
              colour=Screen.COLOUR_BLACK,
              speed=1,
              start_frame=50,
              stop_frame=70),
        Print(screen,
              FigletText("Fire!", "banner3"),
              (screen.height - 4) // 2,
              colour=Screen.COLOUR_BLACK,
              speed=1,
              start_frame=70),
    ]
    scenes.append(Scene(effects, 100))

    screen.play(scenes, stop_on_resize=True)

if __name__ == "__main__":
    while True:
        try:
            Screen.wrapper(demo)
            sys.exit(0)
        except ResizeScreenError:
            pass

I have tried from asciimatics.exceptions import ResizeScreenError, StopApplication and throw an exception, but the animation keeps looping anyway.

peterbrittain commented 2 years ago

There are many ways you can control the end of the animation. If you know the exact timing, you can just set the duration of the Scene and make sure that you don't loop playback (by setting repeat=False when you call play).

If you need to tie it to something else to trigger it, you need your application to throw the exception inside the play loop. That typically means you need to handle it inside input/output handling for the classes (so typically process_event or update / _update).

If you want to see some examples, search for raise in the sample code.