Add selector by ID

This commit is contained in:
Alexandre Bury 2015-05-23 10:33:29 -07:00
parent 77aae36836
commit d9b56574d2
8 changed files with 117 additions and 31 deletions

View File

@ -32,3 +32,7 @@ path = "examples/dialog.rs"
[[example]]
name = "logs"
path = "examples/logs.rs"
[[example]]
name = "mutation"
path = "examples/mutation.rs"

16
examples/mutation.rs Normal file
View File

@ -0,0 +1,16 @@
extern crate cursive;
use cursive::Cursive;
use cursive::view::{IdView,TextView,Dialog,Selector};
fn main() {
let mut siv = Cursive::new();
siv.add_layer(IdView::new("text", TextView::new("Aaahh\nAaaah\nAaaah\nAaaaah\nAaaaah\nAaaaah\nAaaaah")));
siv.add_layer(Dialog::new(TextView::new("Tak!"))
.button("Change", |s,_| s.find::<TextView>(&Selector::Id("text")).unwrap()
.set_content("Bleeeeh") ));
siv.run();
}

View File

@ -41,7 +41,7 @@ use std::collections::HashMap;
use vec::Vec2;
use view::View;
use printer::Printer;
use view::{StackView,ViewPath};
use view::{StackView,ViewPath,Selector};
use event::{EventResult,Callback};
@ -132,16 +132,16 @@ impl Cursive {
self.active_screen = screen_id;
}
fn find_any(&mut self, path: &ViewPath) -> Option<&mut Any> {
fn find_any(&mut self, selector: &Selector) -> Option<&mut Any> {
// Internal find method that returns a Any object.
self.screen_mut().find(path)
self.screen_mut().find(selector)
}
/// 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) {
pub fn find<V: View + Any>(&mut self, selector: &Selector) -> Option<&mut V> {
match self.find_any(selector) {
None => None,
Some(b) => b.downcast_mut::<V>(),
}

30
src/view/id_view.rs Normal file
View File

@ -0,0 +1,30 @@
use std::any::Any;
use view::{View,ViewWrapper,Selector};
/// Wrapper view that allows to select its content with a fixed string id.
pub struct IdView<T: View> {
view: T,
id: String,
}
impl<T: View> IdView<T> {
/// Wraps the given view. It will be selectable with the given id.
pub fn new(id: &str, view: T) -> Self {
IdView {
view: view,
id: id.to_string(),
}
}
}
impl <T: View + Any> ViewWrapper for IdView<T> {
wrap_impl!(&self.view);
fn wrap_find(&mut self, selector: &Selector) -> Option<&mut Any> {
match selector {
&Selector::Id(id) if id == self.id => Some(&mut self.view),
s => self.view.find(s),
}
}
}

View File

@ -10,6 +10,7 @@ mod dialog;
mod button;
mod sized_view;
mod full_view;
mod id_view;
use std::any::Any;
@ -23,11 +24,41 @@ pub use self::button::Button;
pub use self::sized_view::SizedView;
pub use self::view_wrapper::ViewWrapper;
pub use self::full_view::FullView;
pub use self::id_view::IdView;
use event::EventResult;
use vec::{Vec2,ToVec2};
use printer::Printer;
/// Main trait defining a view behaviour.
pub trait View {
/// Called when a key was pressed. Default implementation just ignores it.
fn on_key_event(&mut self, i32) -> EventResult { EventResult::Ignored }
/// Returns the minimum size the view requires under the given restrictions.
fn get_min_size(&self, SizeRequest) -> Vec2 { Vec2::new(1,1) }
/// Called once the size for this view has been decided, so it can
/// propagate the information to its children.
fn layout(&mut self, Vec2) { }
/// Draws the view with the given printer (includes bounds) and focus.
fn draw(&mut self, printer: &Printer, focused: bool);
/// Finds the view pointed to by the given path.
/// Returns None if the path doesn't lead to a view.
fn find(&mut self, &Selector) -> Option<&mut Any> { None }
/// This view is offered focus. Will it take it?
fn take_focus(&mut self) -> bool { false }
}
/// Selects a single view (if any) in the tree.
pub enum Selector<'a> {
Id(&'a str),
Path(&'a ViewPath),
}
/// Describe constraints on a view layout in one dimension.
#[derive(PartialEq,Clone,Copy)]
pub enum DimensionRequest {
@ -78,26 +109,4 @@ impl SizeRequest {
}
}
/// Main trait defining a view behaviour.
pub trait View {
/// Called when a key was pressed. Default implementation just ignores it.
fn on_key_event(&mut self, i32) -> EventResult { EventResult::Ignored }
/// Returns the minimum size the view requires under the given restrictions.
fn get_min_size(&self, SizeRequest) -> Vec2 { Vec2::new(1,1) }
/// Called once the size for this view has been decided, so it can
/// propagate the information to its children.
fn layout(&mut self, Vec2) { }
/// Draws the view with the given printer (includes bounds) and focus.
fn draw(&mut self, printer: &Printer, focused: bool);
/// 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 }
/// This view is offered focus. Will it take it?
fn take_focus(&mut self) -> bool { false }
}

View File

@ -1,10 +1,11 @@
use std::cmp::max;
use std::any::Any;
use ncurses;
use color;
use vec::Vec2;
use view::{View,SizeRequest,DimensionRequest};
use view::{View,SizeRequest,DimensionRequest,Selector};
use event::EventResult;
use printer::Printer;
@ -57,7 +58,7 @@ impl View for StackView {
let y = (printer.size.y - h) / 2;
let printer = printer.style(color::SHADOW);
let printer = printer.style(color::HIGHLIGHT);
printer.print_hline((x+1,y+h), w, ' ' as u64);
printer.print_vline((x+w,y+1), h, ' ' as u64);
@ -115,4 +116,13 @@ impl View for StackView {
Some(mut v) => v.view.take_focus()
}
}
fn find(&mut self, selector: &Selector) -> Option<&mut Any> {
for layer in self.layers.iter_mut() {
if let Some(any) = layer.view.find(selector) {
return Some(any);
}
}
None
}
}

View File

@ -33,6 +33,10 @@ impl TextView {
}
}
pub fn set_content(&mut self, content: &str) {
self.content = content.to_string();
}
/// Returns the number of lines required to display the content
/// with the given width.
fn get_num_lines(&self, max_width: usize) -> usize {

View File

@ -1,9 +1,14 @@
use std::any::Any;
use vec::Vec2;
use view::{View,SizeRequest};
use view::{View,SizeRequest,Selector};
use printer::Printer;
use event::EventResult;
/// Wrapper around a view. Can override some methods, forwards the others.
/// Generic wrapper around a view.
///
/// Default implementation forwards all calls to the child view.
/// Overrides some methods as desired.
pub trait ViewWrapper {
/// Get an immutable reference to the wrapped view, so that we can forward some calls to it.
fn get_view(&self) -> &View;
@ -34,6 +39,10 @@ pub trait ViewWrapper {
fn wrap_take_focus(&mut self) -> bool {
self.get_view_mut().take_focus()
}
fn wrap_find(&mut self, selector: &Selector) -> Option<&mut Any> {
self.get_view_mut().find(selector)
}
}
impl <T: ViewWrapper> View for T {
@ -56,6 +65,10 @@ impl <T: ViewWrapper> View for T {
fn take_focus(&mut self) -> bool {
self.wrap_take_focus()
}
fn find(&mut self, selector: &Selector) -> Option<&mut Any> {
self.wrap_find(selector)
}
}
/// Convenient macro to implement to two methods required for the ViewWrapper trait.