mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-13 20:53:07 +00:00
Add focus system
May need to add a direction to take_focus
This commit is contained in:
parent
7cb0a7b6d4
commit
c8136c67e0
@ -171,7 +171,7 @@ impl Cursive {
|
|||||||
offset: Vec2::new(0,0),
|
offset: Vec2::new(0,0),
|
||||||
size: self.screen_size(),
|
size: self.screen_size(),
|
||||||
};
|
};
|
||||||
self.screen_mut().draw(&printer);
|
self.screen_mut().draw(&printer, true);
|
||||||
ncurses::wrefresh(ncurses::stdscr);
|
ncurses::wrefresh(ncurses::stdscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use event::EventResult;
|
|
||||||
use vec::{Vec2,ToVec2};
|
use vec::{Vec2,ToVec2};
|
||||||
use super::{View,SizeRequest};
|
use super::{View,ViewWrapper,SizeRequest};
|
||||||
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.
|
||||||
pub struct BoxView {
|
pub struct BoxView {
|
||||||
@ -27,20 +25,11 @@ impl BoxView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for BoxView {
|
impl ViewWrapper for BoxView {
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
|
||||||
self.content.on_key_event(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(&self, printer: &Printer) {
|
wrap_impl!(content);
|
||||||
self.content.draw(printer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_min_size(&self, _: SizeRequest) -> Vec2 {
|
fn wrap_get_min_size(&self, _: SizeRequest) -> Vec2 {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&mut self, size: Vec2) {
|
|
||||||
self.content.layout(size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ncurses;
|
|
||||||
|
|
||||||
use ::Cursive;
|
use ::Cursive;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{View,ViewPath,SizeRequest};
|
use view::{View,ViewPath,SizeRequest};
|
||||||
@ -9,12 +7,14 @@ use event::{Callback,EventResult};
|
|||||||
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.
|
||||||
|
/// A button shows its content in a single line and has a fixed size.
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
label: String,
|
label: String,
|
||||||
callback: Rc<Callback>,
|
callback: Rc<Callback>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Button {
|
impl Button {
|
||||||
|
/// Creates a new button with the given content and callback.
|
||||||
pub fn new<F>(label: &str, cb: F) -> Self
|
pub fn new<F>(label: &str, cb: F) -> Self
|
||||||
where F: Fn(&mut Cursive, &ViewPath) + 'static
|
where F: Fn(&mut Cursive, &ViewPath) + 'static
|
||||||
{
|
{
|
||||||
@ -27,13 +27,17 @@ impl Button {
|
|||||||
|
|
||||||
impl View for Button {
|
impl View for Button {
|
||||||
|
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer, focused: bool) {
|
||||||
printer.print((1u32,0u32), &self.label);
|
printer.print((1u32,0u32), &self.label);
|
||||||
printer.print((0u32,0u32), "<");
|
|
||||||
printer.print((printer.size.x-1,0), ">");
|
if focused {
|
||||||
|
printer.print((0u32,0u32), "<");
|
||||||
|
printer.print((printer.size.x-1,0), ">");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_min_size(&self, req: SizeRequest) -> Vec2 {
|
fn get_min_size(&self, _: SizeRequest) -> Vec2 {
|
||||||
|
// Meh. Fixed size we are.
|
||||||
Vec2::new(2 + self.label.len() as u32, 1)
|
Vec2::new(2 + self.label.len() as u32, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,4 +48,8 @@ impl View for Button {
|
|||||||
_ => EventResult::Ignored,
|
_ => EventResult::Ignored,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn take_focus(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ use printer::Printer;
|
|||||||
enum Focus {
|
enum Focus {
|
||||||
Content,
|
Content,
|
||||||
Button(usize),
|
Button(usize),
|
||||||
Nothing,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Dialog {
|
pub struct Dialog {
|
||||||
@ -48,26 +47,16 @@ impl Dialog {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset_request(request: DimensionRequest, offset: i32) -> DimensionRequest {
|
|
||||||
match request {
|
|
||||||
DimensionRequest::Fixed(w) => DimensionRequest::Fixed((w as i32 + offset) as u32),
|
|
||||||
DimensionRequest::AtMost(w) => DimensionRequest::AtMost((w as i32 + offset) as u32),
|
|
||||||
DimensionRequest::Unknown => DimensionRequest::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl View for Dialog {
|
impl View for Dialog {
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer, focused: bool) {
|
||||||
|
|
||||||
let mut height = 0;
|
let mut height = 0;
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
for (i,button) in self.buttons.iter().enumerate().rev() {
|
for (i,button) in self.buttons.iter().enumerate().rev() {
|
||||||
let size = button.size;
|
let size = button.size;
|
||||||
let offset = printer.size - self.borders.bot_right() - self.padding.bot_right() - size - Vec2::new(x, 0);
|
let offset = printer.size - self.borders.bot_right() - self.padding.bot_right() - size - Vec2::new(x, 0);
|
||||||
if self.focus == Focus::Button(i) {
|
// Add some special effect to the focused button
|
||||||
// Add some special effect to the focused button
|
button.draw(&printer.sub_printer(offset, size), focused && (self.focus == Focus::Button(i)));
|
||||||
}
|
|
||||||
button.draw(&printer.sub_printer(offset, size));
|
|
||||||
x += size.x + 1;
|
x += size.x + 1;
|
||||||
height = max(height, size.y+1);
|
height = max(height, size.y+1);
|
||||||
}
|
}
|
||||||
@ -77,7 +66,7 @@ impl View for Dialog {
|
|||||||
- self.borders.combined()
|
- self.borders.combined()
|
||||||
- self.padding.combined();
|
- self.padding.combined();
|
||||||
|
|
||||||
self.content.draw(&printer.sub_printer(self.borders.top_left() + self.padding.top_left(), inner_size));
|
self.content.draw(&printer.sub_printer(self.borders.top_left() + self.padding.top_left(), inner_size), focused && self.focus == Focus::Content);
|
||||||
|
|
||||||
printer.print(Vec2::new(0,0), "+");
|
printer.print(Vec2::new(0,0), "+");
|
||||||
printer.print(Vec2::new(printer.size.x-1, 0), "+");
|
printer.print(Vec2::new(printer.size.x-1, 0), "+");
|
||||||
@ -147,7 +136,16 @@ impl View for Dialog {
|
|||||||
},
|
},
|
||||||
res => res,
|
res => res,
|
||||||
},
|
},
|
||||||
Focus::Nothing => EventResult::Ignored,
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_focus(&mut self) -> bool {
|
||||||
|
if !self.buttons.is_empty() {
|
||||||
|
self.focus = Focus::Button(0);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.focus = Focus::Content;
|
||||||
|
self.content.take_focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,7 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use ::Cursive;
|
use ::Cursive;
|
||||||
use event::{EventResult,Callback};
|
use event::{EventResult,Callback};
|
||||||
use vec::{Vec2};
|
use super::{View,ViewPath,ViewWrapper};
|
||||||
use super::{View,SizeRequest,ViewPath};
|
|
||||||
use printer::Printer;
|
|
||||||
|
|
||||||
/// A simple wrapper view that catches some ignored event from its child.
|
/// A simple wrapper view that catches some ignored event from its child.
|
||||||
///
|
///
|
||||||
@ -34,26 +32,18 @@ impl KeyEventView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for KeyEventView {
|
impl ViewWrapper for KeyEventView {
|
||||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
|
||||||
|
wrap_impl!(content);
|
||||||
|
|
||||||
|
fn wrap_on_key_event(&mut self, ch: i32) -> EventResult {
|
||||||
match self.content.on_key_event(ch) {
|
match self.content.on_key_event(ch) {
|
||||||
EventResult::Ignored => match self.callbacks.get(&ch) {
|
EventResult::Ignored => match self.callbacks.get(&ch) {
|
||||||
None => EventResult::Ignored,
|
None => EventResult::Ignored,
|
||||||
Some(cb) => EventResult::Consumed(Some(cb.clone()), ViewPath::new()),
|
Some(cb) => EventResult::Consumed(Some(cb.clone()), ViewPath::new()),
|
||||||
},
|
},
|
||||||
EventResult::Consumed(cb, path) => EventResult::Consumed(cb, path),
|
res => res,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,5 +1,6 @@
|
|||||||
//! Defines various views to use when creating the layout.
|
//! Defines various views to use when creating the layout.
|
||||||
|
|
||||||
|
#[macro_use] mod view_wrapper;
|
||||||
mod box_view;
|
mod box_view;
|
||||||
mod stack_view;
|
mod stack_view;
|
||||||
mod text_view;
|
mod text_view;
|
||||||
@ -8,7 +9,6 @@ mod view_path;
|
|||||||
mod dialog;
|
mod dialog;
|
||||||
mod button;
|
mod button;
|
||||||
mod sized_view;
|
mod sized_view;
|
||||||
mod view_wrapper;
|
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
@ -85,11 +85,14 @@ pub trait View {
|
|||||||
/// propagate the information to its children.
|
/// propagate the information to its children.
|
||||||
fn layout(&mut self, Vec2) { }
|
fn layout(&mut self, Vec2) { }
|
||||||
|
|
||||||
/// Draws the view within the given bounds.
|
/// Draws the view with the given printer (includes bounds) and focus.
|
||||||
fn draw(&self, &Printer);
|
fn draw(&self, printer: &Printer, focused: bool);
|
||||||
|
|
||||||
/// Finds the view pointed to by the given path.
|
/// Finds the view pointed to by the given path.
|
||||||
/// Returns None if the path doesn't lead to a view.
|
/// Returns None if the path doesn't lead to a view.
|
||||||
fn find(&mut self, &ViewPath) -> Option<&mut Any> { None }
|
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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,14 +40,14 @@ impl StackView {
|
|||||||
|
|
||||||
|
|
||||||
impl View for StackView {
|
impl View for StackView {
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer, focused: bool) {
|
||||||
match self.layers.last() {
|
match self.layers.last() {
|
||||||
None => (),
|
None => (),
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
// Center the view
|
// Center the view
|
||||||
let view_size = Vec2::min(printer.size, v.size);
|
let view_size = Vec2::min(printer.size, v.size);
|
||||||
let offset = (printer.size - view_size) / 2;
|
let offset = (printer.size - view_size) / 2;
|
||||||
v.view.draw(&printer.sub_printer(offset, v.size));
|
v.view.draw(&printer.sub_printer(offset, v.size), focused);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,4 +82,11 @@ impl View for StackView {
|
|||||||
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn take_focus(&mut self) -> bool {
|
||||||
|
match self.layers.last_mut() {
|
||||||
|
None => false,
|
||||||
|
Some(mut v) => v.view.take_focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,9 @@ impl <'a> Iterator for LinesIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl View for TextView {
|
impl View for TextView {
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer, _: bool) {
|
||||||
|
// We don't have a focused view
|
||||||
|
|
||||||
let lines = self.content.split("\n")
|
let lines = self.content.split("\n")
|
||||||
.flat_map(|line| LinesIterator::new(line, printer.size.x as usize));
|
.flat_map(|line| LinesIterator::new(line, printer.size.x as usize));
|
||||||
for (i, line) in lines.enumerate() {
|
for (i, line) in lines.enumerate() {
|
||||||
|
@ -7,8 +7,8 @@ pub trait ViewWrapper {
|
|||||||
fn get_view(&self) -> &View;
|
fn get_view(&self) -> &View;
|
||||||
fn get_view_mut(&mut self) -> &mut View;
|
fn get_view_mut(&mut self) -> &mut View;
|
||||||
|
|
||||||
fn wrap_draw(&self, printer: &Printer) {
|
fn wrap_draw(&self, printer: &Printer, focused: bool) {
|
||||||
self.get_view().draw(printer);
|
self.get_view().draw(printer, focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 {
|
fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 {
|
||||||
@ -25,8 +25,8 @@ pub trait ViewWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl <T: ViewWrapper> View for T {
|
impl <T: ViewWrapper> View for T {
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer, focused: bool) {
|
||||||
self.wrap_draw(printer);
|
self.wrap_draw(printer, focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_min_size(&self, req: SizeRequest) -> Vec2 {
|
fn get_min_size(&self, req: SizeRequest) -> Vec2 {
|
||||||
@ -41,3 +41,17 @@ impl <T: ViewWrapper> View for T {
|
|||||||
self.wrap_layout(size);
|
self.wrap_layout(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! wrap_impl {
|
||||||
|
($v:ident) => {
|
||||||
|
|
||||||
|
fn get_view(&self) -> &View {
|
||||||
|
&*self.$v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_view_mut(&mut self) -> &mut View {
|
||||||
|
&mut *self.$v
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user