mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Merge branch 'master' into scroll
This commit is contained in:
commit
f0b3287d73
11
.travis.yml
11
.travis.yml
@ -4,11 +4,6 @@ rust:
|
|||||||
- stable
|
- stable
|
||||||
- nightly
|
- nightly
|
||||||
script:
|
script:
|
||||||
- cargo build --verbose
|
- cargo check --all-features
|
||||||
- cargo test --verbose
|
- cargo build --verbose --features "pancurses-backend termion-backend"
|
||||||
-
|
- cargo test --verbose --features "pancurses-backend termion-backend"
|
||||||
- cargo build --verbose --features=pancurses-backend --no-default-features
|
|
||||||
- cargo test --verbose --features=pancurses-backend --no-default-features
|
|
||||||
-
|
|
||||||
- cargo build --verbose --features=termion-backend --no-default-features
|
|
||||||
- cargo test --verbose --features=termion-backend --no-default-features
|
|
||||||
|
25
CHANGELOG.md
25
CHANGELOG.md
@ -1,6 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## Next version: 0.8.2
|
## Next version: 0.9.0
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
- Make backend a dynamic choice
|
||||||
|
- User must select a backend in `Cursive::new`
|
||||||
|
- 3rd party libraries do not need to play with backend features anymore
|
||||||
|
- Add `StackView::find_layer_from_id`
|
||||||
|
- Add `SelectView::insert_item`
|
||||||
|
- Add `TextArea::{enable, disable}`
|
||||||
|
- Reworked `AnyView`
|
||||||
|
- `SelectView`: Fix mouse events
|
||||||
|
- Return callbacks from manual control methods
|
||||||
|
- `SelectView::{set_selection, select_up, select_down, remove_item}`
|
||||||
|
- `EditView::{set_content, insert, remove}`
|
||||||
|
- Add `rect::Rect`
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
- Renamed `Vec4` to `Margins`
|
||||||
|
- `Callbacks` cannot be created from functions that return a value
|
||||||
|
- The returned value used to be completely ignored
|
||||||
|
- `AnyView` does not extend `View` anymore (instead, `View` extends `AnyView`)
|
||||||
|
- If you were using `AnyView` before, you probably need to replace it with `View`
|
||||||
|
|
||||||
|
|
||||||
## 0.8.1
|
## 0.8.1
|
||||||
|
@ -9,7 +9,7 @@ license = "MIT"
|
|||||||
name = "cursive"
|
name = "cursive"
|
||||||
readme = "Readme.md"
|
readme = "Readme.md"
|
||||||
repository = "https://github.com/gyscos/Cursive"
|
repository = "https://github.com/gyscos/Cursive"
|
||||||
version = "0.8.2-alpha.0"
|
version = "0.9.0-alpha.0"
|
||||||
[badges.travis-ci]
|
[badges.travis-ci]
|
||||||
repository = "gyscos/Cursive"
|
repository = "gyscos/Cursive"
|
||||||
|
|
||||||
@ -23,6 +23,7 @@ toml = "0.4"
|
|||||||
unicode-segmentation = "1.0"
|
unicode-segmentation = "1.0"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.1"
|
||||||
xi-unicode = "0.1.0"
|
xi-unicode = "0.1.0"
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
[dependencies.maplit]
|
[dependencies.maplit]
|
||||||
optional = true
|
optional = true
|
||||||
@ -61,6 +62,7 @@ version = "1.5.0"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
|
pretty-bytes = "0.2.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
blt-backend = ["bear-lib-terminal"]
|
blt-backend = ["bear-lib-terminal"]
|
||||||
|
@ -12,7 +12,7 @@ use cursive::Cursive;
|
|||||||
use cursive::views::TextView;
|
use cursive::views::TextView;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_global_callback('q', |s| s.quit());
|
siv.add_global_callback('q', |s| s.quit());
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ extern crate cursive;
|
|||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.run();
|
siv.run();
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ It's rather easy to identify the two steps involved.
|
|||||||
If you run this, you'll get an empty blue terminal, with no way of properly
|
If you run this, you'll get an empty blue terminal, with no way of properly
|
||||||
leaving the application (you'll have to press <Ctrl-C> to kill it).
|
leaving the application (you'll have to press <Ctrl-C> to kill it).
|
||||||
|
|
||||||
[`Cursive`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html
|
[`Cursive`]: https://docs.rs/cursive/0/cursive/struct.Cursive.html
|
||||||
|
|
||||||
## Interactivity
|
## Interactivity
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ extern crate cursive;
|
|||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_global_callback('q', |s| s.quit());
|
siv.add_global_callback('q', |s| s.quit());
|
||||||
|
|
||||||
@ -128,10 +128,10 @@ fn main() {
|
|||||||
As expected, running it show no visible change, but hitting the `q` key at
|
As expected, running it show no visible change, but hitting the `q` key at
|
||||||
least closes the application.
|
least closes the application.
|
||||||
|
|
||||||
[`add_global_callback`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.add_global_callback
|
[`add_global_callback`]: https://docs.rs/cursive/0/cursive/struct.Cursive.html#method.add_global_callback
|
||||||
[`event::Event`]: http://gyscos.github.io/Cursive/cursive/event/enum.Event.html
|
[`event::Event`]: https://docs.rs/cursive/0/cursive/event/enum.Event.html
|
||||||
[`event::Key`]: http://gyscos.github.io/Cursive/cursive/event/enum.Key.html
|
[`event::Key`]: https://docs.rs/cursive/0/cursive/event/enum.Key.html
|
||||||
[`Cursive::quit`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.quit
|
[`Cursive::quit`]: https://docs.rs/cursive/0/cursive/struct.Cursive.html#method.quit
|
||||||
|
|
||||||
## Views
|
## Views
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ use cursive::Cursive;
|
|||||||
use cursive::views::TextView;
|
use cursive::views::TextView;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_global_callback('q', |s| s.quit());
|
siv.add_global_callback('q', |s| s.quit());
|
||||||
|
|
||||||
@ -169,9 +169,9 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`View`s]: http://gyscos.github.io/Cursive/cursive/view/trait.View.html
|
[`View`s]: https://docs.rs/cursive/0/cursive/view/trait.View.html
|
||||||
[`TextView`]: http://gyscos.github.io/Cursive/cursive/views/struct.TextView.html
|
[`TextView`]: https://docs.rs/cursive/0/cursive/views/struct.TextView.html
|
||||||
[`StackView`]: http://gyscos.github.io/Cursive/cursive/views/struct.StackView.html
|
[`StackView`]: https://docs.rs/cursive/0/cursive/views/struct.StackView.html
|
||||||
[`Cursive::add_layer`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.add_layer
|
[`Cursive::add_layer`]: https://docs.rs/cursive/0/cursive/struct.Cursive.html#method.add_layer
|
||||||
|
|
||||||
Next: [Starting with Cursive (2/3)](./tutorial_2.md)
|
Next: [Starting with Cursive (2/3)](./tutorial_2.md)
|
||||||
|
@ -12,7 +12,7 @@ use cursive::Cursive;
|
|||||||
use cursive::views::Dialog;
|
use cursive::views::Dialog;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.")
|
siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.")
|
||||||
.title("Important survey")
|
.title("Important survey")
|
||||||
@ -51,7 +51,7 @@ extern crate cursive;
|
|||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.run();
|
siv.run();
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ use cursive::views::Dialog;
|
|||||||
use cursive::views::TextView;
|
use cursive::views::TextView;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_layer(Dialog::around(TextView::new("...")));
|
siv.add_layer(Dialog::around(TextView::new("...")));
|
||||||
|
|
||||||
@ -103,11 +103,11 @@ 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
|
views provide chainable variants of their methods, to allow creating the view
|
||||||
and configuring it in one spot.
|
and configuring it in one spot.
|
||||||
|
|
||||||
[`TextView`]: http://gyscos.github.io/Cursive/cursive/views/struct.TextView
|
[`TextView`]: https://docs.rs/cursive/0/cursive/views/struct.TextView
|
||||||
[`Dialog`]: http://gyscos.github.io/Cursive/cursive/views/struct.Dialog.html
|
[`Dialog`]: https://docs.rs/cursive/0/cursive/views/struct.Dialog.html
|
||||||
[`Dialog::around`]: http://gyscos.github.io/Cursive/cursive/views/struct.Dialog.html#method.around
|
[`Dialog::around`]: https://docs.rs/cursive/0/cursive/views/struct.Dialog.html#method.around
|
||||||
[`Dialog::text`]: http://gyscos.github.io/Cursive/cursive/views/struct.Dialog.html#method.text
|
[`Dialog::text`]: https://docs.rs/cursive/0/cursive/views/struct.Dialog.html#method.text
|
||||||
[`Dialog::title`]: http://gyscos.github.io/Cursive/cursive/views/struct.Dialog.html#method.title
|
[`Dialog::title`]: https://docs.rs/cursive/0/cursive/views/struct.Dialog.html#method.title
|
||||||
|
|
||||||
## Buttons
|
## Buttons
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ use cursive::Cursive;
|
|||||||
use cursive::views::Dialog;
|
use cursive::views::Dialog;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.")
|
siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.")
|
||||||
.title("Important survey")
|
.title("Important survey")
|
||||||
@ -149,7 +149,7 @@ fn show_next(_: &mut Cursive) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Dialog::button`]: http://gyscos.github.io/Cursive/cursive/views/struct.Dialog.html#method.button
|
[`Dialog::button`]: https://docs.rs/cursive/0/cursive/views/struct.Dialog.html#method.button
|
||||||
|
|
||||||
## Layers
|
## Layers
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ fn show_answer(s: &mut Cursive, msg: &str) {
|
|||||||
Here, `show_answer()` does the same thing: remove the previous layer, and add
|
Here, `show_answer()` does the same thing: remove the previous layer, and add
|
||||||
a new `Dialog` instead.
|
a new `Dialog` instead.
|
||||||
|
|
||||||
[`Cursive::pop_layer`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.pop_layer
|
[`Cursive::pop_layer`]: https://docs.rs/cursive/0/cursive/struct.Cursive.html#method.pop_layer
|
||||||
|
|
||||||
## Conclusion
|
## Conclusion
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use cursive::views::{Button, Dialog, DummyView, EditView,
|
|||||||
use cursive::traits::*;
|
use cursive::traits::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
let select = SelectView::<String>::new()
|
let select = SelectView::<String>::new()
|
||||||
.on_submit(on_submit)
|
.on_submit(on_submit)
|
||||||
@ -138,11 +138,11 @@ not on the `BoxView` returned by `fixed_size`!)
|
|||||||
What we do there should be pretty familiar by now:
|
What we do there should be pretty familiar by now:
|
||||||
replace the layer with a simple dialog.
|
replace the layer with a simple dialog.
|
||||||
|
|
||||||
[`SelectView`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html
|
[`SelectView`]: https://docs.rs/cursive/0/cursive/views/struct.SelectView.html
|
||||||
[`BoxView`]: http://gyscos.github.io/Cursive/cursive/views/struct.BoxView.html
|
[`BoxView`]: https://docs.rs/cursive/0/cursive/views/struct.BoxView.html
|
||||||
[`Boxable`]: http://gyscos.github.io/Cursive/cursive/view/trait.Boxable.html
|
[`Boxable`]: https://docs.rs/cursive/0/cursive/view/trait.Boxable.html
|
||||||
[`traits`]: http://gyscos.github.io/Cursive/cursive/traits/index.html
|
[`traits`]: https://docs.rs/cursive/0/cursive/traits/index.html
|
||||||
[`SelectView::on_submit`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html#method.on_submit
|
[`SelectView::on_submit`]: https://docs.rs/cursive/0/cursive/views/struct.SelectView.html#method.on_submit
|
||||||
|
|
||||||
## Linear layouts
|
## Linear layouts
|
||||||
|
|
||||||
@ -188,10 +188,10 @@ We've added a `DummyView` again to add some space between the list and the
|
|||||||
buttons. Though with an empty list, it doesn't look like much yet. Let's fill
|
buttons. Though with an empty list, it doesn't look like much yet. Let's fill
|
||||||
this list with names!
|
this list with names!
|
||||||
|
|
||||||
[`Button`]: http://gyscos.github.io/Cursive/cursive/views/struct.Button.html
|
[`Button`]: https://docs.rs/cursive/0/cursive/views/struct.Button.html
|
||||||
[`Dialog::around`]: http://gyscos.github.io/Cursive/cursive/views/struct.Dialog.html#method.new
|
[`Dialog::around`]: https://docs.rs/cursive/0/cursive/views/struct.Dialog.html#method.new
|
||||||
[`LinearLayout`]: http://gyscos.github.io/Cursive/cursive/views/struct.LinearLayout.html
|
[`LinearLayout`]: https://docs.rs/cursive/0/cursive/views/struct.LinearLayout.html
|
||||||
[`DummyView`]: http://gyscos.github.io/Cursive/cursive/views/struct.DummyView.html
|
[`DummyView`]: https://docs.rs/cursive/0/cursive/views/struct.DummyView.html
|
||||||
|
|
||||||
## IDs
|
## IDs
|
||||||
|
|
||||||
@ -311,14 +311,14 @@ this method returns a handle, through which we can mutate the view.
|
|||||||
It uses `Rc` and `RefCell` under the hood to provide mutable access to the
|
It uses `Rc` and `RefCell` under the hood to provide mutable access to the
|
||||||
view without borrowing the `Cursive` root, leaving us free to pop layers.
|
view without borrowing the `Cursive` root, leaving us free to pop layers.
|
||||||
|
|
||||||
[`EditView`]: http://gyscos.github.io/Cursive/cursive/views/struct.EditView.html
|
[`EditView`]: https://docs.rs/cursive/0/cursive/views/struct.EditView.html
|
||||||
[`IdView`]: http://gyscos.github.io/Cursive/cursive/views/struct.IdView.html
|
[`IdView`]: https://docs.rs/cursive/0/cursive/views/struct.IdView.html
|
||||||
[`IdView::new`]: http://gyscos.github.io/Cursive/cursive/prelude/struct.IdView.html#method.around
|
[`IdView::new`]: https://docs.rs/cursive/0/cursive/prelude/struct.IdView.html#method.around
|
||||||
[`Identifiable`]: http://gyscos.github.io/Cursive/cursive/view/trait.Identifiable.html
|
[`Identifiable`]: https://docs.rs/cursive/0/cursive/view/trait.Identifiable.html
|
||||||
[`Cursive::find_id`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.find_id
|
[`Cursive::find_id`]: https://docs.rs/cursive/0/cursive/struct.Cursive.html#method.find_id
|
||||||
[`Cursive::call_on_id`]: http://gyscos.github.io/Cursive/cursive/struct.Cursive.html#method.call_on_id
|
[`Cursive::call_on_id`]: https://docs.rs/cursive/0/cursive/struct.Cursive.html#method.call_on_id
|
||||||
[`SelectView::selected_id`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html#method.selected_id
|
[`SelectView::selected_id`]: https://docs.rs/cursive/0/cursive/views/struct.SelectView.html#method.selected_id
|
||||||
[`SelectView::remove_item`]: http://gyscos.github.io/Cursive/cursive/views/struct.SelectView.html#method.remove_item
|
[`SelectView::remove_item`]: https://docs.rs/cursive/0/cursive/views/struct.SelectView.html#method.remove_item
|
||||||
|
|
||||||
## Conclusion
|
## Conclusion
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use cursive::views::Canvas;
|
|||||||
// 256 colors.
|
// 256 colors.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
Canvas::new(())
|
Canvas::new(())
|
||||||
|
@ -5,7 +5,7 @@ use cursive::views::{Dialog, TextView};
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Creates the cursive root - required for every application.
|
// Creates the cursive root - required for every application.
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// Creates a dialog with a single "Quit" button
|
// Creates a dialog with a single "Quit" button
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
|
@ -5,7 +5,7 @@ use cursive::traits::*;
|
|||||||
use cursive::views::{Dialog, EditView, TextView};
|
use cursive::views::{Dialog, EditView, TextView};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// Create a dialog with an edit text and a button.
|
// Create a dialog with an edit text and a button.
|
||||||
// The user can either hit the <Ok> button,
|
// The user can either hit the <Ok> button,
|
||||||
|
@ -4,7 +4,7 @@ use cursive::Cursive;
|
|||||||
use cursive::views::TextView;
|
use cursive::views::TextView;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// We can quit by pressing `q`
|
// We can quit by pressing `q`
|
||||||
siv.add_global_callback('q', Cursive::quit);
|
siv.add_global_callback('q', Cursive::quit);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
extern crate cursive;
|
extern crate cursive;
|
||||||
|
|
||||||
use cursive::{Cursive, Printer};
|
|
||||||
use cursive::event::{Event, EventResult};
|
use cursive::event::{Event, EventResult};
|
||||||
use cursive::traits::*;
|
use cursive::traits::*;
|
||||||
|
use cursive::{Cursive, Printer};
|
||||||
|
|
||||||
// This example define a custom view that prints any event it receives.
|
// This example define a custom view that prints any event it receives.
|
||||||
// This is a handy way to check the input received by cursive.
|
// This is a handy way to check the input received by cursive.
|
||||||
|
@ -8,7 +8,7 @@ use cursive::views::{Dialog, DummyView, LinearLayout, TextView};
|
|||||||
// This example uses a LinearLayout to stick multiple views next to each other.
|
// This example uses a LinearLayout to stick multiple views next to each other.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// Some description text
|
// Some description text
|
||||||
let text = "This is a very simple example of linear layout. Two views \
|
let text = "This is a very simple example of linear layout. Two views \
|
||||||
|
@ -10,7 +10,7 @@ use cursive::views::{Checkbox, Dialog, EditView, LinearLayout, ListView,
|
|||||||
// ListView can be used to build forms, with a list of inputs.
|
// ListView can be used to build forms, with a list of inputs.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
Dialog::new()
|
Dialog::new()
|
||||||
|
@ -14,7 +14,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// As usual, create the Cursive root
|
// As usual, create the Cursive root
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// We want to refresh the page even when no input is given.
|
// We want to refresh the page even when no input is given.
|
||||||
siv.set_fps(10);
|
siv.set_fps(10);
|
||||||
|
@ -9,7 +9,7 @@ fn main() {
|
|||||||
// Read some long text from a file.
|
// Read some long text from a file.
|
||||||
let content = include_str!("../assets/lorem.txt");
|
let content = include_str!("../assets/lorem.txt");
|
||||||
|
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// We can quit by pressing q
|
// We can quit by pressing q
|
||||||
siv.add_global_callback('q', |s| s.quit());
|
siv.add_global_callback('q', |s| s.quit());
|
||||||
|
@ -9,7 +9,7 @@ use cursive::utils::markup::StyledString;
|
|||||||
use cursive::views::{Dialog, TextView};
|
use cursive::views::{Dialog, TextView};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
let mut styled = StyledString::plain("Isn't ");
|
let mut styled = StyledString::plain("Isn't ");
|
||||||
styled.append(StyledString::styled(
|
styled.append(StyledString::styled(
|
||||||
|
@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||||||
// application.
|
// application.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// We'll use a counter to name new files.
|
// We'll use a counter to name new files.
|
||||||
let counter = AtomicUsize::new(1);
|
let counter = AtomicUsize::new(1);
|
||||||
|
@ -12,7 +12,7 @@ use cursive::vec::Vec2;
|
|||||||
use cursive::views::{Button, Dialog, LinearLayout, Panel, SelectView};
|
use cursive::views::{Button, Dialog, LinearLayout, Panel, SelectView};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
Dialog::new()
|
Dialog::new()
|
||||||
|
@ -8,7 +8,7 @@ use cursive::views::{Dialog, OnEventView, TextView};
|
|||||||
// This example modifies a view after creation.
|
// This example modifies a view after creation.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
let content = "Press Q to quit the application.\n\nPress P to open the \
|
let content = "Press Q to quit the application.\n\nPress P to open the \
|
||||||
popup.";
|
popup.";
|
||||||
|
@ -22,7 +22,7 @@ fn move_top(c: &mut Cursive, x_in: isize, y_in: isize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
siv.set_fps(60);
|
siv.set_fps(60);
|
||||||
|
|
||||||
// We can quit by pressing `q`
|
// We can quit by pressing `q`
|
||||||
|
@ -4,7 +4,7 @@ extern crate rand;
|
|||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
use cursive::traits::*;
|
use cursive::traits::*;
|
||||||
use cursive::views::{Button, Dialog, LinearLayout, ProgressBar, TextView};
|
use cursive::views::{Button, Dialog, LinearLayout, ProgressBar, TextView};
|
||||||
use cursive::views::Counter;
|
use cursive::utils::Counter;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
@ -17,7 +17,7 @@ use std::time::Duration;
|
|||||||
// "ticked" to indicate progress.
|
// "ticked" to indicate progress.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// We'll start slowly with a simple start button...
|
// We'll start slowly with a simple start button...
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
|
@ -6,7 +6,7 @@ use cursive::views::{Dialog, DummyView, LinearLayout, RadioGroup};
|
|||||||
// This example uses radio buttons.
|
// This example uses radio buttons.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// We need to pre-create the groups for our RadioButtons.
|
// We need to pre-create the groups for our RadioButtons.
|
||||||
let mut color_group: RadioGroup<String> = RadioGroup::new();
|
let mut color_group: RadioGroup<String> = RadioGroup::new();
|
||||||
|
@ -7,7 +7,7 @@ use cursive::views::{Dialog, EditView, LinearLayout, TextView};
|
|||||||
// This example shows a way to access multiple views at the same time.
|
// This example shows a way to access multiple views at the same time.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// Create a dialog with 2 edit fields, and a text view.
|
// Create a dialog with 2 edit fields, and a text view.
|
||||||
// The text view indicates when the 2 fields content match.
|
// The text view indicates when the 2 fields content match.
|
||||||
|
@ -33,7 +33,7 @@ fn main() {
|
|||||||
Some(EventResult::Consumed(None))
|
Some(EventResult::Consumed(None))
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// Let's add a BoxView to keep the list at a reasonable size
|
// Let's add a BoxView to keep the list at a reasonable size
|
||||||
// (it can scroll anyway).
|
// (it can scroll anyway).
|
||||||
|
@ -5,7 +5,7 @@ use cursive::traits::*;
|
|||||||
use cursive::views::{Dialog, SliderView};
|
use cursive::views::{Dialog, SliderView};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
siv.add_global_callback('q', |s| s.quit());
|
siv.add_global_callback('q', |s| s.quit());
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use cursive::views::TextView;
|
|||||||
// This way, it looks more natural.
|
// This way, it looks more natural.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
let theme = custom_theme_from_cursive(&siv);
|
let theme = custom_theme_from_cursive(&siv);
|
||||||
siv.set_theme(theme);
|
siv.set_theme(theme);
|
||||||
|
@ -6,7 +6,7 @@ use cursive::traits::*;
|
|||||||
use cursive::views::{Dialog, EditView, OnEventView, TextArea};
|
use cursive::views::{Dialog, EditView, OnEventView, TextArea};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
// The main dialog will just have a textarea.
|
// The main dialog will just have a textarea.
|
||||||
// Its size expand automatically with the content.
|
// Its size expand automatically with the content.
|
||||||
|
@ -4,7 +4,7 @@ use cursive::Cursive;
|
|||||||
use cursive::views::{Dialog, TextView};
|
use cursive::views::{Dialog, TextView};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
// You can load a theme from a file at runtime for fast development.
|
// You can load a theme from a file at runtime for fast development.
|
||||||
siv.load_theme_file("assets/style.toml")
|
siv.load_theme_file("assets/style.toml")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -5,7 +5,7 @@ use cursive::theme::{BaseColor, BorderStyle, Color, ColorStyle};
|
|||||||
use cursive::views::{Dialog, EditView, LinearLayout, TextView};
|
use cursive::views::{Dialog, EditView, LinearLayout, TextView};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
let layout = LinearLayout::vertical()
|
let layout = LinearLayout::vertical()
|
||||||
.child(TextView::new(
|
.child(TextView::new(
|
||||||
|
139
examples/vpv.rs
Normal file
139
examples/vpv.rs
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
extern crate cursive;
|
||||||
|
extern crate pretty_bytes;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use cursive::Cursive;
|
||||||
|
use cursive::traits::{Boxable, With};
|
||||||
|
use cursive::utils;
|
||||||
|
use cursive::views::{Canvas, Dialog, LinearLayout, ProgressBar};
|
||||||
|
use pretty_bytes::converter::convert;
|
||||||
|
use std::thread;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
|
// This example is a visual version of the `pv` tool.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut siv = Cursive::default();
|
||||||
|
|
||||||
|
// We'll use this channel to signal the end of the transfer
|
||||||
|
let cb_sink = siv.cb_sink().clone();
|
||||||
|
|
||||||
|
// Use a counter to track progress
|
||||||
|
let counter = utils::Counter::new(0);
|
||||||
|
let counter_copy = counter.clone();
|
||||||
|
let start = time::Instant::now();
|
||||||
|
|
||||||
|
// If an argument is given, it is the file we'll read from.
|
||||||
|
// Else, read from stdin.
|
||||||
|
let (source, len) = match std::env::args().nth(1) {
|
||||||
|
Some(source) => {
|
||||||
|
let meta = std::fs::metadata(&source).unwrap();
|
||||||
|
// If possible, read the file size to have a progress bar.
|
||||||
|
let len = meta.len();
|
||||||
|
(
|
||||||
|
Some(source),
|
||||||
|
if len > 0 { Some(len) } else { None },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => (None, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start the copy in a separate thread
|
||||||
|
thread::spawn(move || {
|
||||||
|
// Copy to stdout - lock it for better performance.
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let mut stdout = stdout.lock();
|
||||||
|
|
||||||
|
match source {
|
||||||
|
None => {
|
||||||
|
// Copy from stdin - lock it for better performance.
|
||||||
|
let stdin = io::stdin();
|
||||||
|
let stdin = stdin.lock();
|
||||||
|
let mut reader =
|
||||||
|
utils::ProgressReader::new(counter_copy, stdin);
|
||||||
|
|
||||||
|
// And copy!
|
||||||
|
io::copy(&mut reader, &mut stdout).unwrap();
|
||||||
|
}
|
||||||
|
Some(source) => {
|
||||||
|
// Copy from stdin - lock it for better performance.
|
||||||
|
let input = std::fs::File::open(source).unwrap();
|
||||||
|
let mut reader =
|
||||||
|
utils::ProgressReader::new(counter_copy, input);
|
||||||
|
|
||||||
|
// And copy!
|
||||||
|
io::copy(&mut reader, &mut stdout).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we're done, shut down the application
|
||||||
|
cb_sink
|
||||||
|
.send(Box::new(|s: &mut Cursive| s.quit()))
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a single view: progress status
|
||||||
|
siv.add_layer(
|
||||||
|
Dialog::new().title("Copying...").content(
|
||||||
|
LinearLayout::vertical()
|
||||||
|
.child(
|
||||||
|
Canvas::new(counter.clone())
|
||||||
|
.with_draw(move |c, printer| {
|
||||||
|
let ticks = c.get() as f64;
|
||||||
|
let now = time::Instant::now();
|
||||||
|
let duration = now - start;
|
||||||
|
|
||||||
|
let seconds = duration.as_secs() as f64
|
||||||
|
+ duration.subsec_nanos() as f64 * 1e-9;
|
||||||
|
|
||||||
|
let speed = ticks / seconds;
|
||||||
|
|
||||||
|
// Print ETA if we have a file size
|
||||||
|
// Otherwise prints elapsed time.
|
||||||
|
if let Some(len) = len {
|
||||||
|
let remaining = (len as f64 - ticks) / speed;
|
||||||
|
printer.print(
|
||||||
|
(0, 0),
|
||||||
|
&format!(
|
||||||
|
"ETA: {:.1} seconds",
|
||||||
|
remaining
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
printer.print(
|
||||||
|
(0, 0),
|
||||||
|
&format!(
|
||||||
|
"Elapsed: {:.1} seconds",
|
||||||
|
seconds
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
printer.print(
|
||||||
|
(0, 1),
|
||||||
|
&format!("Copied: {}", convert(ticks)),
|
||||||
|
);
|
||||||
|
printer.print(
|
||||||
|
(0, 2),
|
||||||
|
&format!("Speed: {}/s", convert(speed)),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.fixed_size((25, 3)),
|
||||||
|
)
|
||||||
|
.with(|l| {
|
||||||
|
// If we have a file length, add a progress bar
|
||||||
|
if let Some(len) = len {
|
||||||
|
l.add_child(
|
||||||
|
ProgressBar::new()
|
||||||
|
.max(len as usize)
|
||||||
|
.with_value(counter.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
siv.set_fps(10);
|
||||||
|
|
||||||
|
siv.run();
|
||||||
|
}
|
@ -1,3 +1,8 @@
|
|||||||
|
//! Backend using BearLibTerminal
|
||||||
|
//!
|
||||||
|
//! Requires the `blt-backend` feature.
|
||||||
|
#![cfg(feature = "bear-lib-terminal")]
|
||||||
|
|
||||||
extern crate bear_lib_terminal;
|
extern crate bear_lib_terminal;
|
||||||
|
|
||||||
use self::bear_lib_terminal::Color as BltColor;
|
use self::bear_lib_terminal::Color as BltColor;
|
||||||
@ -15,12 +20,34 @@ enum ColorRole {
|
|||||||
Background,
|
Background,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Concrete {
|
pub struct Backend {
|
||||||
mouse_position: Vec2,
|
mouse_position: Vec2,
|
||||||
buttons_pressed: HashSet<MouseButton>,
|
buttons_pressed: HashSet<MouseButton>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Concrete {
|
impl Backend {
|
||||||
|
pub fn init() -> Box<Self> {
|
||||||
|
terminal::open("Cursive", 80, 24);
|
||||||
|
terminal::set(terminal::config::Window::empty().resizeable(true));
|
||||||
|
terminal::set(vec![
|
||||||
|
terminal::config::InputFilter::Group {
|
||||||
|
group: terminal::config::InputFilterGroup::Keyboard,
|
||||||
|
both: false,
|
||||||
|
},
|
||||||
|
terminal::config::InputFilter::Group {
|
||||||
|
group: terminal::config::InputFilterGroup::Mouse,
|
||||||
|
both: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
let c = Backend {
|
||||||
|
mouse_position: Vec2::zero(),
|
||||||
|
buttons_pressed: HashSet::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Box::new(c)
|
||||||
|
}
|
||||||
|
|
||||||
fn blt_keycode_to_ev(
|
fn blt_keycode_to_ev(
|
||||||
&mut self, kc: KeyCode, shift: bool, ctrl: bool
|
&mut self, kc: KeyCode, shift: bool, ctrl: bool
|
||||||
) -> Event {
|
) -> Event {
|
||||||
@ -144,52 +171,52 @@ impl Concrete {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl backend::Backend for Concrete {
|
impl backend::Backend for Backend {
|
||||||
fn init() -> Self {
|
|
||||||
terminal::open("Cursive", 80, 24);
|
|
||||||
terminal::set(terminal::config::Window::empty().resizeable(true));
|
|
||||||
terminal::set(vec![
|
|
||||||
terminal::config::InputFilter::Group {
|
|
||||||
group: terminal::config::InputFilterGroup::Keyboard,
|
|
||||||
both: false,
|
|
||||||
},
|
|
||||||
terminal::config::InputFilter::Group {
|
|
||||||
group: terminal::config::InputFilterGroup::Mouse,
|
|
||||||
both: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
Concrete {
|
|
||||||
mouse_position: Vec2::zero(),
|
|
||||||
buttons_pressed: HashSet::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finish(&mut self) {
|
fn finish(&mut self) {
|
||||||
terminal::close();
|
terminal::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_color<F: FnOnce()>(&self, color: ColorPair, f: F) {
|
fn set_color(&self, color: ColorPair) -> ColorPair {
|
||||||
|
let current = ColorPair {
|
||||||
|
front: blt_colour_to_colour(state::foreground()),
|
||||||
|
back: blt_colour_to_colour(state::background())
|
||||||
|
};
|
||||||
|
|
||||||
let fg = colour_to_blt_colour(color.front, ColorRole::Foreground);
|
let fg = colour_to_blt_colour(color.front, ColorRole::Foreground);
|
||||||
let bg = colour_to_blt_colour(color.back, ColorRole::Background);
|
let bg = colour_to_blt_colour(color.back, ColorRole::Background);
|
||||||
terminal::with_colors(fg, bg, f);
|
|
||||||
|
terminal::set_colors(fg, bg);
|
||||||
|
|
||||||
|
current
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
|
fn set_effect(&self, effect: Effect) {
|
||||||
match effect {
|
match effect {
|
||||||
// TODO: does BLT support bold/italic/underline?
|
// TODO: does BLT support bold/italic/underline?
|
||||||
Effect::Bold
|
Effect::Bold
|
||||||
| Effect::Italic
|
| Effect::Italic
|
||||||
| Effect::Underline
|
| Effect::Underline
|
||||||
| Effect::Simple => f(),
|
| Effect::Simple => {},
|
||||||
// TODO: how to do this correctly?`
|
// TODO: how to do this correctly?`
|
||||||
// BLT itself doesn't do this kind of thing,
|
// BLT itself doesn't do this kind of thing,
|
||||||
// we'd need the colours in our position,
|
// we'd need the colours in our position,
|
||||||
// but `f()` can do whatever
|
// but `f()` can do whatever
|
||||||
Effect::Reverse => terminal::with_colors(
|
Effect::Reverse => terminal::set_colors(
|
||||||
BltColor::from_rgb(0, 0, 0),
|
state::background(), state::foreground()
|
||||||
BltColor::from_rgb(255, 255, 255),
|
),
|
||||||
f,
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unset_effect(&self, effect: Effect) {
|
||||||
|
match effect {
|
||||||
|
// TODO: does BLT support bold/italic/underline?
|
||||||
|
Effect::Bold
|
||||||
|
| Effect::Italic
|
||||||
|
| Effect::Underline
|
||||||
|
| Effect::Simple => {},
|
||||||
|
// The process of reversing is the same as unreversing
|
||||||
|
Effect::Reverse => terminal::set_colors(
|
||||||
|
state::background(), state::foreground()
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,9 +225,9 @@ impl backend::Backend for Concrete {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen_size(&self) -> (usize, usize) {
|
fn screen_size(&self) -> Vec2 {
|
||||||
let Size { width, height } = terminal::state::size();
|
let Size { width, height } = terminal::state::size();
|
||||||
(width as usize, height as usize)
|
(width, height).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&self, color: Color) {
|
fn clear(&self, color: Color) {
|
||||||
@ -215,8 +242,8 @@ impl backend::Backend for Concrete {
|
|||||||
terminal::refresh();
|
terminal::refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_at(&self, (x, y): (usize, usize), text: &str) {
|
fn print_at(&self, pos: Vec2, text: &str) {
|
||||||
terminal::print_xy(x as i32, y as i32, text);
|
terminal::print_xy(pos.x as i32, pos.y as i32, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_refresh_rate(&mut self, _: u32) {
|
fn set_refresh_rate(&mut self, _: u32) {
|
||||||
@ -284,6 +311,10 @@ impl backend::Backend for Concrete {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blt_colour_to_colour(c: BltColor) -> Color {
|
||||||
|
Color::Rgb(c.red, c.green, c.blue)
|
||||||
|
}
|
||||||
|
|
||||||
fn colour_to_blt_colour(clr: Color, role: ColorRole) -> BltColor {
|
fn colour_to_blt_colour(clr: Color, role: ColorRole) -> BltColor {
|
||||||
let (r, g, b) = match clr {
|
let (r, g, b) = match clr {
|
||||||
Color::TerminalDefault => {
|
Color::TerminalDefault => {
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
|
//! Common module for the ncurses and pancurses backends.
|
||||||
|
//!
|
||||||
|
//! Requires either of `ncurses-backend` or `pancurses-backend`.
|
||||||
|
#![cfg(any(feature = "ncurses", feature = "pancurses"))]
|
||||||
|
|
||||||
use event::{Event, Key};
|
use event::{Event, Key};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use theme::{BaseColor, Color, ColorPair};
|
use theme::{BaseColor, Color, ColorPair};
|
||||||
|
|
||||||
#[cfg(feature = "ncurses")]
|
#[cfg(feature = "ncurses")]
|
||||||
mod n;
|
pub mod n;
|
||||||
#[cfg(feature = "ncurses")]
|
|
||||||
pub use self::n::*;
|
|
||||||
|
|
||||||
#[cfg(feature = "pancurses")]
|
#[cfg(feature = "pancurses")]
|
||||||
mod pan;
|
pub mod pan;
|
||||||
#[cfg(feature = "pancurses")]
|
|
||||||
pub use self::pan::*;
|
|
||||||
|
|
||||||
fn split_i32(code: i32) -> Vec<u8> {
|
fn split_i32(code: i32) -> Vec<u8> {
|
||||||
(0..4).map(|i| ((code >> (8 * i)) & 0xFF) as u8).collect()
|
(0..4).map(|i| ((code >> (8 * i)) & 0xFF) as u8).collect()
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
extern crate ncurses;
|
extern crate ncurses;
|
||||||
|
|
||||||
use self::ncurses::mmask_t;
|
|
||||||
use self::super::split_i32;
|
use self::super::split_i32;
|
||||||
|
use self::ncurses::mmask_t;
|
||||||
use backend;
|
use backend;
|
||||||
use event::{Event, Key, MouseButton, MouseEvent};
|
use event::{Event, Key, MouseButton, MouseEvent};
|
||||||
|
use libc;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::{stdout, Write};
|
use std::ffi::CString;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
use theme::{Color, ColorPair, Effect};
|
use theme::{Color, ColorPair, Effect};
|
||||||
use utf8;
|
use utf8;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
|
||||||
pub struct Concrete {
|
pub struct Backend {
|
||||||
current_style: Cell<ColorPair>,
|
current_style: Cell<ColorPair>,
|
||||||
|
|
||||||
// Maps (front, back) ncurses colors to ncurses pairs
|
// Maps (front, back) ncurses colors to ncurses pairs
|
||||||
@ -27,10 +31,73 @@ fn find_closest_pair(pair: &ColorPair) -> (i16, i16) {
|
|||||||
super::find_closest_pair(pair, ncurses::COLORS() as i16)
|
super::find_closest_pair(pair, ncurses::COLORS() as i16)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Concrete {
|
/// Writes some bytes directly to `/dev/tty`
|
||||||
|
///
|
||||||
|
/// Since this is not going to be used often, we can afford to re-open the
|
||||||
|
/// file every time.
|
||||||
|
fn write_to_tty(bytes: &[u8]) -> io::Result<()> {
|
||||||
|
let mut tty_output =
|
||||||
|
File::create("/dev/tty").expect("cursive can only run with a tty");
|
||||||
|
tty_output.write_all(bytes)?;
|
||||||
|
// tty_output will be flushed automatically at the end of the function.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backend {
|
||||||
|
pub fn init() -> Box<backend::Backend> {
|
||||||
|
// Change the locale.
|
||||||
|
// For some reasons it's mandatory to get some UTF-8 support.
|
||||||
|
ncurses::setlocale(ncurses::LcCategory::all, "");
|
||||||
|
|
||||||
|
// The delay is the time ncurses wait after pressing ESC
|
||||||
|
// to see if it's an escape sequence.
|
||||||
|
// Default delay is way too long. 25 is imperceptible yet works fine.
|
||||||
|
::std::env::set_var("ESCDELAY", "25");
|
||||||
|
|
||||||
|
let tty_path = CString::new("/dev/tty").unwrap();
|
||||||
|
let mode = CString::new("r+").unwrap();
|
||||||
|
let tty = unsafe { libc::fopen(tty_path.as_ptr(), mode.as_ptr()) };
|
||||||
|
ncurses::newterm(None, tty, tty);
|
||||||
|
ncurses::keypad(ncurses::stdscr(), true);
|
||||||
|
|
||||||
|
// This disables mouse click detection,
|
||||||
|
// and provides 0-delay access to mouse presses.
|
||||||
|
ncurses::mouseinterval(0);
|
||||||
|
// Listen to all mouse events.
|
||||||
|
ncurses::mousemask(
|
||||||
|
(ncurses::ALL_MOUSE_EVENTS | ncurses::REPORT_MOUSE_POSITION)
|
||||||
|
as mmask_t,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
ncurses::noecho();
|
||||||
|
ncurses::cbreak();
|
||||||
|
ncurses::start_color();
|
||||||
|
// Pick up background and text color from the terminal theme.
|
||||||
|
ncurses::use_default_colors();
|
||||||
|
// No cursor
|
||||||
|
ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
|
||||||
|
|
||||||
|
// This asks the terminal to provide us with mouse drag events
|
||||||
|
// (Mouse move when a button is pressed).
|
||||||
|
// Replacing 1002 with 1003 would give us ANY mouse move.
|
||||||
|
write_to_tty(b"\x1B[?1002h").unwrap();
|
||||||
|
|
||||||
|
let c = Backend {
|
||||||
|
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
|
||||||
|
pairs: RefCell::new(HashMap::new()),
|
||||||
|
|
||||||
|
last_mouse_button: None,
|
||||||
|
event_queue: Vec::new(),
|
||||||
|
|
||||||
|
key_codes: initialize_keymap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Box::new(c)
|
||||||
|
}
|
||||||
|
|
||||||
/// Save a new color pair.
|
/// Save a new color pair.
|
||||||
fn insert_color(
|
fn insert_color(
|
||||||
&self, pairs: &mut HashMap<(i16, i16), i16>, (front, back): (i16, i16)
|
&self, pairs: &mut HashMap<(i16, i16), i16>, (front, back): (i16, i16),
|
||||||
) -> i16 {
|
) -> i16 {
|
||||||
let n = 1 + pairs.len() as i16;
|
let n = 1 + pairs.len() as i16;
|
||||||
|
|
||||||
@ -96,7 +163,7 @@ impl Concrete {
|
|||||||
let make_event = |event| Event::Mouse {
|
let make_event = |event| Event::Mouse {
|
||||||
offset: Vec2::zero(),
|
offset: Vec2::zero(),
|
||||||
position: Vec2::new(mevent.x as usize, mevent.y as usize),
|
position: Vec2::new(mevent.x as usize, mevent.y as usize),
|
||||||
event: event,
|
event,
|
||||||
};
|
};
|
||||||
|
|
||||||
if mevent.bstate == ncurses::REPORT_MOUSE_POSITION as mmask_t {
|
if mevent.bstate == ncurses::REPORT_MOUSE_POSITION as mmask_t {
|
||||||
@ -153,59 +220,12 @@ impl Concrete {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl backend::Backend for Concrete {
|
impl backend::Backend for Backend {
|
||||||
fn init() -> Self {
|
fn screen_size(&self) -> Vec2 {
|
||||||
// Change the locale.
|
|
||||||
// For some reasons it's mandatory to get some UTF-8 support.
|
|
||||||
ncurses::setlocale(ncurses::LcCategory::all, "");
|
|
||||||
|
|
||||||
// The delay is the time ncurses wait after pressing ESC
|
|
||||||
// to see if it's an escape sequence.
|
|
||||||
// Default delay is way too long. 25 is imperceptible yet works fine.
|
|
||||||
::std::env::set_var("ESCDELAY", "25");
|
|
||||||
|
|
||||||
ncurses::initscr();
|
|
||||||
ncurses::keypad(ncurses::stdscr(), true);
|
|
||||||
|
|
||||||
// This disables mouse click detection,
|
|
||||||
// and provides 0-delay access to mouse presses.
|
|
||||||
ncurses::mouseinterval(0);
|
|
||||||
// Listen to all mouse events.
|
|
||||||
ncurses::mousemask(
|
|
||||||
(ncurses::ALL_MOUSE_EVENTS | ncurses::REPORT_MOUSE_POSITION)
|
|
||||||
as mmask_t,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
ncurses::noecho();
|
|
||||||
ncurses::cbreak();
|
|
||||||
ncurses::start_color();
|
|
||||||
// Pick up background and text color from the terminal theme.
|
|
||||||
ncurses::use_default_colors();
|
|
||||||
// No cursor
|
|
||||||
ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
|
|
||||||
|
|
||||||
// This asks the terminal to provide us with mouse drag events
|
|
||||||
// (Mouse move when a button is pressed).
|
|
||||||
// Replacing 1002 with 1003 would give us ANY mouse move.
|
|
||||||
print!("\x1B[?1002h");
|
|
||||||
stdout().flush().expect("could not flush stdout");
|
|
||||||
|
|
||||||
Concrete {
|
|
||||||
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
|
|
||||||
pairs: RefCell::new(HashMap::new()),
|
|
||||||
|
|
||||||
last_mouse_button: None,
|
|
||||||
event_queue: Vec::new(),
|
|
||||||
|
|
||||||
key_codes: initialize_keymap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_size(&self) -> (usize, usize) {
|
|
||||||
let mut x: i32 = 0;
|
let mut x: i32 = 0;
|
||||||
let mut y: i32 = 0;
|
let mut y: i32 = 0;
|
||||||
ncurses::getmaxyx(ncurses::stdscr(), &mut y, &mut x);
|
ncurses::getmaxyx(ncurses::stdscr(), &mut y, &mut x);
|
||||||
(x as usize, y as usize)
|
(x, y).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_colors(&self) -> bool {
|
fn has_colors(&self) -> bool {
|
||||||
@ -213,26 +233,21 @@ impl backend::Backend for Concrete {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&mut self) {
|
fn finish(&mut self) {
|
||||||
print!("\x1B[?1002l");
|
write_to_tty(b"\x1B[?1002l").unwrap();
|
||||||
stdout().flush().expect("could not flush stdout");
|
|
||||||
ncurses::endwin();
|
ncurses::endwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_color<F: FnOnce()>(&self, colors: ColorPair, f: F) {
|
fn set_color(&self, colors: ColorPair) -> ColorPair {
|
||||||
// eprintln!("Color used: {:?}", colors);
|
// eprintln!("Color used: {:?}", colors);
|
||||||
let current = self.current_style.get();
|
let current = self.current_style.get();
|
||||||
if current != colors {
|
if current != colors {
|
||||||
self.set_colors(colors);
|
self.set_colors(colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
f();
|
current
|
||||||
|
|
||||||
if current != colors {
|
|
||||||
self.set_colors(current);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
|
fn set_effect(&self, effect: Effect) {
|
||||||
let style = match effect {
|
let style = match effect {
|
||||||
Effect::Reverse => ncurses::A_REVERSE(),
|
Effect::Reverse => ncurses::A_REVERSE(),
|
||||||
Effect::Simple => ncurses::A_NORMAL(),
|
Effect::Simple => ncurses::A_NORMAL(),
|
||||||
@ -241,7 +256,16 @@ impl backend::Backend for Concrete {
|
|||||||
Effect::Underline => ncurses::A_UNDERLINE(),
|
Effect::Underline => ncurses::A_UNDERLINE(),
|
||||||
};
|
};
|
||||||
ncurses::attron(style);
|
ncurses::attron(style);
|
||||||
f();
|
}
|
||||||
|
|
||||||
|
fn unset_effect(&self, effect: Effect) {
|
||||||
|
let style = match effect {
|
||||||
|
Effect::Reverse => ncurses::A_REVERSE(),
|
||||||
|
Effect::Simple => ncurses::A_NORMAL(),
|
||||||
|
Effect::Bold => ncurses::A_BOLD(),
|
||||||
|
Effect::Italic => ncurses::A_ITALIC(),
|
||||||
|
Effect::Underline => ncurses::A_UNDERLINE(),
|
||||||
|
};
|
||||||
ncurses::attroff(style);
|
ncurses::attroff(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,8 +283,8 @@ impl backend::Backend for Concrete {
|
|||||||
ncurses::refresh();
|
ncurses::refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_at(&self, (x, y): (usize, usize), text: &str) {
|
fn print_at(&self, pos: Vec2, text: &str) {
|
||||||
ncurses::mvaddstr(y as i32, x as i32, text);
|
ncurses::mvaddstr(pos.y as i32, pos.x as i32, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_event(&mut self) -> Event {
|
fn poll_event(&mut self) -> Event {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
extern crate pancurses;
|
extern crate pancurses;
|
||||||
|
|
||||||
use self::pancurses::mmask_t;
|
|
||||||
use self::super::split_i32;
|
use self::super::split_i32;
|
||||||
|
use self::pancurses::mmask_t;
|
||||||
use backend;
|
use backend;
|
||||||
use event::{Event, Key, MouseButton, MouseEvent};
|
use event::{Event, Key, MouseButton, MouseEvent};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
@ -10,7 +10,7 @@ use std::io::{stdout, Write};
|
|||||||
use theme::{Color, ColorPair, Effect};
|
use theme::{Color, ColorPair, Effect};
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
|
||||||
pub struct Concrete {
|
pub struct Backend {
|
||||||
// Used
|
// Used
|
||||||
current_style: Cell<ColorPair>,
|
current_style: Cell<ColorPair>,
|
||||||
pairs: RefCell<HashMap<(i16, i16), i32>>,
|
pairs: RefCell<HashMap<(i16, i16), i32>>,
|
||||||
@ -28,10 +28,46 @@ fn find_closest_pair(pair: &ColorPair) -> (i16, i16) {
|
|||||||
super::find_closest_pair(pair, pancurses::COLORS() as i16)
|
super::find_closest_pair(pair, pancurses::COLORS() as i16)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Concrete {
|
impl Backend {
|
||||||
|
pub fn init() -> Box<Self> {
|
||||||
|
::std::env::set_var("ESCDELAY", "25");
|
||||||
|
|
||||||
|
let window = pancurses::initscr();
|
||||||
|
window.keypad(true);
|
||||||
|
pancurses::noecho();
|
||||||
|
pancurses::cbreak();
|
||||||
|
pancurses::start_color();
|
||||||
|
pancurses::use_default_colors();
|
||||||
|
pancurses::curs_set(0);
|
||||||
|
pancurses::mouseinterval(0);
|
||||||
|
pancurses::mousemask(
|
||||||
|
pancurses::ALL_MOUSE_EVENTS | pancurses::REPORT_MOUSE_POSITION,
|
||||||
|
::std::ptr::null_mut(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// This asks the terminal to provide us with mouse drag events
|
||||||
|
// (Mouse move when a button is pressed).
|
||||||
|
// Replacing 1002 with 1003 would give us ANY mouse move.
|
||||||
|
print!("\x1B[?1002h");
|
||||||
|
stdout()
|
||||||
|
.flush()
|
||||||
|
.expect("could not flush stdout");
|
||||||
|
|
||||||
|
let c = Backend {
|
||||||
|
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
|
||||||
|
pairs: RefCell::new(HashMap::new()),
|
||||||
|
window: window,
|
||||||
|
last_mouse_button: None,
|
||||||
|
event_queue: Vec::new(),
|
||||||
|
key_codes: initialize_keymap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Box::new(c)
|
||||||
|
}
|
||||||
|
|
||||||
/// Save a new color pair.
|
/// Save a new color pair.
|
||||||
fn insert_color(
|
fn insert_color(
|
||||||
&self, pairs: &mut HashMap<(i16, i16), i32>, (front, back): (i16, i16)
|
&self, pairs: &mut HashMap<(i16, i16), i32>, (front, back): (i16, i16),
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let n = 1 + pairs.len() as i32;
|
let n = 1 + pairs.len() as i32;
|
||||||
|
|
||||||
@ -133,42 +169,11 @@ impl Concrete {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl backend::Backend for Concrete {
|
impl backend::Backend for Backend {
|
||||||
fn init() -> Self {
|
fn screen_size(&self) -> Vec2 {
|
||||||
::std::env::set_var("ESCDELAY", "25");
|
// Coordinates are reversed here
|
||||||
|
|
||||||
let window = pancurses::initscr();
|
|
||||||
window.keypad(true);
|
|
||||||
pancurses::noecho();
|
|
||||||
pancurses::cbreak();
|
|
||||||
pancurses::start_color();
|
|
||||||
pancurses::use_default_colors();
|
|
||||||
pancurses::curs_set(0);
|
|
||||||
pancurses::mouseinterval(0);
|
|
||||||
pancurses::mousemask(
|
|
||||||
pancurses::ALL_MOUSE_EVENTS | pancurses::REPORT_MOUSE_POSITION,
|
|
||||||
::std::ptr::null_mut(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// This asks the terminal to provide us with mouse drag events
|
|
||||||
// (Mouse move when a button is pressed).
|
|
||||||
// Replacing 1002 with 1003 would give us ANY mouse move.
|
|
||||||
print!("\x1B[?1002h");
|
|
||||||
stdout().flush().expect("could not flush stdout");
|
|
||||||
|
|
||||||
Concrete {
|
|
||||||
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
|
|
||||||
pairs: RefCell::new(HashMap::new()),
|
|
||||||
window: window,
|
|
||||||
last_mouse_button: None,
|
|
||||||
event_queue: Vec::new(),
|
|
||||||
key_codes: initialize_keymap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn screen_size(&self) -> (usize, usize) {
|
|
||||||
let (y, x) = self.window.get_max_yx();
|
let (y, x) = self.window.get_max_yx();
|
||||||
(x as usize, y as usize)
|
(x, y).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_colors(&self) -> bool {
|
fn has_colors(&self) -> bool {
|
||||||
@ -177,25 +182,23 @@ impl backend::Backend for Concrete {
|
|||||||
|
|
||||||
fn finish(&mut self) {
|
fn finish(&mut self) {
|
||||||
print!("\x1B[?1002l");
|
print!("\x1B[?1002l");
|
||||||
stdout().flush().expect("could not flush stdout");
|
stdout()
|
||||||
|
.flush()
|
||||||
|
.expect("could not flush stdout");
|
||||||
pancurses::endwin();
|
pancurses::endwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_color<F: FnOnce()>(&self, colors: ColorPair, f: F) {
|
fn set_color(&self, colors: ColorPair) -> ColorPair {
|
||||||
let current = self.current_style.get();
|
let current = self.current_style.get();
|
||||||
|
|
||||||
if current != colors {
|
if current != colors {
|
||||||
self.set_colors(colors);
|
self.set_colors(colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
f();
|
current
|
||||||
|
|
||||||
if current != colors {
|
|
||||||
self.set_colors(current);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
|
fn set_effect(&self, effect: Effect) {
|
||||||
let style = match effect {
|
let style = match effect {
|
||||||
Effect::Simple => pancurses::Attribute::Normal,
|
Effect::Simple => pancurses::Attribute::Normal,
|
||||||
Effect::Reverse => pancurses::Attribute::Reverse,
|
Effect::Reverse => pancurses::Attribute::Reverse,
|
||||||
@ -204,7 +207,16 @@ impl backend::Backend for Concrete {
|
|||||||
Effect::Underline => pancurses::Attribute::Underline,
|
Effect::Underline => pancurses::Attribute::Underline,
|
||||||
};
|
};
|
||||||
self.window.attron(style);
|
self.window.attron(style);
|
||||||
f();
|
}
|
||||||
|
|
||||||
|
fn unset_effect(&self, effect: Effect) {
|
||||||
|
let style = match effect {
|
||||||
|
Effect::Simple => pancurses::Attribute::Normal,
|
||||||
|
Effect::Reverse => pancurses::Attribute::Reverse,
|
||||||
|
Effect::Bold => pancurses::Attribute::Bold,
|
||||||
|
Effect::Italic => pancurses::Attribute::Italic,
|
||||||
|
Effect::Underline => pancurses::Attribute::Underline,
|
||||||
|
};
|
||||||
self.window.attroff(style);
|
self.window.attroff(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,8 +233,9 @@ impl backend::Backend for Concrete {
|
|||||||
self.window.refresh();
|
self.window.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_at(&self, (x, y): (usize, usize), text: &str) {
|
fn print_at(&self, pos: Vec2, text: &str) {
|
||||||
self.window.mvaddstr(y as i32, x as i32, text);
|
self.window
|
||||||
|
.mvaddstr(pos.y as i32, pos.x as i32, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_event(&mut self) -> Event {
|
fn poll_event(&mut self) -> Event {
|
||||||
|
49
src/backend/dummy.rs
Normal file
49
src/backend/dummy.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//! Dummy backend
|
||||||
|
use backend;
|
||||||
|
use theme;
|
||||||
|
use event;
|
||||||
|
use vec::Vec2;
|
||||||
|
|
||||||
|
pub struct Backend;
|
||||||
|
|
||||||
|
impl Backend {
|
||||||
|
pub fn init() -> Box<backend::Backend>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Box::new(Backend)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl backend::Backend for Backend {
|
||||||
|
fn finish(&mut self) {}
|
||||||
|
|
||||||
|
fn refresh(&mut self) {}
|
||||||
|
|
||||||
|
fn has_colors(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn screen_size(&self) -> Vec2 {
|
||||||
|
(1, 1).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_event(&mut self) -> event::Event {
|
||||||
|
event::Event::Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_at(&self, _: Vec2, _: &str) {}
|
||||||
|
|
||||||
|
fn clear(&self, _: theme::Color) {}
|
||||||
|
|
||||||
|
fn set_refresh_rate(&mut self, _: u32) {}
|
||||||
|
|
||||||
|
// This sets the Colours and returns the previous colours
|
||||||
|
// to allow you to set them back when you're done.
|
||||||
|
fn set_color(&self, colors: theme::ColorPair) -> theme::ColorPair {
|
||||||
|
colors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_effect(&self, _: theme::Effect) {}
|
||||||
|
fn unset_effect(&self, _: theme::Effect) {}
|
||||||
|
}
|
@ -1,40 +1,64 @@
|
|||||||
|
//! Define backends using common libraries.
|
||||||
|
//!
|
||||||
|
//! Cursive doesn't print anything by itself: it delegates this job to a
|
||||||
|
//! backend library, which handles all actual input and output.
|
||||||
|
//!
|
||||||
|
//! This module defines the `Backend` trait, as well as a few implementations
|
||||||
|
//! using some common libraries. Each of those included backends needs a
|
||||||
|
//! corresonding feature to be enabled.
|
||||||
|
|
||||||
use event;
|
use event;
|
||||||
use theme;
|
use theme;
|
||||||
|
|
||||||
#[cfg(feature = "termion")]
|
use vec::Vec2;
|
||||||
mod termion;
|
|
||||||
#[cfg(feature = "bear-lib-terminal")]
|
|
||||||
mod blt;
|
|
||||||
#[cfg(any(feature = "ncurses", feature = "pancurses"))]
|
|
||||||
mod curses;
|
|
||||||
|
|
||||||
#[cfg(feature = "bear-lib-terminal")]
|
pub mod dummy;
|
||||||
pub use self::blt::*;
|
|
||||||
#[cfg(any(feature = "ncurses", feature = "pancurses"))]
|
|
||||||
pub use self::curses::*;
|
|
||||||
#[cfg(feature = "termion")]
|
|
||||||
pub use self::termion::*;
|
|
||||||
|
|
||||||
|
pub mod termion;
|
||||||
|
pub mod blt;
|
||||||
|
pub mod curses;
|
||||||
|
|
||||||
|
/// Trait defining the required methods to be a backend.
|
||||||
pub trait Backend {
|
pub trait Backend {
|
||||||
fn init() -> Self;
|
|
||||||
// TODO: take `self` by value?
|
// TODO: take `self` by value?
|
||||||
// Or implement Drop?
|
// Or implement Drop?
|
||||||
|
/// Prepares to close the backend.
|
||||||
|
///
|
||||||
|
/// This should clear any state in the terminal.
|
||||||
fn finish(&mut self);
|
fn finish(&mut self);
|
||||||
|
|
||||||
|
/// Refresh the screen.
|
||||||
fn refresh(&mut self);
|
fn refresh(&mut self);
|
||||||
|
|
||||||
|
/// Should return `true` if this backend supports colors.
|
||||||
fn has_colors(&self) -> bool;
|
fn has_colors(&self) -> bool;
|
||||||
fn screen_size(&self) -> (usize, usize);
|
|
||||||
|
/// Returns the screen size.
|
||||||
|
fn screen_size(&self) -> Vec2;
|
||||||
|
|
||||||
/// Main input method
|
/// Main input method
|
||||||
fn poll_event(&mut self) -> event::Event;
|
fn poll_event(&mut self) -> event::Event;
|
||||||
|
|
||||||
/// Main method used for printing
|
/// Main method used for printing
|
||||||
fn print_at(&self, (usize, usize), &str);
|
fn print_at(&self, pos: Vec2, text: &str);
|
||||||
|
|
||||||
|
/// Clears the screen with the given color.
|
||||||
fn clear(&self, color: theme::Color);
|
fn clear(&self, color: theme::Color);
|
||||||
|
|
||||||
|
/// Sets the refresh rate for the backend.
|
||||||
|
///
|
||||||
|
/// If no event is detected in the interval, send an `Event::Refresh`.
|
||||||
fn set_refresh_rate(&mut self, fps: u32);
|
fn set_refresh_rate(&mut self, fps: u32);
|
||||||
// TODO: unify those into a single method?
|
|
||||||
fn with_color<F: FnOnce()>(&self, colors: theme::ColorPair, f: F);
|
/// Starts using a new color.
|
||||||
fn with_effect<F: FnOnce()>(&self, effect: theme::Effect, f: F);
|
///
|
||||||
|
/// This should return the previously active color.
|
||||||
|
fn set_color(&self, colors: theme::ColorPair) -> theme::ColorPair;
|
||||||
|
|
||||||
|
/// Enables the given effect.
|
||||||
|
fn set_effect(&self, effect: theme::Effect);
|
||||||
|
|
||||||
|
|
||||||
|
/// Disables the given effect.
|
||||||
|
fn unset_effect(&self, effect: theme::Effect);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
//! Backend using the pure-rust termion library.
|
||||||
|
//!
|
||||||
|
//! Requires the `termion-backend` feature.
|
||||||
|
#![cfg(feature = "termion")]
|
||||||
|
|
||||||
extern crate termion;
|
extern crate termion;
|
||||||
|
|
||||||
extern crate chan_signal;
|
extern crate chan_signal;
|
||||||
@ -20,7 +25,7 @@ use std::thread;
|
|||||||
use theme;
|
use theme;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
|
||||||
pub struct Concrete {
|
pub struct Backend {
|
||||||
terminal: AlternateScreen<MouseTerminal<RawTerminal<Stdout>>>,
|
terminal: AlternateScreen<MouseTerminal<RawTerminal<Stdout>>>,
|
||||||
current_style: Cell<theme::ColorPair>,
|
current_style: Cell<theme::ColorPair>,
|
||||||
input: chan::Receiver<TEvent>,
|
input: chan::Receiver<TEvent>,
|
||||||
@ -56,7 +61,39 @@ impl Effectable for theme::Effect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Concrete {
|
impl Backend {
|
||||||
|
pub fn init() -> Box<Self> {
|
||||||
|
print!("{}", termion::cursor::Hide);
|
||||||
|
|
||||||
|
let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);
|
||||||
|
|
||||||
|
// TODO: lock stdout
|
||||||
|
let terminal = AlternateScreen::from(MouseTerminal::from(
|
||||||
|
::std::io::stdout().into_raw_mode().unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let (sender, receiver) = chan::async();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
for key in ::std::io::stdin().events() {
|
||||||
|
if let Ok(key) = key {
|
||||||
|
sender.send(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let c = Backend {
|
||||||
|
terminal: terminal,
|
||||||
|
current_style: Cell::new(theme::ColorPair::from_256colors(0, 0)),
|
||||||
|
input: receiver,
|
||||||
|
resize: resize,
|
||||||
|
timeout: None,
|
||||||
|
last_button: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Box::new(c)
|
||||||
|
}
|
||||||
|
|
||||||
fn apply_colors(&self, colors: theme::ColorPair) {
|
fn apply_colors(&self, colors: theme::ColorPair) {
|
||||||
with_color(&colors.front, |c| print!("{}", tcolor::Fg(c)));
|
with_color(&colors.front, |c| print!("{}", tcolor::Fg(c)));
|
||||||
with_color(&colors.back, |c| print!("{}", tcolor::Bg(c)));
|
with_color(&colors.back, |c| print!("{}", tcolor::Bg(c)));
|
||||||
@ -136,37 +173,7 @@ impl Concrete {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl backend::Backend for Concrete {
|
impl backend::Backend for Backend {
|
||||||
fn init() -> Self {
|
|
||||||
print!("{}", termion::cursor::Hide);
|
|
||||||
|
|
||||||
let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);
|
|
||||||
|
|
||||||
// TODO: lock stdout
|
|
||||||
let terminal = AlternateScreen::from(MouseTerminal::from(
|
|
||||||
::std::io::stdout().into_raw_mode().unwrap(),
|
|
||||||
));
|
|
||||||
|
|
||||||
let (sender, receiver) = chan::async();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
for key in ::std::io::stdin().events() {
|
|
||||||
if let Ok(key) = key {
|
|
||||||
sender.send(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Concrete {
|
|
||||||
terminal: terminal,
|
|
||||||
current_style: Cell::new(theme::ColorPair::from_256colors(0, 0)),
|
|
||||||
input: receiver,
|
|
||||||
resize: resize,
|
|
||||||
timeout: None,
|
|
||||||
last_button: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finish(&mut self) {
|
fn finish(&mut self) {
|
||||||
print!(
|
print!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
@ -181,7 +188,7 @@ impl backend::Backend for Concrete {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_color<F: FnOnce()>(&self, color: theme::ColorPair, f: F) {
|
fn set_color(&self, color: theme::ColorPair) -> theme::ColorPair {
|
||||||
let current_style = self.current_style.get();
|
let current_style = self.current_style.get();
|
||||||
|
|
||||||
if current_style != color {
|
if current_style != color {
|
||||||
@ -189,17 +196,14 @@ impl backend::Backend for Concrete {
|
|||||||
self.current_style.set(color);
|
self.current_style.set(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
f();
|
return current_style;
|
||||||
|
|
||||||
if current_style != color {
|
|
||||||
self.current_style.set(current_style);
|
|
||||||
self.apply_colors(current_style);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_effect<F: FnOnce()>(&self, effect: theme::Effect, f: F) {
|
fn set_effect(&self, effect: theme::Effect) {
|
||||||
effect.on();
|
effect.on();
|
||||||
f();
|
}
|
||||||
|
|
||||||
|
fn unset_effect(&self, effect: theme::Effect) {
|
||||||
effect.off();
|
effect.off();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +212,9 @@ impl backend::Backend for Concrete {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen_size(&self) -> (usize, usize) {
|
fn screen_size(&self) -> Vec2 {
|
||||||
let (x, y) = termion::terminal_size().unwrap_or((1, 1));
|
let (x, y) = termion::terminal_size().unwrap_or((1, 1));
|
||||||
(x as usize, y as usize)
|
(x, y).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&self, color: theme::Color) {
|
fn clear(&self, color: theme::Color) {
|
||||||
@ -225,10 +229,10 @@ impl backend::Backend for Concrete {
|
|||||||
self.terminal.flush().unwrap();
|
self.terminal.flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_at(&self, (x, y): (usize, usize), text: &str) {
|
fn print_at(&self, pos: Vec2, text: &str) {
|
||||||
print!(
|
print!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
termion::cursor::Goto(1 + x as u16, 1 + y as u16),
|
termion::cursor::Goto(1 + pos.x as u16, 1 + pos.y as u16),
|
||||||
text
|
text
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
109
src/cursive.rs
109
src/cursive.rs
@ -1,5 +1,4 @@
|
|||||||
use backend;
|
use backend;
|
||||||
use backend::Backend;
|
|
||||||
use direction;
|
use direction;
|
||||||
use event::{Callback, Event, EventResult};
|
use event::{Callback, Event, EventResult};
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
@ -33,6 +32,34 @@ impl<F: FnOnce(&mut Cursive) -> () + Send> CbFunc for F {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "termion")]
|
||||||
|
impl Default for Cursive {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::termion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "termion"), feature = "pancurses"))]
|
||||||
|
impl Default for Cursive {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::pancurses()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "termion"), not(feature = "pancurses"), feature = "bear-lib-terminal"))]
|
||||||
|
impl Default for Cursive {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::blt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "termion"), not(feature = "pancurses"), not(feature = "bear-lib-terminal"), feature = "ncurses"))]
|
||||||
|
impl Default for Cursive {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::ncurses()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Central part of the cursive library.
|
/// Central part of the cursive library.
|
||||||
///
|
///
|
||||||
/// It initializes ncurses on creation and cleans up on drop.
|
/// It initializes ncurses on creation and cleans up on drop.
|
||||||
@ -54,19 +81,15 @@ pub struct Cursive {
|
|||||||
|
|
||||||
running: bool,
|
running: bool,
|
||||||
|
|
||||||
backend: backend::Concrete,
|
backend: Box<backend::Backend>,
|
||||||
|
|
||||||
cb_source: mpsc::Receiver<Box<CbFunc>>,
|
cb_source: mpsc::Receiver<Box<CbFunc>>,
|
||||||
cb_sink: mpsc::Sender<Box<CbFunc>>,
|
cb_sink: mpsc::Sender<Box<CbFunc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
new_default!(Cursive);
|
|
||||||
|
|
||||||
impl Cursive {
|
impl Cursive {
|
||||||
/// Creates a new Cursive root, and initialize the back-end.
|
/// Creates a new Cursive root, and initialize the back-end.
|
||||||
pub fn new() -> Self {
|
pub fn new(backend: Box<backend::Backend>) -> Self {
|
||||||
let backend = backend::Concrete::init();
|
|
||||||
|
|
||||||
let theme = theme::load_default();
|
let theme = theme::load_default();
|
||||||
// theme.activate(&mut backend);
|
// theme.activate(&mut backend);
|
||||||
// let theme = theme::load_theme("assets/style.toml").unwrap();
|
// let theme = theme::load_theme("assets/style.toml").unwrap();
|
||||||
@ -87,6 +110,37 @@ impl Cursive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new Cursive root using a ncurses backend.
|
||||||
|
#[cfg(feature = "ncurses")]
|
||||||
|
pub fn ncurses() -> Self {
|
||||||
|
Self::new(backend::curses::n::Backend::init())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new Cursive root using a pancurses backend.
|
||||||
|
#[cfg(feature = "pancurses")]
|
||||||
|
pub fn pancurses() -> Self {
|
||||||
|
Self::new(backend::curses::pan::Backend::init())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new Cursive root using a termion backend.
|
||||||
|
#[cfg(feature = "termion")]
|
||||||
|
pub fn termion() -> Self {
|
||||||
|
Self::new(backend::termion::Backend::init())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new Cursive root using a bear-lib-terminal backend.
|
||||||
|
#[cfg(feature = "bear-lib-terminal")]
|
||||||
|
pub fn blt() -> Self {
|
||||||
|
Self::new(backend::blt::Backend::init())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new Cursive root using a dummy backend.
|
||||||
|
///
|
||||||
|
/// Nothing will be output. This is mostly here for tests.
|
||||||
|
pub fn dummy() -> Self {
|
||||||
|
Self::new(backend::dummy::Backend::init())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a sink for asynchronous callbacks.
|
/// Returns a sink for asynchronous callbacks.
|
||||||
///
|
///
|
||||||
/// Returns the sender part of a channel, that allows to send
|
/// Returns the sender part of a channel, that allows to send
|
||||||
@ -100,11 +154,11 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::*;
|
/// # use cursive::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
/// siv.set_fps(10);
|
/// siv.set_fps(10);
|
||||||
///
|
///
|
||||||
/// // quit() will be called during the next event cycle
|
/// // quit() will be called during the next event cycle
|
||||||
@ -137,7 +191,7 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// #
|
/// #
|
||||||
/// # use cursive::{Cursive, event};
|
/// # use cursive::{Cursive, event};
|
||||||
@ -146,7 +200,7 @@ impl Cursive {
|
|||||||
/// # use cursive::menu::*;
|
/// # use cursive::menu::*;
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// siv.menubar()
|
/// siv.menubar()
|
||||||
/// .add_subtree("File",
|
/// .add_subtree("File",
|
||||||
@ -290,13 +344,13 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::{Cursive, views, view};
|
/// # use cursive::{Cursive, views, view};
|
||||||
/// # use cursive::traits::*;
|
/// # use cursive::traits::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// siv.add_layer(views::TextView::new("Text #1").with_id("text"));
|
/// siv.add_layer(views::TextView::new("Text #1").with_id("text"));
|
||||||
///
|
///
|
||||||
@ -328,12 +382,12 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::{Cursive, views};
|
/// # use cursive::{Cursive, views};
|
||||||
/// # use cursive::traits::*;
|
/// # use cursive::traits::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// siv.add_layer(views::TextView::new("Text #1")
|
/// siv.add_layer(views::TextView::new("Text #1")
|
||||||
/// .with_id("text"));
|
/// .with_id("text"));
|
||||||
@ -361,10 +415,10 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # use cursive::Cursive;
|
/// # use cursive::Cursive;
|
||||||
/// # use cursive::views::{TextView, ViewRef};
|
/// # use cursive::views::{TextView, ViewRef};
|
||||||
/// # let mut siv = Cursive::new();
|
/// # let mut siv = Cursive::dummy();
|
||||||
/// use cursive::traits::Identifiable;
|
/// use cursive::traits::Identifiable;
|
||||||
///
|
///
|
||||||
/// siv.add_layer(TextView::new("foo").with_id("id"));
|
/// siv.add_layer(TextView::new("foo").with_id("id"));
|
||||||
@ -401,11 +455,11 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::*;
|
/// # use cursive::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// siv.add_global_callback('q', |s| s.quit());
|
/// siv.add_global_callback('q', |s| s.quit());
|
||||||
/// # }
|
/// # }
|
||||||
@ -424,11 +478,11 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::*;
|
/// # use cursive::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// siv.add_global_callback('q', |s| s.quit());
|
/// siv.add_global_callback('q', |s| s.quit());
|
||||||
/// siv.clear_global_callbacks('q');
|
/// siv.clear_global_callbacks('q');
|
||||||
@ -446,11 +500,11 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::*;
|
/// # use cursive::*;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// siv.add_layer(views::TextView::new("Hello world!"));
|
/// siv.add_layer(views::TextView::new("Hello world!"));
|
||||||
/// # }
|
/// # }
|
||||||
@ -499,12 +553,7 @@ impl Cursive {
|
|||||||
|
|
||||||
/// Returns the size of the screen, in characters.
|
/// Returns the size of the screen, in characters.
|
||||||
pub fn screen_size(&self) -> Vec2 {
|
pub fn screen_size(&self) -> Vec2 {
|
||||||
let (x, y) = self.backend.screen_size();
|
self.backend.screen_size()
|
||||||
|
|
||||||
Vec2 {
|
|
||||||
x: x as usize,
|
|
||||||
y: y as usize,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&mut self) {
|
fn layout(&mut self) {
|
||||||
@ -526,7 +575,7 @@ impl Cursive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let printer =
|
let printer =
|
||||||
Printer::new(self.screen_size(), &self.theme, &self.backend);
|
Printer::new(self.screen_size(), &self.theme, &*self.backend);
|
||||||
|
|
||||||
let selected = self.menubar.receive_events();
|
let selected = self.menubar.receive_events();
|
||||||
|
|
||||||
|
@ -32,14 +32,14 @@
|
|||||||
//!
|
//!
|
||||||
//! ## Examples
|
//! ## Examples
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```rust
|
||||||
//! extern crate cursive;
|
//! extern crate cursive;
|
||||||
//!
|
//!
|
||||||
//! use cursive::Cursive;
|
//! use cursive::Cursive;
|
||||||
//! use cursive::views::TextView;
|
//! use cursive::views::TextView;
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let mut siv = Cursive::new();
|
//! let mut siv = Cursive::dummy();
|
||||||
//!
|
//!
|
||||||
//! siv.add_layer(TextView::new("Hello World!\nPress q to quit."));
|
//! siv.add_layer(TextView::new("Hello World!\nPress q to quit."));
|
||||||
//!
|
//!
|
||||||
@ -73,6 +73,7 @@ extern crate log;
|
|||||||
extern crate maplit;
|
extern crate maplit;
|
||||||
|
|
||||||
extern crate num;
|
extern crate num;
|
||||||
|
extern crate libc;
|
||||||
extern crate owning_ref;
|
extern crate owning_ref;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
extern crate unicode_segmentation;
|
extern crate unicode_segmentation;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Makes drawing on ncurses windows easier.
|
//! Makes drawing on ncurses windows easier.
|
||||||
|
|
||||||
use backend::{self, Backend};
|
use backend::Backend;
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
@ -34,7 +34,7 @@ pub struct Printer<'a> {
|
|||||||
new: Rc<Cell<bool>>,
|
new: Rc<Cell<bool>>,
|
||||||
|
|
||||||
/// Backend used to actually draw things
|
/// Backend used to actually draw things
|
||||||
backend: &'a backend::Concrete,
|
backend: &'a Backend,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Clone for Printer<'a> {
|
impl<'a> Clone for Printer<'a> {
|
||||||
@ -57,16 +57,16 @@ impl<'a> Printer<'a> {
|
|||||||
/// But nobody needs to know that.
|
/// But nobody needs to know that.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn new<T: Into<Vec2>>(
|
pub fn new<T: Into<Vec2>>(
|
||||||
size: T, theme: &'a Theme, backend: &'a backend::Concrete
|
size: T, theme: &'a Theme, backend: &'a Backend
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Printer {
|
Printer {
|
||||||
offset: Vec2::zero(),
|
offset: Vec2::zero(),
|
||||||
content_offset: Vec2::zero(),
|
content_offset: Vec2::zero(),
|
||||||
size: size.into(),
|
size: size.into(),
|
||||||
focused: true,
|
focused: true,
|
||||||
theme: theme,
|
theme,
|
||||||
new: Rc::new(Cell::new(true)),
|
new: Rc::new(Cell::new(true)),
|
||||||
backend: backend,
|
backend,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ impl<'a> Printer<'a> {
|
|||||||
let text = &text[..prefix_len];
|
let text = &text[..prefix_len];
|
||||||
|
|
||||||
let p = p + self.offset;
|
let p = p + self.offset;
|
||||||
self.backend.print_at((p.x, p.y), text);
|
self.backend.print_at(p, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a vertical line using the given character.
|
/// Prints a vertical line using the given character.
|
||||||
@ -118,7 +118,7 @@ impl<'a> Printer<'a> {
|
|||||||
|
|
||||||
let p = p + self.offset;
|
let p = p + self.offset;
|
||||||
for y in 0..len {
|
for y in 0..len {
|
||||||
self.backend.print_at((p.x, (p.y + y)), c);
|
self.backend.print_at(p + (0,y), c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ impl<'a> Printer<'a> {
|
|||||||
let text: String = ::std::iter::repeat(c).take(len).collect();
|
let text: String = ::std::iter::repeat(c).take(len).collect();
|
||||||
|
|
||||||
let p = p + self.offset;
|
let p = p + self.offset;
|
||||||
self.backend.print_at((p.x, p.y), &text);
|
self.backend.print_at(p, &text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the given closure with a colored printer,
|
/// Call the given closure with a colored printer,
|
||||||
@ -142,13 +142,13 @@ impl<'a> Printer<'a> {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```rust
|
||||||
/// # use cursive::Printer;
|
/// # use cursive::Printer;
|
||||||
/// # use cursive::theme;
|
/// # use cursive::theme;
|
||||||
/// # use cursive::backend::{self, Backend};
|
/// # use cursive::backend;
|
||||||
/// # let b = backend::Concrete::init();
|
/// # let b = backend::dummy::Backend::init();
|
||||||
/// # let t = theme::load_default();
|
/// # let t = theme::load_default();
|
||||||
/// # let printer = Printer::new((6,4), &t, &b);
|
/// # let printer = Printer::new((6,4), &t, &*b);
|
||||||
/// printer.with_color(theme::ColorStyle::highlight(), |printer| {
|
/// printer.with_color(theme::ColorStyle::highlight(), |printer| {
|
||||||
/// printer.print((0,0), "This text is highlighted!");
|
/// printer.print((0,0), "This text is highlighted!");
|
||||||
/// });
|
/// });
|
||||||
@ -157,8 +157,9 @@ impl<'a> Printer<'a> {
|
|||||||
where
|
where
|
||||||
F: FnOnce(&Printer),
|
F: FnOnce(&Printer),
|
||||||
{
|
{
|
||||||
self.backend
|
let old = self.backend.set_color(c.resolve(&self.theme.palette));
|
||||||
.with_color(c.resolve(&self.theme.palette), || f(self));
|
f(self);
|
||||||
|
self.backend.set_color(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the given closure with a styled printer,
|
/// Call the given closure with a styled printer,
|
||||||
@ -190,7 +191,9 @@ impl<'a> Printer<'a> {
|
|||||||
where
|
where
|
||||||
F: FnOnce(&Printer),
|
F: FnOnce(&Printer),
|
||||||
{
|
{
|
||||||
self.backend.with_effect(effect, || f(self));
|
self.backend.set_effect(effect);
|
||||||
|
f(self);
|
||||||
|
self.backend.unset_effect(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the given closure with a modified printer
|
/// Call the given closure with a modified printer
|
||||||
@ -217,13 +220,13 @@ impl<'a> Printer<'a> {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```rust
|
||||||
/// # use cursive::Printer;
|
/// # use cursive::Printer;
|
||||||
/// # use cursive::theme;
|
/// # use cursive::theme;
|
||||||
/// # use cursive::backend::{self, Backend};
|
/// # use cursive::backend;
|
||||||
/// # let b = backend::Concrete::init();
|
/// # let b = backend::dummy::Backend::init();
|
||||||
/// # let t = theme::load_default();
|
/// # let t = theme::load_default();
|
||||||
/// # let printer = Printer::new((6,4), &t, &b);
|
/// # let printer = Printer::new((6,4), &t, &*b);
|
||||||
/// printer.print_box((0,0), (6,4), false);
|
/// printer.print_box((0,0), (6,4), false);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn print_box<T: Into<Vec2>, S: Into<Vec2>>(
|
pub fn print_box<T: Into<Vec2>, S: Into<Vec2>>(
|
||||||
|
30
src/utils/counter.rs
Normal file
30
src/utils/counter.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
|
/// Atomic counter used by [`ProgressBar`].
|
||||||
|
///
|
||||||
|
/// [`ProgressBar`]: ../views/struct.ProgressBar.html
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Counter(pub Arc<AtomicUsize>);
|
||||||
|
|
||||||
|
impl Counter {
|
||||||
|
/// Creates a new `Counter` starting with the given value.
|
||||||
|
pub fn new(value: usize) -> Self {
|
||||||
|
Counter(Arc::new(AtomicUsize::new(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the current progress value.
|
||||||
|
pub fn get(&self) -> usize {
|
||||||
|
self.0.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the current progress value.
|
||||||
|
pub fn set(&self, value: usize) {
|
||||||
|
self.0.store(value, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase the current progress by `ticks`.
|
||||||
|
pub fn tick(&self, ticks: usize) {
|
||||||
|
self.0.fetch_add(ticks, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,13 @@
|
|||||||
//!
|
//!
|
||||||
//! Computed rows will include a list of span segments.
|
//! Computed rows will include a list of span segments.
|
||||||
//! Each segment include the source span ID, and start/end byte offsets.
|
//! Each segment include the source span ID, and start/end byte offsets.
|
||||||
mod lines_iterator;
|
|
||||||
mod chunk_iterator;
|
|
||||||
mod segment_merge_iterator;
|
|
||||||
mod row;
|
|
||||||
mod prefix;
|
|
||||||
mod chunk;
|
mod chunk;
|
||||||
|
mod chunk_iterator;
|
||||||
|
mod lines_iterator;
|
||||||
|
mod prefix;
|
||||||
|
mod row;
|
||||||
mod segment;
|
mod segment;
|
||||||
|
mod segment_merge_iterator;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -18,7 +18,7 @@ where
|
|||||||
|
|
||||||
let spans = parse_spans(&input);
|
let spans = parse_spans(&input);
|
||||||
|
|
||||||
StyledString::new(input, spans)
|
StyledString::with_spans(input, spans)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator that parse a markdown text and outputs styled spans.
|
/// Iterator that parse a markdown text and outputs styled spans.
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
//! Toolbox to make text layout easier.
|
//! Toolbox to make text layout easier.
|
||||||
|
|
||||||
mod reader;
|
mod counter;
|
||||||
pub mod span;
|
|
||||||
pub mod lines;
|
pub mod lines;
|
||||||
pub mod markup;
|
pub mod markup;
|
||||||
|
mod reader;
|
||||||
|
pub mod span;
|
||||||
|
|
||||||
|
pub use self::counter::Counter;
|
||||||
pub use self::reader::ProgressReader;
|
pub use self::reader::ProgressReader;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use views::Counter;
|
use utils::Counter;
|
||||||
|
|
||||||
/// Wrapper around a `Read` that reports the progress made.
|
/// Wrapper around a `Read` that reports the progress made.
|
||||||
///
|
///
|
||||||
@ -32,7 +32,7 @@ impl<R: Read> ProgressReader<R> {
|
|||||||
|
|
||||||
impl<R: Read> Read for ProgressReader<R> {
|
impl<R: Read> Read for ProgressReader<R> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
let result = try!(self.reader.read(buf));
|
let result = self.reader.read(buf)?;
|
||||||
self.counter.tick(result);
|
self.counter.tick(result);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,13 @@ pub trait Identifiable: View + Sized {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # use cursive::Cursive;
|
/// # use cursive::Cursive;
|
||||||
/// # use cursive::views::TextView;
|
/// # use cursive::views::TextView;
|
||||||
/// # use cursive::view::Boxable;
|
/// # use cursive::view::Boxable;
|
||||||
/// use cursive::view::Identifiable;
|
/// use cursive::view::Identifiable;
|
||||||
///
|
///
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
/// siv.add_layer(
|
/// siv.add_layer(
|
||||||
/// TextView::new("foo")
|
/// TextView::new("foo")
|
||||||
/// .with_id("text")
|
/// .with_id("text")
|
||||||
|
@ -18,10 +18,10 @@ impl Margins {
|
|||||||
/// Creates a new Margins.
|
/// Creates a new Margins.
|
||||||
pub fn new(left: usize, right: usize, top: usize, bottom: usize) -> Self {
|
pub fn new(left: usize, right: usize, top: usize, bottom: usize) -> Self {
|
||||||
Margins {
|
Margins {
|
||||||
left: left,
|
left,
|
||||||
right: right,
|
right,
|
||||||
top: top,
|
top,
|
||||||
bottom: bottom,
|
bottom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ impl Margins {
|
|||||||
|
|
||||||
impl From<(usize, usize, usize, usize)> for Margins {
|
impl From<(usize, usize, usize, usize)> for Margins {
|
||||||
fn from(
|
fn from(
|
||||||
(left, right, top, bottom): (usize, usize, usize, usize)
|
(left, right, top, bottom): (usize, usize, usize, usize),
|
||||||
) -> Margins {
|
) -> Margins {
|
||||||
Margins::new(left, right, top, bottom)
|
Margins::new(left, right, top, bottom)
|
||||||
}
|
}
|
||||||
@ -72,14 +72,14 @@ impl From<(i32, i32, i32, i32)> for Margins {
|
|||||||
|
|
||||||
impl From<((i32, i32), (i32, i32))> for Margins {
|
impl From<((i32, i32), (i32, i32))> for Margins {
|
||||||
fn from(
|
fn from(
|
||||||
((left, right), (top, bottom)): ((i32, i32), (i32, i32))
|
((left, right), (top, bottom)): ((i32, i32), (i32, i32)),
|
||||||
) -> Margins {
|
) -> Margins {
|
||||||
(left, right, top, bottom).into()
|
(left, right, top, bottom).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<((usize, usize), (usize, usize))> for Margins {
|
impl From<((usize, usize), (usize, usize))> for Margins {
|
||||||
fn from(
|
fn from(
|
||||||
((left, right), (top, bottom)): ((usize, usize), (usize, usize))
|
((left, right), (top, bottom)): ((usize, usize), (usize, usize)),
|
||||||
) -> Margins {
|
) -> Margins {
|
||||||
(left, right, top, bottom).into()
|
(left, right, top, bottom).into()
|
||||||
}
|
}
|
||||||
|
@ -228,15 +228,15 @@ impl ScrollBase {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```rust
|
||||||
/// # use cursive::view::ScrollBase;
|
/// # use cursive::view::ScrollBase;
|
||||||
/// # use cursive::Printer;
|
/// # use cursive::Printer;
|
||||||
/// # use cursive::theme;
|
/// # use cursive::theme;
|
||||||
/// # use cursive::backend::{self, Backend};
|
/// # use cursive::backend;
|
||||||
/// # let scrollbase = ScrollBase::new();
|
/// # let scrollbase = ScrollBase::new();
|
||||||
/// # let b = backend::Concrete::init();
|
/// # let b = backend::dummy::Backend::init();
|
||||||
/// # let t = theme::load_default();
|
/// # let t = theme::load_default();
|
||||||
/// # let printer = Printer::new((5,1), &t, &b);
|
/// # let printer = Printer::new((5,1), &t, &*b);
|
||||||
/// # let printer = &printer;
|
/// # let printer = &printer;
|
||||||
/// let lines = ["Line 1", "Line number 2"];
|
/// let lines = ["Line 1", "Line number 2"];
|
||||||
/// scrollbase.draw(printer, |printer, i| {
|
/// scrollbase.draw(printer, |printer, i| {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use XY;
|
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
use XY;
|
||||||
|
|
||||||
/// Cache around a one-dimensional layout result.
|
/// Cache around a one-dimensional layout result.
|
||||||
///
|
///
|
||||||
@ -19,8 +19,8 @@ impl SizeCache {
|
|||||||
/// Creates a new sized cache
|
/// Creates a new sized cache
|
||||||
pub fn new(value: usize, constrained: bool) -> Self {
|
pub fn new(value: usize, constrained: bool) -> Self {
|
||||||
SizeCache {
|
SizeCache {
|
||||||
value: value,
|
value,
|
||||||
constrained: constrained,
|
constrained,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ impl<T: ViewWrapper> View for T {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```rust
|
||||||
/// # #[macro_use] extern crate cursive;
|
/// # #[macro_use] extern crate cursive;
|
||||||
/// # use cursive::view::{View,ViewWrapper};
|
/// # use cursive::view::{View,ViewWrapper};
|
||||||
/// struct FooView<T: View> {
|
/// struct FooView<T: View> {
|
||||||
@ -197,7 +197,7 @@ macro_rules! wrap_impl {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```rust
|
||||||
/// # #[macro_use] extern crate cursive;
|
/// # #[macro_use] extern crate cursive;
|
||||||
/// # use cursive::view::{View,ViewWrapper};
|
/// # use cursive::view::{View,ViewWrapper};
|
||||||
/// struct FooView<T: View> {
|
/// struct FooView<T: View> {
|
||||||
|
@ -44,7 +44,7 @@ impl<T: View> BoxView<T> {
|
|||||||
BoxView {
|
BoxView {
|
||||||
size: (width, height).into(),
|
size: (width, height).into(),
|
||||||
squishable: false,
|
squishable: false,
|
||||||
view: view,
|
view,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ impl<T> Canvas<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn new(state: T) -> Self {
|
pub fn new(state: T) -> Self {
|
||||||
Canvas {
|
Canvas {
|
||||||
state: state,
|
state,
|
||||||
draw: Box::new(|_, _| ()),
|
draw: Box::new(|_, _| ()),
|
||||||
on_event: Box::new(|_, _| EventResult::Ignored),
|
on_event: Box::new(|_, _| EventResult::Ignored),
|
||||||
required_size: Box::new(|_, _| Vec2::new(1, 1)),
|
required_size: Box::new(|_, _| Vec2::new(1, 1)),
|
||||||
|
@ -30,13 +30,13 @@ pub type OnSubmit = Fn(&mut Cursive, &str);
|
|||||||
///
|
///
|
||||||
/// [1]: https://github.com/gyscos/Cursive/blob/master/examples/edit.rs
|
/// [1]: https://github.com/gyscos/Cursive/blob/master/examples/edit.rs
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::Cursive;
|
/// # use cursive::Cursive;
|
||||||
/// # use cursive::traits::*;
|
/// # use cursive::traits::*;
|
||||||
/// # use cursive::views::{Dialog, EditView, TextView};
|
/// # use cursive::views::{Dialog, EditView, TextView};
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// // Create a dialog with an edit text and a button.
|
/// // Create a dialog with an edit text and a button.
|
||||||
/// // The user can either hit the <Ok> button,
|
/// // The user can either hit the <Ok> button,
|
||||||
|
@ -113,7 +113,7 @@ impl LinearLayout {
|
|||||||
pub fn new(orientation: direction::Orientation) -> Self {
|
pub fn new(orientation: direction::Orientation) -> Self {
|
||||||
LinearLayout {
|
LinearLayout {
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
orientation: orientation,
|
orientation,
|
||||||
focus: 0,
|
focus: 0,
|
||||||
cache: None,
|
cache: None,
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ impl MenuPopup {
|
|||||||
/// Creates a new `MenuPopup` using the given menu tree.
|
/// Creates a new `MenuPopup` using the given menu tree.
|
||||||
pub fn new(menu: Rc<MenuTree>) -> Self {
|
pub fn new(menu: Rc<MenuTree>) -> Self {
|
||||||
MenuPopup {
|
MenuPopup {
|
||||||
menu: menu,
|
menu,
|
||||||
focus: 0,
|
focus: 0,
|
||||||
scrollbase: ScrollBase::new()
|
scrollbase: ScrollBase::new()
|
||||||
.scrollbar_offset(1)
|
.scrollbar_offset(1)
|
||||||
|
@ -78,7 +78,7 @@ pub use self::menu_popup::MenuPopup;
|
|||||||
pub use self::menubar::Menubar;
|
pub use self::menubar::Menubar;
|
||||||
pub use self::on_event_view::OnEventView;
|
pub use self::on_event_view::OnEventView;
|
||||||
pub use self::panel::Panel;
|
pub use self::panel::Panel;
|
||||||
pub use self::progress_bar::{Counter, ProgressBar};
|
pub use self::progress_bar::ProgressBar;
|
||||||
pub use self::radio::{RadioButton, RadioGroup};
|
pub use self::radio::{RadioButton, RadioGroup};
|
||||||
pub use self::scroll_view::ScrollView;
|
pub use self::scroll_view::ScrollView;
|
||||||
pub use self::select_view::SelectView;
|
pub use self::select_view::SelectView;
|
||||||
|
@ -72,7 +72,7 @@ impl<T: View> OnEventView<T> {
|
|||||||
/// Wraps the given view in a new OnEventView.
|
/// Wraps the given view in a new OnEventView.
|
||||||
pub fn new(view: T) -> Self {
|
pub fn new(view: T) -> Self {
|
||||||
OnEventView {
|
OnEventView {
|
||||||
view: view,
|
view,
|
||||||
callbacks: HashMap::new(),
|
callbacks: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub struct Panel<V: View> {
|
|||||||
impl<V: View> Panel<V> {
|
impl<V: View> Panel<V> {
|
||||||
/// Creates a new panel around the given view.
|
/// Creates a new panel around the given view.
|
||||||
pub fn new(view: V) -> Self {
|
pub fn new(view: V) -> Self {
|
||||||
Panel { view: view }
|
Panel { view }
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_getters!(self.view: V);
|
inner_getters!(self.view: V);
|
||||||
|
@ -1,40 +1,13 @@
|
|||||||
use Printer;
|
use Printer;
|
||||||
use align::HAlign;
|
use align::HAlign;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use theme::{ColorStyle, Effect};
|
use theme::{ColorStyle, Effect};
|
||||||
|
use utils::Counter;
|
||||||
use view::View;
|
use view::View;
|
||||||
|
|
||||||
// pub type CbPromise = Option<Box<Fn(&mut Cursive) + Send>>;
|
// pub type CbPromise = Option<Box<Fn(&mut Cursive) + Send>>;
|
||||||
|
|
||||||
/// Atomic counter used by `ProgressBar`.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Counter(pub Arc<AtomicUsize>);
|
|
||||||
|
|
||||||
impl Counter {
|
|
||||||
/// Creates a new `Counter` starting with the given value.
|
|
||||||
pub fn new(value: usize) -> Self {
|
|
||||||
Counter(Arc::new(AtomicUsize::new(value)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the current progress value.
|
|
||||||
pub fn get(&self) -> usize {
|
|
||||||
self.0.load(Ordering::Relaxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the current progress value.
|
|
||||||
pub fn set(&self, value: usize) {
|
|
||||||
self.0.store(value, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Increase the current progress by `ticks`.
|
|
||||||
pub fn tick(&self, ticks: usize) {
|
|
||||||
self.0.fetch_add(ticks, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Animated bar showing a progress value.
|
/// Animated bar showing a progress value.
|
||||||
///
|
///
|
||||||
/// This bar has an internal counter, and adapts the length of the displayed
|
/// This bar has an internal counter, and adapts the length of the displayed
|
||||||
|
@ -110,10 +110,10 @@ impl<T> RadioButton<T> {
|
|||||||
state: Rc<RefCell<SharedState<T>>>, id: usize, label: String
|
state: Rc<RefCell<SharedState<T>>>, id: usize, label: String
|
||||||
) -> Self {
|
) -> Self {
|
||||||
RadioButton {
|
RadioButton {
|
||||||
state: state,
|
state,
|
||||||
id: id,
|
id,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
label: label,
|
label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use views::MenuPopup;
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```rust
|
||||||
/// # extern crate cursive;
|
/// # extern crate cursive;
|
||||||
/// # use cursive::Cursive;
|
/// # use cursive::Cursive;
|
||||||
/// # use cursive::views::{SelectView, Dialog, TextView};
|
/// # use cursive::views::{SelectView, Dialog, TextView};
|
||||||
@ -40,7 +40,7 @@ use views::MenuPopup;
|
|||||||
/// .button("Quit", |s| s.quit()));
|
/// .button("Quit", |s| s.quit()));
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
/// siv.add_layer(Dialog::around(time_select)
|
/// siv.add_layer(Dialog::around(time_select)
|
||||||
/// .title("How long is your wait?"));
|
/// .title("How long is your wait?"));
|
||||||
/// # }
|
/// # }
|
||||||
@ -262,6 +262,15 @@ impl<T: 'static> SelectView<T> {
|
|||||||
.unwrap_or_else(Callback::dummy)
|
.unwrap_or_else(Callback::dummy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Inserts an item at position `index`, shifting all elements after it to
|
||||||
|
/// the right.
|
||||||
|
pub fn insert_item<S>(&mut self, index: usize, label: S, value: T)
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
self.items.insert(index, Item::new(label.into(), value));
|
||||||
|
}
|
||||||
|
|
||||||
/// Chainable variant of add_item
|
/// Chainable variant of add_item
|
||||||
pub fn item<S: Into<String>>(self, label: S, value: T) -> Self {
|
pub fn item<S: Into<String>>(self, label: S, value: T) -> Self {
|
||||||
self.with(|s| s.add_item(label, value))
|
self.with(|s| s.add_item(label, value))
|
||||||
@ -334,7 +343,7 @@ impl<T: 'static> SelectView<T> {
|
|||||||
// TODO: Check if `i >= self.len()` ?
|
// TODO: Check if `i >= self.len()` ?
|
||||||
// assert!(i < self.len(), "SelectView: trying to select out-of-bound");
|
// assert!(i < self.len(), "SelectView: trying to select out-of-bound");
|
||||||
// Or just cap the ID?
|
// Or just cap the ID?
|
||||||
let i = if self.len() == 0 {
|
let i = if self.is_empty() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
min(i, self.len() - 1)
|
min(i, self.len() - 1)
|
||||||
@ -638,6 +647,12 @@ impl SelectView<String> {
|
|||||||
self.with(|s| s.add_item_str(label))
|
self.with(|s| s.add_item_str(label))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenient method to use the label as value.
|
||||||
|
pub fn insert_item_str<S>(&mut self, index: usize, label: S) where S: Into<String> {
|
||||||
|
let label = label.into();
|
||||||
|
self.insert_item(index, label.clone(), label);
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds all strings from an iterator.
|
/// Adds all strings from an iterator.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -110,6 +110,37 @@ impl TextArea {
|
|||||||
self.with(|s| s.set_content(content))
|
self.with(|s| s.set_content(content))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Disables this view.
|
||||||
|
///
|
||||||
|
/// A disabled view cannot be selected.
|
||||||
|
pub fn disable(&mut self) {
|
||||||
|
self.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disables this view.
|
||||||
|
///
|
||||||
|
/// Chainable variant.
|
||||||
|
pub fn disabled(self) -> Self {
|
||||||
|
self.with(Self::disable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-enables this view.
|
||||||
|
pub fn enable(&mut self) {
|
||||||
|
self.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Re-enables this view.
|
||||||
|
///
|
||||||
|
/// Chainable variant.
|
||||||
|
pub fn enabled(self) -> Self {
|
||||||
|
self.with(Self::enable)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this view is enabled.
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
|
||||||
/// Finds the row containing the grapheme at the given offset
|
/// Finds the row containing the grapheme at the given offset
|
||||||
fn row_at(&self, offset: usize) -> usize {
|
fn row_at(&self, offset: usize) -> usize {
|
||||||
debug!("Offset: {}", offset);
|
debug!("Offset: {}", offset);
|
||||||
|
@ -155,10 +155,10 @@ impl TextContentInner {
|
|||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust
|
||||||
/// # use cursive::Cursive;
|
/// # use cursive::Cursive;
|
||||||
/// # use cursive::views::TextView;
|
/// # use cursive::views::TextView;
|
||||||
/// let mut siv = Cursive::new();
|
/// let mut siv = Cursive::dummy();
|
||||||
///
|
///
|
||||||
/// siv.add_layer(TextView::new("Hello world!"));
|
/// siv.add_layer(TextView::new("Hello world!"));
|
||||||
/// ```
|
/// ```
|
||||||
|
11
src/with.rs
11
src/with.rs
@ -14,6 +14,17 @@ pub trait With: Sized {
|
|||||||
f(&mut self)?;
|
f(&mut self)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calls the given closure if `condition == true`.
|
||||||
|
fn with_if<F>(mut self, condition: bool, f: F) -> Self
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self),
|
||||||
|
{
|
||||||
|
if condition {
|
||||||
|
f(&mut self);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Sized> With for T {}
|
impl<T: Sized> With for T {}
|
||||||
|
@ -13,7 +13,7 @@ pub struct XY<T> {
|
|||||||
impl<T> XY<T> {
|
impl<T> XY<T> {
|
||||||
/// Creates a new `XY` from the given values.
|
/// Creates a new `XY` from the given values.
|
||||||
pub fn new(x: T, y: T) -> Self {
|
pub fn new(x: T, y: T) -> Self {
|
||||||
XY { x: x, y: y }
|
XY { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `f(self.x, self.y)`
|
/// Returns `f(self.x, self.y)`
|
||||||
|
Loading…
Reference in New Issue
Block a user