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),
|
||||
size: self.screen_size(),
|
||||
};
|
||||
self.screen_mut().draw(&printer);
|
||||
self.screen_mut().draw(&printer, true);
|
||||
ncurses::wrefresh(ncurses::stdscr);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
use event::EventResult;
|
||||
use vec::{Vec2,ToVec2};
|
||||
use super::{View,SizeRequest};
|
||||
use printer::Printer;
|
||||
use super::{View,ViewWrapper,SizeRequest};
|
||||
|
||||
/// BoxView is a wrapper around an other view, with a given minimum size.
|
||||
pub struct BoxView {
|
||||
@ -27,20 +25,11 @@ impl BoxView {
|
||||
}
|
||||
}
|
||||
|
||||
impl View for BoxView {
|
||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
||||
self.content.on_key_event(ch)
|
||||
}
|
||||
impl ViewWrapper for BoxView {
|
||||
|
||||
fn draw(&self, printer: &Printer) {
|
||||
self.content.draw(printer)
|
||||
}
|
||||
wrap_impl!(content);
|
||||
|
||||
fn get_min_size(&self, _: SizeRequest) -> Vec2 {
|
||||
fn wrap_get_min_size(&self, _: SizeRequest) -> Vec2 {
|
||||
self.size
|
||||
}
|
||||
|
||||
fn layout(&mut self, size: Vec2) {
|
||||
self.content.layout(size);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use ncurses;
|
||||
|
||||
use ::Cursive;
|
||||
use vec::Vec2;
|
||||
use view::{View,ViewPath,SizeRequest};
|
||||
@ -9,12 +7,14 @@ use event::{Callback,EventResult};
|
||||
use printer::Printer;
|
||||
|
||||
/// 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 {
|
||||
label: String,
|
||||
callback: Rc<Callback>,
|
||||
}
|
||||
|
||||
impl Button {
|
||||
/// Creates a new button with the given content and callback.
|
||||
pub fn new<F>(label: &str, cb: F) -> Self
|
||||
where F: Fn(&mut Cursive, &ViewPath) + 'static
|
||||
{
|
||||
@ -27,13 +27,17 @@ impl Button {
|
||||
|
||||
impl View for Button {
|
||||
|
||||
fn draw(&self, printer: &Printer) {
|
||||
fn draw(&self, printer: &Printer, focused: bool) {
|
||||
printer.print((1u32,0u32), &self.label);
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -44,4 +48,8 @@ impl View for Button {
|
||||
_ => EventResult::Ignored,
|
||||
}
|
||||
}
|
||||
|
||||
fn take_focus(&mut self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ use printer::Printer;
|
||||
enum Focus {
|
||||
Content,
|
||||
Button(usize),
|
||||
Nothing,
|
||||
}
|
||||
|
||||
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 {
|
||||
fn draw(&self, printer: &Printer) {
|
||||
fn draw(&self, printer: &Printer, focused: bool) {
|
||||
|
||||
let mut height = 0;
|
||||
let mut x = 0;
|
||||
for (i,button) in self.buttons.iter().enumerate().rev() {
|
||||
let size = button.size;
|
||||
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
|
||||
}
|
||||
button.draw(&printer.sub_printer(offset, size));
|
||||
button.draw(&printer.sub_printer(offset, size), focused && (self.focus == Focus::Button(i)));
|
||||
x += size.x + 1;
|
||||
height = max(height, size.y+1);
|
||||
}
|
||||
@ -77,7 +66,7 @@ impl View for Dialog {
|
||||
- self.borders.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(printer.size.x-1, 0), "+");
|
||||
@ -147,7 +136,16 @@ impl View for Dialog {
|
||||
},
|
||||
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 event::{EventResult,Callback};
|
||||
use vec::{Vec2};
|
||||
use super::{View,SizeRequest,ViewPath};
|
||||
use printer::Printer;
|
||||
use super::{View,ViewPath,ViewWrapper};
|
||||
|
||||
/// A simple wrapper view that catches some ignored event from its child.
|
||||
///
|
||||
@ -34,26 +32,18 @@ impl KeyEventView {
|
||||
}
|
||||
}
|
||||
|
||||
impl View for KeyEventView {
|
||||
fn on_key_event(&mut self, ch: i32) -> EventResult {
|
||||
impl ViewWrapper for KeyEventView {
|
||||
|
||||
wrap_impl!(content);
|
||||
|
||||
fn wrap_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),
|
||||
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.
|
||||
|
||||
#[macro_use] mod view_wrapper;
|
||||
mod box_view;
|
||||
mod stack_view;
|
||||
mod text_view;
|
||||
@ -8,7 +9,6 @@ mod view_path;
|
||||
mod dialog;
|
||||
mod button;
|
||||
mod sized_view;
|
||||
mod view_wrapper;
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
@ -85,11 +85,14 @@ pub trait View {
|
||||
/// propagate the information to its children.
|
||||
fn layout(&mut self, Vec2) { }
|
||||
|
||||
/// Draws the view within the given bounds.
|
||||
fn draw(&self, &Printer);
|
||||
/// Draws the view with the given printer (includes bounds) and focus.
|
||||
fn draw(&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 }
|
||||
}
|
||||
|
||||
|
@ -40,14 +40,14 @@ impl StackView {
|
||||
|
||||
|
||||
impl View for StackView {
|
||||
fn draw(&self, printer: &Printer) {
|
||||
fn draw(&self, printer: &Printer, focused: bool) {
|
||||
match self.layers.last() {
|
||||
None => (),
|
||||
Some(v) => {
|
||||
// Center the view
|
||||
let view_size = Vec2::min(printer.size, v.size);
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
fn draw(&self, printer: &Printer) {
|
||||
fn draw(&self, printer: &Printer, _: bool) {
|
||||
// We don't have a focused view
|
||||
|
||||
let lines = self.content.split("\n")
|
||||
.flat_map(|line| LinesIterator::new(line, printer.size.x as usize));
|
||||
for (i, line) in lines.enumerate() {
|
||||
|
@ -7,8 +7,8 @@ pub trait ViewWrapper {
|
||||
fn get_view(&self) -> &View;
|
||||
fn get_view_mut(&mut self) -> &mut View;
|
||||
|
||||
fn wrap_draw(&self, printer: &Printer) {
|
||||
self.get_view().draw(printer);
|
||||
fn wrap_draw(&self, printer: &Printer, focused: bool) {
|
||||
self.get_view().draw(printer, focused);
|
||||
}
|
||||
|
||||
fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 {
|
||||
@ -25,8 +25,8 @@ pub trait ViewWrapper {
|
||||
}
|
||||
|
||||
impl <T: ViewWrapper> View for T {
|
||||
fn draw(&self, printer: &Printer) {
|
||||
self.wrap_draw(printer);
|
||||
fn draw(&self, printer: &Printer, focused: bool) {
|
||||
self.wrap_draw(printer, focused);
|
||||
}
|
||||
|
||||
fn get_min_size(&self, req: SizeRequest) -> Vec2 {
|
||||
@ -41,3 +41,17 @@ impl <T: ViewWrapper> View for T {
|
||||
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