mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-12 12:13:08 +00:00
Add ViewPath and Cursive::find
Callbacks now include a path to the triggering view. The Cursive root can find the View corresponding to a ViewPath. In the future, ViewPaths may be returned when creating the layout.
This commit is contained in:
parent
6cd2a28966
commit
e17ca97136
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use ::Cursive;
|
||||||
|
use view::ViewPath;
|
||||||
|
|
||||||
/// Callback is a function that can be triggered by an event.
|
/// Callback is a function that can be triggered by an event.
|
||||||
/// It has a mutable access to the cursive root.
|
/// It has a mutable access to the cursive root.
|
||||||
pub type Callback = Box<Fn(&mut super::Cursive)>;
|
pub type Callback = Box<Fn(&mut Cursive, &ViewPath)>;
|
||||||
|
|
||||||
/// Answer to an event notification.
|
/// Answer to an event notification.
|
||||||
/// The event can be consumed or ignored.
|
/// The event can be consumed or ignored.
|
||||||
@ -12,5 +15,5 @@ pub enum EventResult {
|
|||||||
/// The event was ignored. The parent can keep handling it.
|
/// The event was ignored. The parent can keep handling it.
|
||||||
Ignored,
|
Ignored,
|
||||||
/// The event was consumed. An optionnal callback to run is attached.
|
/// The event was consumed. An optionnal callback to run is attached.
|
||||||
Consumed(Option<Rc<Callback>>),
|
Consumed(Option<Rc<Callback>>, ViewPath),
|
||||||
}
|
}
|
||||||
|
33
src/lib.rs
33
src/lib.rs
@ -20,26 +20,23 @@
|
|||||||
//! siv.run();
|
//! siv.run();
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
extern crate ncurses;
|
extern crate ncurses;
|
||||||
|
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod view;
|
pub mod view;
|
||||||
pub mod printer;
|
pub mod printer;
|
||||||
pub mod vec2;
|
pub mod vec2;
|
||||||
mod box_view;
|
|
||||||
mod stack_view;
|
|
||||||
mod text_view;
|
|
||||||
|
|
||||||
mod div;
|
mod div;
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use vec2::Vec2;
|
use vec2::Vec2;
|
||||||
use view::View;
|
use view::View;
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
use stack_view::StackView;
|
use view::{StackView,ViewPath};
|
||||||
|
|
||||||
use event::{EventResult,Callback};
|
use event::{EventResult,Callback};
|
||||||
|
|
||||||
@ -47,6 +44,7 @@ use event::{EventResult,Callback};
|
|||||||
pub type ScreenId = usize;
|
pub type ScreenId = usize;
|
||||||
|
|
||||||
/// 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.
|
||||||
/// To use it, you should populate it with views, layouts and callbacks,
|
/// To use it, you should populate it with views, layouts and callbacks,
|
||||||
/// then start the event loop with run().
|
/// then start the event loop with run().
|
||||||
@ -110,9 +108,23 @@ impl Cursive {
|
|||||||
self.active_screen = screen_id;
|
self.active_screen = screen_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_any(&mut self, path: &ViewPath) -> Option<&mut Any> {
|
||||||
|
self.screen_mut().find(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to find the view pointed to by the given path.
|
||||||
|
/// If the view is not found, or if it is not of the asked type,
|
||||||
|
/// it returns None.
|
||||||
|
pub fn find<V: View + Any>(&mut self, path: &ViewPath) -> Option<&mut V> {
|
||||||
|
match self.find_any(path) {
|
||||||
|
None => None,
|
||||||
|
Some(b) => b.downcast_mut::<V>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a global callback, triggered on the given key press when no view catches it.
|
/// Adds a global callback, triggered on the given key press when no view catches it.
|
||||||
pub fn add_global_callback<F>(&mut self, key: i32, cb: F)
|
pub fn add_global_callback<F>(&mut self, key: i32, cb: F)
|
||||||
where F: Fn(&mut Cursive) + 'static
|
where F: Fn(&mut Cursive, &ViewPath) + 'static
|
||||||
{
|
{
|
||||||
self.global_callbacks.insert(key, Rc::new(Box::new(cb)));
|
self.global_callbacks.insert(key, Rc::new(Box::new(cb)));
|
||||||
}
|
}
|
||||||
@ -128,9 +140,11 @@ impl Cursive {
|
|||||||
None => return,
|
None => return,
|
||||||
Some(cb) => cb.clone(),
|
Some(cb) => cb.clone(),
|
||||||
};
|
};
|
||||||
cb(self);
|
// Not from a view, so no viewpath here
|
||||||
|
cb(self, &ViewPath::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the size of the screen, in characters.
|
||||||
pub fn screen_size(&self) -> Vec2 {
|
pub fn screen_size(&self) -> Vec2 {
|
||||||
let mut x: i32 = 0;
|
let mut x: i32 = 0;
|
||||||
let mut y: i32 = 0;
|
let mut y: i32 = 0;
|
||||||
@ -180,12 +194,13 @@ impl Cursive {
|
|||||||
// If the event was ignored, it is our turn to play with it.
|
// If the event was ignored, it is our turn to play with it.
|
||||||
match self.screen_mut().on_key_event(ch) {
|
match self.screen_mut().on_key_event(ch) {
|
||||||
EventResult::Ignored => self.on_key_event(ch),
|
EventResult::Ignored => self.on_key_event(ch),
|
||||||
EventResult::Consumed(None) => (),
|
EventResult::Consumed(None, _) => (),
|
||||||
EventResult::Consumed(Some(cb)) => cb(self),
|
EventResult::Consumed(Some(cb), path) => cb(self, &path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stops the event loop.
|
||||||
pub fn quit(&mut self) {
|
pub fn quit(&mut self) {
|
||||||
self.running = false;
|
self.running = false;
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,13 @@ fn main() {
|
|||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::new();
|
||||||
|
|
||||||
// We can quit by pressing q
|
// We can quit by pressing q
|
||||||
siv.add_global_callback('q' as i32, |s| s.quit());
|
siv.add_global_callback('q' as i32, |s,_| s.quit());
|
||||||
|
|
||||||
siv.add_layer(TextView::new("Hello World!\nPress q to quit the application."));
|
siv.add_layer(TextView::new("Hello World!\nPress q to quit the application."));
|
||||||
|
|
||||||
|
siv.add_global_callback('a' as i32, |s, _| {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
|
||||||
siv.run();
|
siv.run();
|
||||||
}
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
use super::View;
|
|
||||||
|
|
||||||
pub trait ToView {
|
|
||||||
fn to_view(self) -> Box<View>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ToView for &'a str {
|
|
||||||
fn to_view(self) -> Box<View> {
|
|
||||||
Box::new(TextView::new(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
use event::EventResult;
|
use event::EventResult;
|
||||||
use vec2::{Vec2,ToVec2};
|
use vec2::{Vec2,ToVec2};
|
||||||
use view::{View,SizeRequest};
|
use super::{View,SizeRequest};
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
|
|
||||||
/// BoxView is a wrapper around an other view, with a given minimum size.
|
/// BoxView is a wrapper around an other view, with a given minimum size.
|
59
src/view/key_event_view.rs
Normal file
59
src/view/key_event_view.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use ::Cursive;
|
||||||
|
use event::{EventResult,Callback};
|
||||||
|
use vec2::{Vec2};
|
||||||
|
use super::{View,SizeRequest,ViewPath};
|
||||||
|
use printer::Printer;
|
||||||
|
|
||||||
|
/// A simple wrapper view that catches some ignored event from its child.
|
||||||
|
///
|
||||||
|
/// Events ignored by its child without a callback will stay ignored.
|
||||||
|
pub struct KeyEventView {
|
||||||
|
content: Box<View>,
|
||||||
|
callbacks: HashMap<i32, Rc<Callback>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyEventView {
|
||||||
|
/// Wraps the given view in a new KeyEventView.
|
||||||
|
pub fn new<V: View + 'static>(view: V) -> Self {
|
||||||
|
KeyEventView {
|
||||||
|
content: Box::new(view),
|
||||||
|
callbacks: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers a callback when the given key is ignored by the child.
|
||||||
|
pub fn register<F>(mut self, key: i32, cb: F) -> Self
|
||||||
|
where F: Fn(&mut Cursive, &ViewPath) + 'static
|
||||||
|
{
|
||||||
|
self.callbacks.insert(key, Rc::new(Box::new(cb)));
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for KeyEventView {
|
||||||
|
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
||||||
|
match self.content.on_key_event(ch) {
|
||||||
|
EventResult::Ignored => match self.callbacks.get(&ch) {
|
||||||
|
None => EventResult::Ignored,
|
||||||
|
Some(cb) => EventResult::Consumed(Some(cb.clone()), ViewPath::new()),
|
||||||
|
},
|
||||||
|
EventResult::Consumed(cb, path) => EventResult::Consumed(cb, path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, printer: &Printer) {
|
||||||
|
self.content.draw(printer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_min_size(&self, req: SizeRequest) -> Vec2 {
|
||||||
|
self.content.get_min_size(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(&mut self, size: Vec2) {
|
||||||
|
self.content.layout(size);
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,20 @@
|
|||||||
//! Defines various views to use when creating the layout.
|
//! Defines various views to use when creating the layout.
|
||||||
|
|
||||||
|
mod box_view;
|
||||||
|
mod stack_view;
|
||||||
|
mod text_view;
|
||||||
|
mod key_event_view;
|
||||||
|
mod view_path;
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
pub use self::view_path::ViewPath;
|
||||||
|
pub use self::key_event_view::KeyEventView;
|
||||||
|
pub use self::box_view::BoxView;
|
||||||
|
pub use self::stack_view::StackView;
|
||||||
|
pub use self::text_view::TextView;
|
||||||
|
|
||||||
use event::EventResult;
|
use event::EventResult;
|
||||||
|
|
||||||
pub use box_view::BoxView;
|
|
||||||
pub use stack_view::StackView;
|
|
||||||
pub use text_view::TextView;
|
|
||||||
|
|
||||||
use vec2::Vec2;
|
use vec2::Vec2;
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
|
|
||||||
@ -43,4 +52,9 @@ pub trait View {
|
|||||||
|
|
||||||
/// Draws the view within the given bounds.
|
/// Draws the view within the given bounds.
|
||||||
fn draw(&self, &Printer);
|
fn draw(&self, &Printer);
|
||||||
|
|
||||||
|
/// Finds the view pointed to by the given path.
|
||||||
|
/// Returns None if the path doesn't lead to a view.
|
||||||
|
fn find(&mut self, &ViewPath) -> Option<&mut Any> { None }
|
||||||
}
|
}
|
||||||
|
|
15
src/view/view_path.rs
Normal file
15
src/view/view_path.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/// Represents a path to a single view in the layout.
|
||||||
|
pub struct ViewPath {
|
||||||
|
/// List of turns to make on decision nodes when descending the view tree.
|
||||||
|
/// Simple nodes (with one fixed child) are skipped.
|
||||||
|
pub path: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewPath {
|
||||||
|
/// Creates a new empty path.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ViewPath {
|
||||||
|
path: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user