mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-08 18:30:40 +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 ::Cursive;
|
||||
use view::ViewPath;
|
||||
|
||||
/// Callback is a function that can be triggered by an event.
|
||||
/// 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.
|
||||
/// The event can be consumed or ignored.
|
||||
@ -12,5 +15,5 @@ pub enum EventResult {
|
||||
/// The event was ignored. The parent can keep handling it.
|
||||
Ignored,
|
||||
/// 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();
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
extern crate ncurses;
|
||||
|
||||
pub mod event;
|
||||
pub mod view;
|
||||
pub mod printer;
|
||||
pub mod vec2;
|
||||
mod box_view;
|
||||
mod stack_view;
|
||||
mod text_view;
|
||||
|
||||
mod div;
|
||||
|
||||
use std::any::Any;
|
||||
use std::rc::Rc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use vec2::Vec2;
|
||||
use view::View;
|
||||
use printer::Printer;
|
||||
use stack_view::StackView;
|
||||
use view::{StackView,ViewPath};
|
||||
|
||||
use event::{EventResult,Callback};
|
||||
|
||||
@ -47,6 +44,7 @@ use event::{EventResult,Callback};
|
||||
pub type ScreenId = usize;
|
||||
|
||||
/// Central part of the cursive library.
|
||||
///
|
||||
/// It initializes ncurses on creation and cleans up on drop.
|
||||
/// To use it, you should populate it with views, layouts and callbacks,
|
||||
/// then start the event loop with run().
|
||||
@ -110,9 +108,23 @@ impl Cursive {
|
||||
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.
|
||||
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)));
|
||||
}
|
||||
@ -128,9 +140,11 @@ impl Cursive {
|
||||
None => return,
|
||||
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 {
|
||||
let mut x: 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.
|
||||
match self.screen_mut().on_key_event(ch) {
|
||||
EventResult::Ignored => self.on_key_event(ch),
|
||||
EventResult::Consumed(None) => (),
|
||||
EventResult::Consumed(Some(cb)) => cb(self),
|
||||
EventResult::Consumed(None, _) => (),
|
||||
EventResult::Consumed(Some(cb), path) => cb(self, &path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stops the event loop.
|
||||
pub fn quit(&mut self) {
|
||||
self.running = false;
|
||||
}
|
||||
|
@ -7,9 +7,13 @@ fn main() {
|
||||
let mut siv = Cursive::new();
|
||||
|
||||
// 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_global_callback('a' as i32, |s, _| {
|
||||
//
|
||||
});
|
||||
|
||||
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 vec2::{Vec2,ToVec2};
|
||||
use view::{View,SizeRequest};
|
||||
use super::{View,SizeRequest};
|
||||
use printer::Printer;
|
||||
|
||||
/// 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.
|
||||
|
||||
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;
|
||||
|
||||
pub use box_view::BoxView;
|
||||
pub use stack_view::StackView;
|
||||
pub use text_view::TextView;
|
||||
|
||||
use vec2::Vec2;
|
||||
use printer::Printer;
|
||||
|
||||
@ -43,4 +52,9 @@ pub trait View {
|
||||
|
||||
/// Draws the view within the given bounds.
|
||||
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