From 7e823435cd40c623cd67666b79fca784e0791fc8 Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Sat, 23 May 2015 15:58:06 -0700 Subject: [PATCH] Stop using ncurses::WINDOW Overlap is a mess. Let's do it ourselve. --- examples/mutation.rs | 7 +++-- src/lib.rs | 2 +- src/printer.rs | 57 +++++++++-------------------------------- src/view/button.rs | 9 ++++--- src/view/dialog.rs | 2 +- src/view/mod.rs | 2 ++ src/view/shadow_view.rs | 53 ++++++++++++++++++++++++++++++++++++++ src/view/stack_view.rs | 31 ++++------------------ 8 files changed, 84 insertions(+), 79 deletions(-) create mode 100644 src/view/shadow_view.rs diff --git a/examples/mutation.rs b/examples/mutation.rs index ee76414..e944cc0 100644 --- a/examples/mutation.rs +++ b/examples/mutation.rs @@ -6,11 +6,14 @@ 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_global_callback('q' as i32, |s,_| s.quit()); + + siv.add_layer(IdView::new("text", TextView::new("Aaahh\nAaaah\nAaaah\nAaaaah\nAaaaah\nAaaaah\nAaaaah\nAaaaaah\nAaaaah"))); siv.add_layer(Dialog::new(TextView::new("Tak!")) .button("Change", |s,_| s.find::(&Selector::Id("text")).unwrap() - .set_content("Bleeeeh") )); + .set_content("Bleeeeh\nBleeeeeeeeeeh\nBleeeh") ) + .dismiss_button("Ok")); siv.run(); } diff --git a/src/lib.rs b/src/lib.rs index 6478569..5706a5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -188,11 +188,11 @@ impl Cursive { fn draw(&mut self) { let printer = Printer { - win: ncurses::stdscr, offset: Vec2::new(0,0), size: self.screen_size(), }; self.screen_mut().draw(&printer, true); + ncurses::refresh(); } /// Runs the event loop. diff --git a/src/printer.rs b/src/printer.rs index eb8580e..6811f6f 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -5,50 +5,18 @@ use ncurses; use color; use vec::{Vec2,ToVec2}; -/// Wrapper around a subset of a ncurses window. +/// Convenient interface to draw on a subset of the screen. pub struct Printer { - /// ncurses window this printer will use. You can use it directly if you want. - pub win: ncurses::WINDOW, /// Offset into the window this printer should start drawing at. pub offset: Vec2, /// Size of the area we are allowed to draw on. pub size: Vec2, } -/// Wrapper around a parent printer that applies a style to prints. -pub struct StyledPrinter<'a> { - parent: &'a Printer, - style: color::ThemeColor, -} - -impl <'a> StyledPrinter<'a> { - /// Wrapper around the parent's `print` method with `self.style` applied. - pub fn print(&self, pos: S, text: &str) { - ncurses::wattron(self.parent.win, ncurses::COLOR_PAIR(self.style) as i32); - self.parent.print(pos, text); - ncurses::wattroff(self.parent.win, ncurses::COLOR_PAIR(self.style) as i32); - } - - /// Wrapper around the parent's `print_vline` method with `self.style` applied. - pub fn print_vline(&self, start: T, len: u32, c: u64) { - ncurses::wattron(self.parent.win, ncurses::COLOR_PAIR(self.style) as i32); - self.parent.print_vline(start, len, c); - ncurses::wattroff(self.parent.win, ncurses::COLOR_PAIR(self.style) as i32); - } - - /// Wrapper around the parent's `print_hline` method with `self.style` applied. - pub fn print_hline(&self, start: T, len: u32, c: u64) { - ncurses::wattron(self.parent.win, ncurses::COLOR_PAIR(self.style) as i32); - self.parent.print_hline(start, len, c); - ncurses::wattroff(self.parent.win, ncurses::COLOR_PAIR(self.style) as i32); - } -} - impl Printer { /// Creates a new printer on the given window. - pub fn new(win: ncurses::WINDOW, size: T) -> Self { + pub fn new(size: T) -> Self { Printer { - win: win, offset: Vec2::zero(), size: size.to_vec2(), } @@ -57,28 +25,30 @@ impl Printer { /// Prints some text at the given position relative to the window. pub fn print(&self, pos: S, text: &str) { let p = pos.to_vec2() + self.offset; - ncurses::mvwprintw(self.win, p.y as i32, p.x as i32, text); + ncurses::mvprintw(p.y as i32, p.x as i32, text); } /// Prints a vertical line using the given character. pub fn print_vline(&self, start: T, len: u32, c: u64) { let p = start.to_vec2() + self.offset; - ncurses::mvwvline(self.win, p.y as i32, p.x as i32, c, len as i32); + ncurses::mvvline(p.y as i32, p.x as i32, c, len as i32); } /// Prints a horizontal line using the given character. pub fn print_hline(&self, start: T, len: u32, c: u64) { let p = start.to_vec2() + self.offset; - ncurses::mvwhline(self.win, p.y as i32, p.x as i32, c, len as i32); + ncurses::mvhline(p.y as i32, p.x as i32, c, len as i32); } /// Returns a wrapper around this printer, /// that will apply the given style on prints. - pub fn style<'a>(&'a self, style: color::ThemeColor) -> StyledPrinter<'a> { - StyledPrinter { - parent: self, - style: style, - } + pub fn with_style<'a, F>(&'a self, style: color::ThemeColor, f: F) + where F: Fn(&Printer) + { + ncurses::attron(ncurses::COLOR_PAIR(style)); + f(self); + ncurses::attroff(ncurses::COLOR_PAIR(style)); + ncurses::attron(ncurses::COLOR_PAIR(color::PRIMARY)); } /// Prints a rectangular box. @@ -92,8 +62,6 @@ impl Printer { let start_v = start.to_vec2(); let size_v = size.to_vec2() - (1,1); - - self.print(start_v, "┌"); self.print(start_v + size_v.keep_x(), "┐"); self.print(start_v + size_v.keep_y(), "└"); @@ -109,7 +77,6 @@ impl Printer { pub fn sub_printer(&self, offset: S, size: S) -> Printer { let offset_v = offset.to_vec2(); Printer { - win: self.win, offset: self.offset + offset_v, // We can't be larger than what remains size: Vec2::min(self.size - offset_v, size.to_vec2()), diff --git a/src/view/button.rs b/src/view/button.rs index 5f84722..ed3df73 100644 --- a/src/view/button.rs +++ b/src/view/button.rs @@ -32,10 +32,11 @@ impl View for Button { let style = if !focused { color::PRIMARY } else { color::HIGHLIGHT }; let x = printer.size.x - 1; - let printer = printer.style(style); - printer.print((1u32,0u32), &self.label); - printer.print((0u32,0u32), "<"); - printer.print((x,0), ">"); + printer.with_style(style, |printer| { + printer.print((1u32,0u32), &self.label); + printer.print((0u32,0u32), "<"); + printer.print((x,0), ">"); + }); } fn get_min_size(&self, _: SizeRequest) -> Vec2 { diff --git a/src/view/dialog.rs b/src/view/dialog.rs index a4a4413..e4254b1 100644 --- a/src/view/dialog.rs +++ b/src/view/dialog.rs @@ -106,7 +106,7 @@ impl View for Dialog { printer.print((x-2,0), "┤ "); printer.print((x+self.title.len() as u32,0), " ├"); - printer.style(color::TITLE_PRIMARY).print((x,0), &self.title); + printer.with_style(color::TITLE_PRIMARY, |p| p.print((x,0), &self.title)); } } diff --git a/src/view/mod.rs b/src/view/mod.rs index cf52b65..db938a4 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -11,6 +11,7 @@ mod button; mod sized_view; mod full_view; mod id_view; +mod shadow_view; use std::any::Any; @@ -25,6 +26,7 @@ pub use self::sized_view::SizedView; pub use self::view_wrapper::ViewWrapper; pub use self::full_view::FullView; pub use self::id_view::IdView; +pub use self::shadow_view::ShadowView; use event::EventResult; use vec::{Vec2,ToVec2}; diff --git a/src/view/shadow_view.rs b/src/view/shadow_view.rs new file mode 100644 index 0000000..ca0fb82 --- /dev/null +++ b/src/view/shadow_view.rs @@ -0,0 +1,53 @@ +use view::{View,ViewWrapper,SizeRequest}; +use printer::Printer; +use vec::Vec2; +use color; + +pub struct ShadowView { + pub view: T, +} + +impl ShadowView { + pub fn new(view: T) -> Self { + ShadowView { + view: view, + } + } +} + +impl ViewWrapper for ShadowView { + + wrap_impl!(&self.view); + + fn wrap_get_min_size(&self, req: SizeRequest) -> Vec2 { + self.view.get_min_size(req.reduced((2,2))) + (2,2) + } + + fn wrap_layout(&mut self, size: Vec2) { + self.view.layout(size - (2,2)); + } + + fn wrap_draw(&mut self, printer: &Printer, focused: bool) { + + { + printer.with_style(color::PRIMARY, |printer| { + // Draw the view background + for y in 1..printer.size.y-1 { + printer.print_hline((1,y), printer.size.x-2, ' ' as u64); + } + }); + } + + + self.view.draw(&printer.sub_printer(Vec2::new(1,1), printer.size - (2,2)), focused); + + + let h = printer.size.y-1; + let w = printer.size.x-1; + + printer.with_style(color::SHADOW, |printer| { + printer.print_hline((2,h), w-1, ' ' as u64); + printer.print_vline((w,2), h-1, ' ' as u64); + }); + } +} diff --git a/src/view/stack_view.rs b/src/view/stack_view.rs index e19c450..fffd5f2 100644 --- a/src/view/stack_view.rs +++ b/src/view/stack_view.rs @@ -1,11 +1,9 @@ use std::cmp::max; use std::any::Any; -use ncurses; - use color; use vec::Vec2; -use view::{View,SizeRequest,DimensionRequest,Selector}; +use view::{View,SizeRequest,DimensionRequest,Selector,ShadowView}; use event::EventResult; use printer::Printer; @@ -18,7 +16,6 @@ pub struct StackView { struct Layer { view: Box, size: Vec2, - win: Option, } impl StackView { @@ -32,9 +29,8 @@ impl StackView { /// Add new view on top of the stack. pub fn add_layer(&mut self, view: T) { self.layers.push(Layer { - view: Box::new(view), + view: Box::new(ShadowView::new(view)), size: Vec2::new(0,0), - win: None, }); } @@ -44,26 +40,17 @@ impl StackView { } } - impl View for StackView { fn draw(&mut self, printer: &Printer, focused: bool) { - ncurses::wrefresh(printer.win); for v in self.layers.iter_mut() { // Center the view - v.view.draw(&Printer::new(v.win.unwrap(), v.size), focused); - - let h = v.size.y; - let w = v.size.x; - let x = (printer.size.x - w) / 2; - let y = (printer.size.y - h) / 2; + let size = v.size; + let offset = (printer.size - size) / 2; + v.view.draw(&printer.sub_printer(offset, size), focused); - 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); // v.view.draw(&printer.sub_printer(offset, v.size), focused); - ncurses::wrefresh(v.win.unwrap()); } } @@ -87,14 +74,6 @@ impl View for StackView { let w = layer.size.x as i32; let x = (size.x as i32 - w) / 2; let y = (size.y as i32 - h) / 2; - let win = ncurses::newwin(h, w, y, x); - ncurses::wbkgd(win, ncurses::COLOR_PAIR(color::PRIMARY)); - - match layer.win { - None => (), - Some(w) => { ncurses::delwin(w); }, - } - layer.win = Some(win); } }