From 2afe9787c207b6a969aa20bbab1ebbb4e9ac7b3f Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Sat, 20 Aug 2016 01:22:07 -0700 Subject: [PATCH] Add second tutorial --- Readme.md | 7 +- doc/tutorial_1.md | 2 +- doc/tutorial_2.md | 215 +++++++++++++++++++++++++++++++++++++++++++++ doc/tutorial_2.png | Bin 0 -> 4725 bytes 4 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 doc/tutorial_2.md create mode 100644 doc/tutorial_2.png diff --git a/Readme.md b/Readme.md index 087bb1c..8c87cc0 100644 --- a/Readme.md +++ b/Readme.md @@ -59,7 +59,12 @@ Check out the other [examples](https://github.com/gyscos/Cursive/tree/master/exa _(Colors may depend on your terminal configuration.)_ -You may also have a look at the [tutorial](https://github.com/gyscos/Cursive/tree/master/doc/tutorial_1.md). +## Tutorials + +These tutorials may help you get started with cursive: + +* [Starting with cursive: Basics](https://github.com/gyscos/Cursive/tree/master/doc/tutorial_1.md) +* [Starting with cursive: Intermediate](https://github.com/gyscos/Cursive/tree/master/doc/tutorial_2.md) ## Goals diff --git a/doc/tutorial_1.md b/doc/tutorial_1.md index ec808fa..e967234 100644 --- a/doc/tutorial_1.md +++ b/doc/tutorial_1.md @@ -3,7 +3,7 @@ ## Target goal In this first tutorial, we'll learn the basics of cursive, -and write a very basic first application: +and write a very basic first application: ```rust extern crate cursive; diff --git a/doc/tutorial_2.md b/doc/tutorial_2.md new file mode 100644 index 0000000..6f20468 --- /dev/null +++ b/doc/tutorial_2.md @@ -0,0 +1,215 @@ +# Starting with cursive: Intermediate + +## Target goal + +This time, we'll work on a slightly bigger example, where the user will need to +actually make some choices. Here is what the code will look like: + +```rust +extern crate cursive; + +use cursive::Cursive; +use cursive::views::Dialog; + +fn main() { + let mut siv = Cursive::new(); + + siv.add_layer(Dialog::text("This is a survey!\nPress when you're ready.") + .title("Important survey") + .button("Next", show_next)); + + siv.run(); +} + +fn show_next(s: &mut Cursive) { + s.pop_layer(); + s.add_layer(Dialog::text("Did you do the thing?") + .title("Question 1") + .button("Yes!", |s| show_answer(s, "I knew it! Well done!")) + .button("No!", |s| show_answer(s, "I knew you couldn't be trusted!")) + .button("Uh?", |s| s.add_layer(Dialog::info("Try again!")))); +} + +fn show_answer(s: &mut Cursive, msg: &str) { + s.pop_layer(); + s.add_layer(Dialog::text(msg) + .title("Results") + .button("Finish", |s| s.quit())); +} +``` + +Tutorial 2 goal + +## Preparation + +This time you're not a beginner anymore, so we'll skip the introduction! +Let's start from a basic cursive application: + +```rust +extern crate cursive + +use cursive::Cursive; + +fn main() { + let mut siv = Cursive::new(); + + siv.run(); +} +``` + +## Dialogs + +Instead of directly using a [`TextView`], we'll use a [`Dialog`] this time. +A dialog is wrapper with a frame around another view, and optionally a title +and/or buttons. + +[`Dialog::new`] directly takes a view, so we'll directly give it the +`TextView`: + +```rust +extern crate cursive; + +use cursive::Cursive; +use cursive::views::Dialog; +use cursive::views::TextView; + +fn main() { + let mut siv = Cursive::new(); + + siv.add_layer(Dialog::new(TextView::new("..."))); + + siv.run(); +} +``` + +Since creating a `Dialog` around a `TextView` is a pretty common task, +[Dialog::text`] is a shortcut function that directly does that. Our line +becomes a little shorter (and we don't need to import +`cursive::views::TextView` anymore): + +```rust +siv.add_layer(Dialog::text("...")); +``` + +Next, let's add a title. To do that, `Dialog` has a chainable [`Dialog::title`] +method. It takes the dialog by value, and return it back, making function +chains easy: + +```rust +siv.add_layer(Dialog::text("...").title("...")); +``` + +This way of chaining method to set-up the view is very common in cursive. Most +views provide chainable variants of their methods, to allow creating the view +and configuring it in one spot. + +[`Dialog::title`]: http://gyscos.github.io/Cursive/cursive/views/struct.Dialog.html#method.title + +## Buttons + +Our dialog looks better than a `TextView` alone, but it's still missing some +action. Adding some buttons there will help. + +Just like with the title, `Dialog` has a [`Dialog::button`] method to add a +button in a chain. This method takes a label and a callback, the same kind +we saw in the previous tutorial: + +```rust +siv.add_layer(Dialog::text("...") + .title("...") + .button("Quit", |s| s.quit())); +``` + +Only this time, we don't want to exit the application right away. Instead of +packing everything into the closure, let's use a separate function for the +callback. Here is the current state: + +```rust +extern crate cursive; + +use cursive::Cursive; +use cursive::views::Dialog; + +fn main() { + let mut siv = Cursive::new(); + + siv.add_layer(Dialog::text("This is a survey!\nPress when you're ready.") + .title("Important survey") + .button("Next", show_next)); + + siv.run(); +} + +fn show_next(s: &mut Cursive) { + // Empty for now +} +``` + +## Layers + +After the user presses the `` button, we want to hide the current popup +and show a new one instead. We'll use [`Cursive::pop_layer`] to do that. + +Then, we add a new `Dialog`, this time with a few more buttons: + +```rust +fn show_next(s: &mut Cursive) { + s.pop_layer(); + s.add_layer(Dialog::text("Did you do the thing?") + .title("Question 1") + .button("Yes!", |s| ()) //< Do something interesting here... + .button("No!", |s| ()) //< And here as well... + .button("Uh?", |s| ()); //< And finally here too. +} +``` + +As you see, `Dialog::button()` can be called several times to add more buttons. + +The `` button will add a new popup, without removing the current one: +it'll act as a dismissable infobox. `Dialog::info()` is a shortcut to build +such a popup: + +```rust +fn show_next(s: &mut Cursive) { + s.pop_layer(); + s.add_layer(Dialog::text("Did you do the thing?") + .title("Question 1") + .button("Yes!", |s| ()) //< We'll fill this callback soon, + .button("No!", |s| ()) //< along with this one. + .button("Uh?", |s| s.add_layer(Dialog::info("Try again!")))); +} +``` + +Finally, let's have the "Yes" and "No" buttons use the same callback method to +print a message, but with a different text parameter: + +```rust +fn show_next(s: &mut Cursive) { + s.pop_layer(); + s.add_layer(Dialog::text("Did you do the thing?") + .title("Question 1") + .button("Yes!", |s| show_answer(s, "I knew it! Well done!")) + .button("No!", |s| show_answer(s, "I knew you couldn't be trusted!")) + .button("Uh?", |s| s.add_layer(Dialog::info("Try again!")))); +} + +fn show_answer(s: &mut Cursive, msg: &str) { + s.pop_layer(); + s.add_layer(Dialog::text(msg) + .title("Results") + .button("Finish", |s| s.quit())); +} +``` + +Here, `show_answer()` does the same thing: remove the previous layer, and add +a new `Dialog` instead. + +[`Cursive::pop_layer`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.pop_layer + +## Conclusion + +Your code should now look like the one at the top of this guide. + +As you've seen, the `Dialog` view is a nice way to present a `TextView`, but it +works with any other content. Actually, most layers you'll add will start with +a `Dialog` wrapping some other view. diff --git a/doc/tutorial_2.png b/doc/tutorial_2.png new file mode 100644 index 0000000000000000000000000000000000000000..2936b331d7e0287800efee26cf2b7242a8609c92 GIT binary patch literal 4725 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 WugPOlOd>#Vf$ms*S8>brhyMcSS6xT| literal 0 HcmV?d00001