gyscos / cursive

A Text User Interface library for the Rust programming language
MIT License
4.27k stars 243 forks source link

Lifecycle events? #280

Open inferiorhumanorgans opened 6 years ago

inferiorhumanorgans commented 6 years ago

It would be nice to be able to register a callback for various lifecycle events (e.g. create, draw, destroy) for the views. My current use case is displaying a splash screen and letting something happen. For my use some sort of blocking interface would be fine, however pulling the aync stuff from the progress bar view would also be quite useful.

gyscos commented 6 years ago

Hi, and thanks for the report!

Could you tell us more about your splash-screen use-case? Do you want to listen for new views being added? For views being removed from the tree?

inferiorhumanorgans commented 6 years ago

I'd like to be able to:

I can use callbacks for a splash screen easily enough, but I'd also like to display some sort of box for a potentially long-running function (e.g. serial communication) where the overhead of passing data back and forth between threads is unwarranted.

I've tried to do this synchronously:

However, the initial add_layer isn't drawn until after the second step finishes. If I add a call to Cursive.step between steps 1 and 2, the app displays the initial dialog but then blocks until an event (e.g. key press) and then continues. Forcing cursive to redraw would work too.

gyscos commented 6 years ago

In general I'd really advise against running long things in the main UI thread. Running the task asynchronously lets you show a progress bar, lets the user interrupt it with some action, or just provide overall better responsiveness (for example react to resized window). And, as you noticed, it's easier to integrate with cursive.

If you really want to run the computation logic in the same thread (if your data isn't Send and was created in the wrong thread for some reasons), you may use Cursive::step as you did, but before that, send a dummy callback to Cursive::cb_sink. This will cause Cursive::step to return immediately (executing the dummy callback) instead of waiting for an input.