mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Transform ncurses i32 key into Event enum
Prepares support for unicode char input spanning multiple ncurses characters.
This commit is contained in:
parent
ca09885978
commit
f9c9e56518
@ -7,7 +7,7 @@ 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', |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."));
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct KeyCodeView {
|
struct KeyCodeView {
|
||||||
history: Vec<i32>,
|
history: Vec<String>,
|
||||||
size: usize,
|
size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,13 +30,17 @@ impl KeyCodeView {
|
|||||||
|
|
||||||
impl View for KeyCodeView {
|
impl View for KeyCodeView {
|
||||||
fn draw(&mut self, printer: &Printer, _: bool) {
|
fn draw(&mut self, printer: &Printer, _: bool) {
|
||||||
for (y,n) in self.history.iter().enumerate() {
|
for (y,line) in self.history.iter().enumerate() {
|
||||||
printer.print((0,y), &format!("{}", n));
|
printer.print((0,y), &line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
self.history.push(ch);
|
let line = match event {
|
||||||
|
Event::CharEvent(c) => format!("Char: {}", c),
|
||||||
|
Event::KeyEvent(key) => format!("Key: {}", key),
|
||||||
|
}
|
||||||
|
self.history.push(line);
|
||||||
|
|
||||||
while self.history.len() > self.size {
|
while self.history.len() > self.size {
|
||||||
self.history.remove(0);
|
self.history.remove(0);
|
||||||
|
@ -13,7 +13,7 @@ fn main() {
|
|||||||
|
|
||||||
// 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);
|
||||||
siv.add_global_callback('q' as i32, |s| s.quit());
|
siv.add_global_callback('q', |s| s.quit());
|
||||||
|
|
||||||
// A channel will communicate data from our running task to the UI.
|
// A channel will communicate data from our running task to the UI.
|
||||||
let (tx,rx) = mpsc::channel();
|
let (tx,rx) = mpsc::channel();
|
||||||
|
@ -15,7 +15,7 @@ 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', |s| s.quit());
|
||||||
|
|
||||||
// The text is too long to fit on a line, so the view will wrap lines,
|
// The text is too long to fit on a line, so the view will wrap lines,
|
||||||
// and will adapt to the terminal size.
|
// and will adapt to the terminal size.
|
||||||
|
@ -21,13 +21,13 @@ fn main() {
|
|||||||
|
|
||||||
let content = "Press Q to quit the application.\n\nPress P to open the popup.";
|
let content = "Press Q to quit the application.\n\nPress P to open the popup.";
|
||||||
|
|
||||||
siv.add_global_callback('q' as i32, |s| s.quit());
|
siv.add_global_callback('q', |s| s.quit());
|
||||||
|
|
||||||
// Let's wrap the view to give it a recognizable ID, so we can look for it.
|
// Let's wrap the view to give it a recognizable ID, so we can look for it.
|
||||||
// We add the P callback on the textview only (and not globally),
|
// We add the P callback on the textview only (and not globally),
|
||||||
// so that we can't call it when the popup is already visible.
|
// so that we can't call it when the popup is already visible.
|
||||||
siv.add_layer(KeyEventView::new(IdView::new("text", TextView::new(content)))
|
siv.add_layer(KeyEventView::new(IdView::new("text", TextView::new(content)))
|
||||||
.register('p' as i32, |s| show_popup(s)));
|
.register('p', |s| show_popup(s)));
|
||||||
|
|
||||||
|
|
||||||
siv.run();
|
siv.run();
|
||||||
|
87
src/event.rs
87
src/event.rs
@ -1,7 +1,10 @@
|
|||||||
//! User-input events and their effects.
|
//! User-input events and their effects.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use ncurses;
|
||||||
|
|
||||||
use ::Cursive;
|
use ::Cursive;
|
||||||
|
|
||||||
/// Callback is a function that can be triggered by an event.
|
/// Callback is a function that can be triggered by an event.
|
||||||
@ -16,3 +19,87 @@ pub enum EventResult {
|
|||||||
/// 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>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq,Eq,Clone,Copy,Hash)]
|
||||||
|
pub enum Key {
|
||||||
|
Enter,
|
||||||
|
ArrowLeft,
|
||||||
|
ArrowRight,
|
||||||
|
ArrowUp,
|
||||||
|
ArrowDown,
|
||||||
|
PageUp,
|
||||||
|
PageDown,
|
||||||
|
Backspace,
|
||||||
|
Home,
|
||||||
|
End,
|
||||||
|
Del,
|
||||||
|
Unknown(i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Key {
|
||||||
|
pub fn from_ncurses(ch: i32) -> Self {
|
||||||
|
match ch {
|
||||||
|
10 => Key::Enter,
|
||||||
|
127 => Key::Backspace,
|
||||||
|
330 => Key::Del,
|
||||||
|
ncurses::KEY_LEFT => Key::ArrowLeft,
|
||||||
|
ncurses::KEY_RIGHT => Key::ArrowRight,
|
||||||
|
ncurses::KEY_UP => Key::ArrowUp,
|
||||||
|
ncurses::KEY_DOWN => Key::ArrowDown,
|
||||||
|
ncurses::KEY_PPAGE => Key::PageUp,
|
||||||
|
ncurses::KEY_NPAGE => Key::PageDown,
|
||||||
|
ncurses::KEY_HOME => Key::Home,
|
||||||
|
ncurses::KEY_END => Key::End,
|
||||||
|
_ => Key::Unknown(ch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Key {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Key::Unknown(ch) => write!(f, "Unknown: {}", ch),
|
||||||
|
key => write!(f, "{}", match key {
|
||||||
|
Key::ArrowLeft => "Left",
|
||||||
|
Key::ArrowRight => "Right",
|
||||||
|
Key::ArrowDown => "Down",
|
||||||
|
Key::ArrowUp => "Up",
|
||||||
|
Key::PageUp => "PageUp",
|
||||||
|
Key::PageDown => "PageDown",
|
||||||
|
Key::Home => "Home",
|
||||||
|
Key::End => "End",
|
||||||
|
Key::Backspace => "Backspace",
|
||||||
|
Key::Del => "Del",
|
||||||
|
_ => "",
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq,Eq,Clone,Copy,Hash)]
|
||||||
|
pub enum Event {
|
||||||
|
CharEvent(char),
|
||||||
|
KeyEvent(Key),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToEvent {
|
||||||
|
fn to_event(self) -> Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToEvent for char {
|
||||||
|
fn to_event(self) -> Event {
|
||||||
|
Event::CharEvent(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToEvent for Key {
|
||||||
|
fn to_event(self) -> Event {
|
||||||
|
Event::KeyEvent(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToEvent for Event {
|
||||||
|
fn to_event(self) -> Event {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
31
src/lib.rs
31
src/lib.rs
@ -40,7 +40,7 @@ use view::View;
|
|||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
use view::{StackView,Selector};
|
use view::{StackView,Selector};
|
||||||
|
|
||||||
use event::{EventResult,Callback};
|
use event::{Event,ToEvent,Key,EventResult,Callback};
|
||||||
|
|
||||||
/// Identifies a screen in the cursive ROOT.
|
/// Identifies a screen in the cursive ROOT.
|
||||||
pub type ScreenId = usize;
|
pub type ScreenId = usize;
|
||||||
@ -59,7 +59,7 @@ pub struct Cursive {
|
|||||||
|
|
||||||
running: bool,
|
running: bool,
|
||||||
|
|
||||||
global_callbacks: HashMap<i32, Rc<Callback>>,
|
global_callbacks: HashMap<Event, Rc<Callback>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cursive {
|
impl Cursive {
|
||||||
@ -145,10 +145,10 @@ impl Cursive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 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,E: ToEvent>(&mut self, event: E, cb: F)
|
||||||
where F: Fn(&mut Cursive) + 'static
|
where F: Fn(&mut Cursive) + 'static
|
||||||
{
|
{
|
||||||
self.global_callbacks.insert(key, Rc::new(Box::new(cb)));
|
self.global_callbacks.insert(event.to_event(), Rc::new(Box::new(cb)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenient method to add a layer to the current screen.
|
/// Convenient method to add a layer to the current screen.
|
||||||
@ -162,8 +162,8 @@ impl Cursive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handles a key event when it was ignored by the current view
|
// Handles a key event when it was ignored by the current view
|
||||||
fn on_key_event(&mut self, ch: i32) {
|
fn on_event(&mut self, event: Event) {
|
||||||
let cb = match self.global_callbacks.get(&ch) {
|
let cb = match self.global_callbacks.get(&event) {
|
||||||
None => return,
|
None => return,
|
||||||
Some(cb) => cb.clone(),
|
Some(cb) => cb.clone(),
|
||||||
};
|
};
|
||||||
@ -197,6 +197,17 @@ impl Cursive {
|
|||||||
ncurses::refresh();
|
ncurses::refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn poll_event() -> Event {
|
||||||
|
let ch = ncurses::getch();
|
||||||
|
|
||||||
|
// Is it a UTF-8 starting point?
|
||||||
|
if 32 <= ch && ch < 127 {
|
||||||
|
Event::CharEvent(ch as u8 as char)
|
||||||
|
} else {
|
||||||
|
Event::KeyEvent(Key::from_ncurses(ch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Runs the event loop.
|
/// Runs the event loop.
|
||||||
/// It will wait for user input (key presses) and trigger callbacks accordingly.
|
/// It will wait for user input (key presses) and trigger callbacks accordingly.
|
||||||
/// Blocks until quit() is called.
|
/// Blocks until quit() is called.
|
||||||
@ -216,11 +227,13 @@ impl Cursive {
|
|||||||
|
|
||||||
// Blocks until the user press a key.
|
// Blocks until the user press a key.
|
||||||
// TODO: Add a timeout? Animations?
|
// TODO: Add a timeout? Animations?
|
||||||
let ch = ncurses::getch();
|
let event = Cursive::poll_event();
|
||||||
|
|
||||||
|
// Make an event out of it.
|
||||||
|
|
||||||
// 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_event(event) {
|
||||||
EventResult::Ignored => self.on_key_event(ch),
|
EventResult::Ignored => self.on_event(event),
|
||||||
EventResult::Consumed(None) => (),
|
EventResult::Consumed(None) => (),
|
||||||
EventResult::Consumed(Some(cb)) => cb(self),
|
EventResult::Consumed(Some(cb)) => cb(self),
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use color;
|
|||||||
use ::Cursive;
|
use ::Cursive;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{View,SizeRequest};
|
use view::{View,SizeRequest};
|
||||||
use event::{Callback,EventResult};
|
use event::*;
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
|
|
||||||
/// Simple text label with a callback when ENTER is pressed.
|
/// Simple text label with a callback when ENTER is pressed.
|
||||||
@ -44,10 +44,10 @@ impl View for Button {
|
|||||||
Vec2::new(2 + self.label.len(), 1)
|
Vec2::new(2 + self.label.len(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
match ch {
|
match event {
|
||||||
// 10 is the ascii code for '\n', that is the return key
|
// 10 is the ascii code for '\n', that is the return key
|
||||||
10 => EventResult::Consumed(Some(self.callback.clone())),
|
Event::KeyEvent(Key::Enter) => EventResult::Consumed(Some(self.callback.clone())),
|
||||||
_ => EventResult::Ignored,
|
_ => EventResult::Ignored,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use ncurses;
|
|
||||||
|
|
||||||
use color;
|
use color;
|
||||||
use ::{Cursive};
|
use ::{Cursive};
|
||||||
use event::EventResult;
|
use event::*;
|
||||||
use view::{View,SizeRequest,DimensionRequest,Selector};
|
use view::{View,SizeRequest,DimensionRequest,Selector};
|
||||||
use view::{Button,SizedView};
|
use view::{Button,SizedView};
|
||||||
use vec::{Vec2,Vec4,ToVec4};
|
use vec::{Vec2,Vec4,ToVec4};
|
||||||
@ -165,12 +163,12 @@ impl View for Dialog {
|
|||||||
self.content.layout(size - Vec2::new(0, buttons_height));
|
self.content.layout(size - Vec2::new(0, buttons_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
match self.focus {
|
match self.focus {
|
||||||
// If we are on the content, we can only go down.
|
// If we are on the content, we can only go down.
|
||||||
Focus::Content => match self.content.on_key_event(ch) {
|
Focus::Content => match self.content.on_event(event) {
|
||||||
EventResult::Ignored if !self.buttons.is_empty() => match ch {
|
EventResult::Ignored if !self.buttons.is_empty() => match event {
|
||||||
ncurses::KEY_DOWN => {
|
Event::KeyEvent(Key::ArrowDown) => {
|
||||||
// Default to leftmost button when going down.
|
// Default to leftmost button when going down.
|
||||||
self.focus = Focus::Button(0);
|
self.focus = Focus::Button(0);
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
@ -180,10 +178,10 @@ impl View for Dialog {
|
|||||||
res => res,
|
res => res,
|
||||||
},
|
},
|
||||||
// If we are on a button, we have more choice
|
// If we are on a button, we have more choice
|
||||||
Focus::Button(i) => match self.buttons[i].on_key_event(ch) {
|
Focus::Button(i) => match self.buttons[i].on_event(event) {
|
||||||
EventResult::Ignored => match ch {
|
EventResult::Ignored => match event {
|
||||||
// Up goes back to the content
|
// Up goes back to the content
|
||||||
ncurses::KEY_UP => {
|
Event::KeyEvent(Key::ArrowUp) => {
|
||||||
if self.content.take_focus() {
|
if self.content.take_focus() {
|
||||||
self.focus = Focus::Content;
|
self.focus = Focus::Content;
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
@ -192,11 +190,11 @@ impl View for Dialog {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Left and Right move to other buttons
|
// Left and Right move to other buttons
|
||||||
ncurses::KEY_RIGHT if i+1 < self.buttons.len() => {
|
Event::KeyEvent(Key::ArrowRight) if i+1 < self.buttons.len() => {
|
||||||
self.focus = Focus::Button(i+1);
|
self.focus = Focus::Button(i+1);
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
},
|
},
|
||||||
ncurses::KEY_LEFT if i > 0 => {
|
Event::KeyEvent(Key::ArrowRight) if i > 0 => {
|
||||||
self.focus = Focus::Button(i-1);
|
self.focus = Focus::Button(i-1);
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,7 @@ use ncurses;
|
|||||||
use color;
|
use color;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{View,SizeRequest};
|
use view::{View,SizeRequest};
|
||||||
use event::EventResult;
|
use event::*;
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
|
|
||||||
/// Displays an editable text.
|
/// Displays an editable text.
|
||||||
@ -48,15 +48,6 @@ impl EditView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_char(ch: i32) -> Option<char> {
|
|
||||||
// Printable ascii range: 32-126
|
|
||||||
if ch >= ' ' as i32 && ch <= '~' as i32 {
|
|
||||||
Some(ch as u8 as char)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl View for EditView {
|
impl View for EditView {
|
||||||
fn draw(&mut self, printer: &Printer, focused: bool) {
|
fn draw(&mut self, printer: &Printer, focused: bool) {
|
||||||
// let style = if focused { color::HIGHLIGHT } else { color::HIGHLIGHT_INACTIVE };
|
// let style = if focused { color::HIGHLIGHT } else { color::HIGHLIGHT_INACTIVE };
|
||||||
@ -87,22 +78,24 @@ impl View for EditView {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
|
|
||||||
if let Some(ch) = read_char(ch) {
|
match event {
|
||||||
self.content.insert(self.cursor, ch);
|
Event::CharEvent(ch) => {
|
||||||
self.cursor += 1;
|
self.content.insert(self.cursor, ch);
|
||||||
return EventResult::Consumed(None);
|
self.cursor += 1;
|
||||||
}
|
return EventResult::Consumed(None);
|
||||||
|
},
|
||||||
|
Event::KeyEvent(key) => match key {
|
||||||
|
Key::Home => self.cursor = 0,
|
||||||
|
Key::End => self.cursor = self.content.len(),
|
||||||
|
Key::ArrowLeft if self.cursor > 0 => self.cursor -= 1,
|
||||||
|
Key::ArrowRight if self.cursor < self.content.len() => self.cursor += 1,
|
||||||
|
Key::Backspace if self.cursor > 0 => { self.cursor -= 1; self.content.remove(self.cursor); },
|
||||||
|
Key::Del if self.cursor < self.content.len() => { self.content.remove(self.cursor); },
|
||||||
|
_ => return EventResult::Ignored,
|
||||||
|
|
||||||
match ch {
|
},
|
||||||
ncurses::KEY_HOME => self.cursor = 0,
|
|
||||||
ncurses::KEY_END => self.cursor = self.content.len(),
|
|
||||||
ncurses::KEY_LEFT if self.cursor > 0 => self.cursor -= 1,
|
|
||||||
ncurses::KEY_RIGHT if self.cursor < self.content.len() => self.cursor += 1,
|
|
||||||
127 if self.cursor > 0 => { self.cursor -= 1; self.content.remove(self.cursor); },
|
|
||||||
330 if self.cursor < self.content.len() => { self.content.remove(self.cursor); },
|
|
||||||
_ => return EventResult::Ignored,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ::Cursive;
|
use ::Cursive;
|
||||||
use event::{EventResult,Callback};
|
use event::{Event,EventResult,ToEvent,Callback};
|
||||||
use super::{View,ViewWrapper};
|
use super::{View,ViewWrapper};
|
||||||
|
|
||||||
/// A simple wrapper view that catches some ignored event from its child.
|
/// A simple wrapper view that catches some ignored event from its child.
|
||||||
@ -10,7 +10,7 @@ use super::{View,ViewWrapper};
|
|||||||
/// Events ignored by its child without a callback will stay ignored.
|
/// Events ignored by its child without a callback will stay ignored.
|
||||||
pub struct KeyEventView {
|
pub struct KeyEventView {
|
||||||
content: Box<View>,
|
content: Box<View>,
|
||||||
callbacks: HashMap<i32, Rc<Callback>>,
|
callbacks: HashMap<Event, Rc<Callback>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyEventView {
|
impl KeyEventView {
|
||||||
@ -23,10 +23,10 @@ impl KeyEventView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Registers a callback when the given key is ignored by the child.
|
/// Registers a callback when the given key is ignored by the child.
|
||||||
pub fn register<F>(mut self, key: i32, cb: F) -> Self
|
pub fn register<F,E: ToEvent>(mut self, event: E, cb: F) -> Self
|
||||||
where F: Fn(&mut Cursive) + 'static
|
where F: Fn(&mut Cursive) + 'static
|
||||||
{
|
{
|
||||||
self.callbacks.insert(key, Rc::new(Box::new(cb)));
|
self.callbacks.insert(event.to_event(), Rc::new(Box::new(cb)));
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -36,9 +36,9 @@ impl ViewWrapper for KeyEventView {
|
|||||||
|
|
||||||
wrap_impl!(self.content);
|
wrap_impl!(self.content);
|
||||||
|
|
||||||
fn wrap_on_key_event(&mut self, ch: i32) -> EventResult {
|
fn wrap_on_event(&mut self, event: Event) -> EventResult {
|
||||||
match self.content.on_key_event(ch) {
|
match self.content.on_event(event) {
|
||||||
EventResult::Ignored => match self.callbacks.get(&ch) {
|
EventResult::Ignored => match self.callbacks.get(&event) {
|
||||||
None => EventResult::Ignored,
|
None => EventResult::Ignored,
|
||||||
Some(cb) => EventResult::Consumed(Some(cb.clone())),
|
Some(cb) => EventResult::Consumed(Some(cb.clone())),
|
||||||
},
|
},
|
||||||
|
@ -30,14 +30,14 @@ pub use self::id_view::IdView;
|
|||||||
pub use self::shadow_view::ShadowView;
|
pub use self::shadow_view::ShadowView;
|
||||||
pub use self::edit_view::EditView;
|
pub use self::edit_view::EditView;
|
||||||
|
|
||||||
use event::EventResult;
|
use event::{Event,EventResult};
|
||||||
use vec::{Vec2,ToVec2};
|
use vec::{Vec2,ToVec2};
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
|
|
||||||
/// Main trait defining a view behaviour.
|
/// Main trait defining a view behaviour.
|
||||||
pub trait View {
|
pub trait View {
|
||||||
/// Called when a key was pressed. Default implementation just ignores it.
|
/// Called when a key was pressed. Default implementation just ignores it.
|
||||||
fn on_key_event(&mut self, i32) -> EventResult { EventResult::Ignored }
|
fn on_event(&mut self, Event) -> EventResult { EventResult::Ignored }
|
||||||
|
|
||||||
/// Returns the minimum size the view requires under the given restrictions.
|
/// Returns the minimum size the view requires under the given restrictions.
|
||||||
fn get_min_size(&self, SizeRequest) -> Vec2 { Vec2::new(1,1) }
|
fn get_min_size(&self, SizeRequest) -> Vec2 { Vec2::new(1,1) }
|
||||||
|
@ -3,7 +3,7 @@ use std::any::Any;
|
|||||||
|
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{View,SizeRequest,DimensionRequest,Selector,ShadowView};
|
use view::{View,SizeRequest,DimensionRequest,Selector,ShadowView};
|
||||||
use event::EventResult;
|
use event::{Event,EventResult};
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
|
|
||||||
/// Simple stack of views.
|
/// Simple stack of views.
|
||||||
@ -50,10 +50,10 @@ impl View for StackView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
match self.layers.last_mut() {
|
match self.layers.last_mut() {
|
||||||
None => EventResult::Ignored,
|
None => EventResult::Ignored,
|
||||||
Some(v) => v.view.on_key_event(ch),
|
Some(v) => v.view.on_event(event),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
use std::cmp::{max,min};
|
use std::cmp::{max,min};
|
||||||
|
|
||||||
use ncurses;
|
|
||||||
|
|
||||||
use color;
|
use color;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{View,DimensionRequest,SizeRequest};
|
use view::{View,DimensionRequest,SizeRequest};
|
||||||
use div::*;
|
use div::*;
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
use event::EventResult;
|
use event::*;
|
||||||
|
|
||||||
/// A simple view showing a fixed text
|
/// A simple view showing a fixed text
|
||||||
pub struct TextView {
|
pub struct TextView {
|
||||||
@ -194,16 +192,16 @@ impl View for TextView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
if self.view_height >= self.rows.len() {
|
if self.view_height >= self.rows.len() {
|
||||||
return EventResult::Ignored;
|
return EventResult::Ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
match ch {
|
match event {
|
||||||
ncurses::KEY_UP if self.start_line > 0 => self.start_line -= 1,
|
Event::KeyEvent(Key::ArrowUp) if self.start_line > 0 => self.start_line -= 1,
|
||||||
ncurses::KEY_DOWN if self.start_line+self.view_height < self.rows.len() => self.start_line += 1,
|
Event::KeyEvent(Key::ArrowDown) if self.start_line+self.view_height < self.rows.len() => self.start_line += 1,
|
||||||
ncurses::KEY_NPAGE => self.start_line = min(self.start_line+10, self.rows.len()-self.view_height),
|
Event::KeyEvent(Key::PageUp) => self.start_line = min(self.start_line+10, self.rows.len()-self.view_height),
|
||||||
ncurses::KEY_PPAGE => self.start_line -= min(self.start_line, 10),
|
Event::KeyEvent(Key::PageDown) => self.start_line -= min(self.start_line, 10),
|
||||||
_ => return EventResult::Ignored,
|
_ => return EventResult::Ignored,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use std::any::Any;
|
|||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{View,SizeRequest,Selector};
|
use view::{View,SizeRequest,Selector};
|
||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
use event::EventResult;
|
use event::{Event,EventResult};
|
||||||
|
|
||||||
/// Generic wrapper around a view.
|
/// Generic wrapper around a view.
|
||||||
///
|
///
|
||||||
@ -25,9 +25,9 @@ pub trait ViewWrapper {
|
|||||||
self.get_view().get_min_size(req)
|
self.get_view().get_min_size(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps the on_key_event method.
|
/// Wraps the on_event method.
|
||||||
fn wrap_on_key_event(&mut self, ch: i32) -> EventResult {
|
fn wrap_on_event(&mut self, ch: Event) -> EventResult {
|
||||||
self.get_view_mut().on_key_event(ch)
|
self.get_view_mut().on_event(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps the layout method
|
/// Wraps the layout method
|
||||||
@ -54,8 +54,8 @@ impl <T: ViewWrapper> View for T {
|
|||||||
self.wrap_get_min_size(req)
|
self.wrap_get_min_size(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
fn on_event(&mut self, ch: Event) -> EventResult {
|
||||||
self.wrap_on_key_event(ch)
|
self.wrap_on_event(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&mut self, size: Vec2) {
|
fn layout(&mut self, size: Vec2) {
|
||||||
|
Loading…
Reference in New Issue
Block a user