Actually use Theme::{shadow,borders} when drawing

Also add the 8 light base colors
This commit is contained in:
Alexandre Bury 2016-08-04 17:27:04 -07:00
parent db09930fe2
commit f7a3d821d1
9 changed files with 131 additions and 63 deletions

25
examples/theme_manual.rs Normal file
View File

@ -0,0 +1,25 @@
extern crate cursive;
use cursive::prelude::*;
use cursive::theme::BorderStyle;
fn main() {
let mut siv = Cursive::new();
siv.add_layer(Dialog::text("This is a dynamic theme example!")
.button("Change", |s| {
let mut theme = s.current_theme().clone();
theme.shadow = !theme.shadow;
theme.borders = match theme.borders {
Some(BorderStyle::Simple) => Some(BorderStyle::Outset),
Some(BorderStyle::Outset) => None,
None => Some(BorderStyle::Simple),
};
s.set_theme(theme);
})
.button("Quit", Cursive::quit));
siv.run();
}

View File

@ -1,6 +1,6 @@
use backend;
use event::{Event, Key};
use theme::{Color, ColorStyle, Effect};
use theme::{Color, ColorStyle, Effect, BaseColor};
use utf8;
use ncurses;
@ -225,14 +225,22 @@ fn parse_ncurses_char(ch: i32) -> Event {
fn find_closest(color: &Color) -> u8 {
match *color {
Color::Black => 0,
Color::Red => 1,
Color::Green => 2,
Color::Yellow => 3,
Color::Blue => 4,
Color::Magenta => 5,
Color::Cyan => 6,
Color::White => 7,
Color::Dark(BaseColor::Black) => 0,
Color::Dark(BaseColor::Red) => 1,
Color::Dark(BaseColor::Green) => 2,
Color::Dark(BaseColor::Yellow) => 3,
Color::Dark(BaseColor::Blue) => 4,
Color::Dark(BaseColor::Magenta) => 5,
Color::Dark(BaseColor::Cyan) => 6,
Color::Dark(BaseColor::White) => 7,
Color::Light(BaseColor::Black) => 8,
Color::Light(BaseColor::Red) => 9,
Color::Light(BaseColor::Green) => 10,
Color::Light(BaseColor::Yellow) => 11,
Color::Light(BaseColor::Blue) => 12,
Color::Light(BaseColor::Magenta) => 13,
Color::Light(BaseColor::Cyan) => 14,
Color::Light(BaseColor::White) => 15,
Color::Rgb(r, g, b) => {
let r = 6 * r as u16 / 256;
let g = 6 * g as u16 / 256;

View File

@ -254,6 +254,7 @@ impl Cursive {
pub fn set_theme(&mut self, theme: theme::Theme) {
self.theme = theme;
self.theme.activate();
B::clear();
}
/// Loads a theme from the given file.

View File

@ -8,7 +8,7 @@ use backend::Backend;
use B;
use theme::{ColorStyle, Effect, Theme};
use theme::{BorderStyle, ColorStyle, Effect, Theme};
use vec::Vec2;
/// Convenient interface to draw on a subset of the screen.
@ -121,7 +121,8 @@ impl Printer {
/// # let printer = Printer::new((6,4), theme::load_default());
/// printer.print_box((0,0), (6,4));
/// ```
pub fn print_box<T: Into<Vec2>, S: Into<Vec2>>(&self, start: T, size: S) {
pub fn print_box<T: Into<Vec2>, S: Into<Vec2>>(&self, start: T, size: S,
invert: bool) {
let start = start.into();
let size = size.into();
if size.x < 2 || size.y < 2 {
@ -129,15 +130,37 @@ impl Printer {
}
let size = size - (1, 1);
self.print(start, "");
self.print(start + size.keep_x(), "");
self.print(start + size.keep_y(), "");
self.print(start + size, "");
let borders = if let Some(borders) = self.theme.borders {
borders
} else {
return;
};
self.print_hline(start + (1, 0), size.x - 1, "");
self.print_vline(start + (0, 1), size.y - 1, "");
self.print_hline(start + (1, 0) + size.keep_y(), size.x - 1, "");
self.print_vline(start + (0, 1) + size.keep_x(), size.y - 1, "");
self.with_color(match borders {
BorderStyle::Outset if !invert => {
ColorStyle::Tertiary
}
_ => ColorStyle::Primary,
},
|s| {
s.print(start, "");
s.print(start + size.keep_y(), "");
s.print_hline(start + (1, 0), size.x - 1, "");
s.print_vline(start + (0, 1), size.y - 1, "");
});
self.with_color(match borders {
BorderStyle::Outset if invert => {
ColorStyle::Tertiary
}
_ => ColorStyle::Primary,
},
|s| {
s.print(start + size.keep_x(), "");
s.print(start + size, "");
s.print_hline(start + (1, 0) + size.keep_y(), size.x - 1, "");
s.print_vline(start + (0, 1) + size.keep_x(), size.y - 1, "");
});
}
/// Apply a selection style and call the given function.

View File

@ -184,7 +184,7 @@ pub struct Theme {
/// Wheter views in a StackView should have shadows.
pub shadow: bool,
/// How view borders should be drawn.
pub borders: BorderStyle,
pub borders: Option<BorderStyle>,
/// What colors should be used through the application?
pub colors: Palette,
}
@ -193,18 +193,18 @@ impl Default for Theme {
fn default() -> Self {
Theme {
shadow: true,
borders: BorderStyle::Simple,
borders: Some(BorderStyle::Simple),
colors: Palette {
background: Color::Blue,
shadow: Color::Black,
view: Color::White,
primary: Color::Black,
secondary: Color::Blue,
tertiary: Color::White,
title_primary: Color::Red,
title_secondary: Color::Yellow,
highlight: Color::Red,
highlight_inactive: Color::Blue,
background: Color::Dark(BaseColor::Blue),
shadow: Color::Dark(BaseColor::Black),
view: Color::Dark(BaseColor::White),
primary: Color::Dark(BaseColor::Black),
secondary: Color::Dark(BaseColor::Blue),
tertiary: Color::Light(BaseColor::White),
title_primary: Color::Dark(BaseColor::Red),
title_secondary: Color::Dark(BaseColor::Yellow),
highlight: Color::Dark(BaseColor::Red),
highlight_inactive: Color::Dark(BaseColor::Blue),
},
}
}
@ -217,9 +217,7 @@ impl Theme {
}
if let Some(&toml::Value::String(ref borders)) = table.get("borders") {
if let Some(borders) = BorderStyle::from(borders) {
self.borders = borders;
}
self.borders = BorderStyle::from(borders);
}
if let Some(&toml::Value::Table(ref table)) = table.get("colors") {
@ -269,8 +267,6 @@ impl Theme {
/// Borders are used around Dialogs, select popups, and panels.
#[derive(Clone,Copy,Debug)]
pub enum BorderStyle {
/// Don't draw any border.
NoBorder,
/// Simple borders.
Simple,
/// Outset borders with a simple 3d effect.
@ -281,8 +277,6 @@ impl BorderStyle {
fn from(s: &str) -> Option<Self> {
if s == "simple" {
Some(BorderStyle::Simple)
} else if s == "none" {
Some(BorderStyle::NoBorder)
} else if s == "outset" {
Some(BorderStyle::Outset)
} else {
@ -357,9 +351,9 @@ fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool {
}
}
/// Represents a color used by the theme.
#[derive(Clone,Debug)]
pub enum Color {
/// One of the 8 base colors.
#[derive(Clone,Copy,Debug)]
pub enum BaseColor {
/// Black color
///
/// Color #0
@ -392,6 +386,15 @@ pub enum Color {
///
/// Color #7
White,
}
/// Represents a color used by the theme.
#[derive(Clone,Copy,Debug)]
pub enum Color {
/// One of the 8 base colors.
Dark(BaseColor),
/// Lighter version of a base color.
Light(BaseColor),
/// True-color, 24-bit.
Rgb(u8, u8, u8),
/// Low-resolution
@ -422,14 +425,22 @@ impl From<io::Error> for Error {
impl Color {
fn parse(value: &str) -> Option<Self> {
Some(match value {
"black" => Color::Black,
"red" => Color::Red,
"green" => Color::Green,
"yellow" => Color::Yellow,
"blue" => Color::Blue,
"magenta" => Color::Magenta,
"cyan" => Color::Cyan,
"white" => Color::White,
"black" => Color::Dark(BaseColor::Black),
"red" => Color::Dark(BaseColor::Red),
"green" => Color::Dark(BaseColor::Green),
"yellow" => Color::Dark(BaseColor::Yellow),
"blue" => Color::Dark(BaseColor::Blue),
"magenta" => Color::Dark(BaseColor::Magenta),
"cyan" => Color::Dark(BaseColor::Cyan),
"white" => Color::Dark(BaseColor::White),
"light black" => Color::Light(BaseColor::Black),
"light red" => Color::Light(BaseColor::Red),
"light green" => Color::Light(BaseColor::Green),
"light yellow" => Color::Light(BaseColor::Yellow),
"light blue" => Color::Light(BaseColor::Blue),
"light magenta" => Color::Light(BaseColor::Magenta),
"light cyan" => Color::Light(BaseColor::Cyan),
"light white" => Color::Light(BaseColor::White),
value => return Color::parse_special(value),
})
}

View File

@ -218,7 +218,7 @@ impl View for Dialog {
inner_size,
self.focus == Focus::Content));
printer.print_box(Vec2::new(0, 0), printer.size);
printer.print_box(Vec2::new(0, 0), printer.size, false);
if !self.title.is_empty() {
let len = self.title.width();

View File

@ -156,7 +156,7 @@ impl View for MenuPopup {
&printer.sub_printer(Vec2::new(0, offset), printer.size, true);
// Start with a box
printer.print_box(Vec2::new(0, 0), printer.size);
printer.print_box(Vec2::new(0, 0), printer.size, false);
// We're giving it a reduced size because of borders.
// But we're keeping the full width,

View File

@ -24,7 +24,7 @@ impl<V: View> ViewWrapper for Panel<V> {
}
fn wrap_draw(&self, printer: &Printer) {
printer.print_box((0, 0), printer.size);
printer.print_box((0, 0), printer.size, true);
self.view
.draw(&printer.sub_printer((1, 1), printer.size - (2, 2), true));
}

View File

@ -66,11 +66,9 @@ impl<T: View> ViewWrapper for ShadowView<T> {
}
// Skip the first row/column
let printer =
&printer.sub_printer(Vec2::new(self.left_padding as usize,
self.top_padding as usize),
printer.size,
true);
let offset = Vec2::new(self.left_padding as usize,
self.top_padding as usize);
let printer = &printer.offset(offset, true);
// Draw the view background
for y in 0..printer.size.y - 1 {
@ -81,12 +79,14 @@ impl<T: View> ViewWrapper for ShadowView<T> {
printer.size - (1, 1),
true));
let h = printer.size.y;
let w = printer.size.x;
if printer.theme.shadow {
let h = printer.size.y;
let w = printer.size.x;
printer.with_color(ColorStyle::Shadow, |printer| {
printer.print_hline((1, h - 1), w - 1, " ");
printer.print_vline((w - 1, 1), h - 1, " ");
});
printer.with_color(ColorStyle::Shadow, |printer| {
printer.print_hline((1, h - 1), w - 1, " ");
printer.print_vline((w - 1, 1), h - 1, " ");
});
}
}
}