From df4397a174e8a3cc78bd2f4793a8f3918bdfaaa5 Mon Sep 17 00:00:00 2001 From: Alexandre Bury Date: Sat, 8 Oct 2016 16:47:15 -0700 Subject: [PATCH] Add stub termion backend Not supported: input, colors, effects, async --- Cargo.toml | 9 +++-- src/backend/curses.rs | 2 +- src/backend/mod.rs | 6 ++- src/backend/termion.rs | 85 ++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 ++-- src/printer.rs | 3 ++ src/views/shadow_view.rs | 5 ++- 7 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 src/backend/termion.rs diff --git a/Cargo.toml b/Cargo.toml index 6b06b09..3cd2d73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [package] authors = ["Alexandre Bury "] +build = "build.rs" description = "A TUI (Text User Interface) library focused on ease-of-use." documentation = "https://gyscos.github.io/Cursive/cursive/index.html" exclude = ["doc", "assets"] @@ -9,10 +10,13 @@ name = "cursive" readme = "Readme.md" repository = "https://github.com/gyscos/Cursive" version = "0.3.1" -build="build.rs" + +[build-dependencies] +skeptic = "0.6" [dependencies] odds = "0.2" +termion = "1.1.1" toml = "0.2" unicode-segmentation = "0.1" unicode-width = "0.1" @@ -25,8 +29,5 @@ version = "5.82.0" rand = "0.3" skeptic = "0.6" -[build-dependencies] -skeptic = "0.6" - [lib] name = "cursive" diff --git a/src/backend/curses.rs b/src/backend/curses.rs index 8cb2303..b240364 100644 --- a/src/backend/curses.rs +++ b/src/backend/curses.rs @@ -74,7 +74,7 @@ impl backend::Backend for NcursesBackend { ncurses::clear(); } - fn refresh(&self) { + fn refresh(&mut self) { ncurses::refresh(); } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 63a0f0f..10a892e 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -3,15 +3,18 @@ use theme; // Module is not named `ncurses` to avoir naming conflict mod curses; +mod termion; pub use self::curses::NcursesBackend; +pub use self::termion::TermionBackend; pub trait Backend { fn init() -> Self; + // TODO: take `self` by value? fn finish(&mut self); fn clear(&self); - fn refresh(&self); + fn refresh(&mut self); fn has_colors(&self) -> bool; @@ -24,6 +27,7 @@ pub trait Backend { fn set_refresh_rate(&mut self, fps: u32); fn screen_size(&self) -> (usize, usize); + // TODO: unify those into a single method? fn with_color(&self, color: theme::ColorStyle, f: F); fn with_effect(&self, effect: theme::Effect, f: F); } diff --git a/src/backend/termion.rs b/src/backend/termion.rs new file mode 100644 index 0000000..82dc8f9 --- /dev/null +++ b/src/backend/termion.rs @@ -0,0 +1,85 @@ + + +use ::backend; +use ::event::{Event, Key}; +use std::io::Write; +use termion; +use termion::input::TermRead; +use termion::raw::IntoRawMode; +use ::theme::{BaseColor, Color, ColorStyle, Effect}; + +pub struct TermionBackend { + terminal: termion::raw::RawTerminal<::std::io::Stdout>, +} + +impl backend::Backend for TermionBackend { + fn init() -> Self { + print!("{}", termion::cursor::Hide); + Self::clear(); + + + TermionBackend { + terminal: ::std::io::stdout().into_raw_mode().unwrap(), + } + } + + fn finish(&mut self) { + // Maybe we should clear everything? + print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1)); + Self::clear(); + } + + fn init_color_style(&mut self, style: ColorStyle, foreground: &Color, + background: &Color) { + // Do we _need_ to save the color? + } + + fn with_color(&self, color: ColorStyle, f: F) { + // TODO: actually use colors + // TODO: careful! need to remember the previous state + // and apply it back + f(); + } + + fn with_effect(&self, effect: Effect, f: F) { + // TODO: actually use effects + // TODO: careful! need to remember the previous state + // and apply it back + f(); + } + + fn has_colors(&self) -> bool { + // TODO: color support detection? + true + } + + fn screen_size(&self) -> (usize, usize) { + let (x, y) = termion::terminal_size().unwrap_or((1, 1)); + (x as usize, y as usize) + } + + fn clear() { + print!("{}", termion::clear::All); + } + + fn refresh(&mut self) { + // Not sure termion needs a refresh phase + self.terminal.flush().unwrap(); + } + + fn print_at(&self, (x, y): (usize, usize), text: &str) { + // TODO: terminals are 1-based. Should we add 1 here? + print!("{}{}", termion::cursor::Goto(x as u16, y as u16), text); + } + + fn set_refresh_rate(&mut self, fps: u32) { + // TODO: handle async refresh, when no input is entered. + // Could be done with a timeout on the event polling, + // if it was supportedd. + } + + fn poll_event(&self) -> Event { + ::std::io::stdin().keys().next(); + Event::Key(Key::Enter) + } +} diff --git a/src/lib.rs b/src/lib.rs index 577c559..398396b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,7 @@ extern crate toml; extern crate unicode_segmentation; extern crate unicode_width; extern crate odds; +extern crate termion; macro_rules! println_stderr( ($($arg:tt)*) => { { @@ -105,7 +106,7 @@ mod utf8; mod backend; -use backend::{Backend, NcursesBackend}; +use backend::{Backend}; use event::{Callback, Event, EventResult}; @@ -155,7 +156,7 @@ new_default!(Cursive); // Use the Ncurses backend. // TODO: make this feature-driven #[doc(hidden)] -pub type B = NcursesBackend; +pub type B = backend::TermionBackend; impl Cursive { /// Creates a new Cursive root, and initialize ncurses. @@ -493,7 +494,6 @@ impl Cursive { let id = self.active_screen; self.screens.get_mut(id).unwrap().draw(&printer); - self.backend.refresh(); } /// Runs the event loop. @@ -518,6 +518,7 @@ impl Cursive { // TODO: Do we need to redraw every view every time? // (Is this getting repetitive? :p) self.draw(); + self.backend.refresh(); // Wait for next event. // (If set_fps was called, this returns -1 now and then) diff --git a/src/printer.rs b/src/printer.rs index ff71627..ad54d8f 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -104,8 +104,11 @@ impl<'a> Printer<'a> { return; } let len = min(len, self.size.x - p.x); + let text: String = ::std::iter::repeat(c).take(len).collect(); let p = p + self.offset; + // self.backend.print_at((p.x, p.y), &text); + self.print(p, &text); for x in 0..len { self.backend.print_at((p.x + x, p.y), c); } diff --git a/src/views/shadow_view.rs b/src/views/shadow_view.rs index 4c947b7..15a70d6 100644 --- a/src/views/shadow_view.rs +++ b/src/views/shadow_view.rs @@ -60,7 +60,8 @@ impl ViewWrapper for ShadowView { fn wrap_draw(&self, printer: &Printer) { - if printer.size.y == 0 || printer.size.x == 0 { + if printer.size.y <= self.top_padding as usize || + printer.size.x <= self.left_padding as usize { // Nothing to do if there's no place to draw. return; } @@ -79,7 +80,7 @@ impl ViewWrapper for ShadowView { printer.size - (1, 1), true)); - if printer.theme.shadow { + if printer.theme.shadow && false { let h = printer.size.y; let w = printer.size.x;