mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Refactor ColorStyle
Add the notion of PaletteColor to use a color from the palette. Breaking change: most color styles are now methods rather than enum variants.
This commit is contained in:
parent
d9215a2b39
commit
5ac0fce363
35
Cargo.toml
35
Cargo.toml
@ -1,31 +1,21 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["Alexandre Bury <alexandre.bury@gmail.com>"]
|
authors = ["Alexandre Bury <alexandre.bury@gmail.com>"]
|
||||||
categories = [
|
categories = ["command-line-interface", "gui"]
|
||||||
"command-line-interface",
|
|
||||||
"gui",
|
|
||||||
]
|
|
||||||
description = "A TUI (Text User Interface) library focused on ease-of-use."
|
description = "A TUI (Text User Interface) library focused on ease-of-use."
|
||||||
documentation = "https://docs.rs/cursive"
|
documentation = "https://docs.rs/cursive"
|
||||||
exclude = [
|
exclude = ["doc/**", "assets/**", "examples/**"]
|
||||||
"doc/**",
|
keywords = ["ncurses", "TUI", "UI"]
|
||||||
"assets/**",
|
|
||||||
"examples/**",
|
|
||||||
]
|
|
||||||
keywords = [
|
|
||||||
"ncurses",
|
|
||||||
"TUI",
|
|
||||||
"UI",
|
|
||||||
]
|
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "cursive"
|
name = "cursive"
|
||||||
readme = "Readme.md"
|
readme = "Readme.md"
|
||||||
repository = "https://github.com/gyscos/Cursive"
|
repository = "https://github.com/gyscos/Cursive"
|
||||||
version = "0.7.6-alpha.0"
|
version = "0.7.6-alpha.0"
|
||||||
|
|
||||||
[badges.travis-ci]
|
[badges.travis-ci]
|
||||||
repository = "gyscos/Cursive"
|
repository = "gyscos/Cursive"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
enum-map = "0.2.24"
|
||||||
|
enumset = "0.3.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
maplit = "1.0.0"
|
maplit = "1.0.0"
|
||||||
num = "0.1"
|
num = "0.1"
|
||||||
@ -34,8 +24,6 @@ toml = "0.4"
|
|||||||
unicode-segmentation = "1.0"
|
unicode-segmentation = "1.0"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.1"
|
||||||
xi-unicode = "0.1.0"
|
xi-unicode = "0.1.0"
|
||||||
pulldown-cmark = { version = "0.1.0", optional = true, default-features = false }
|
|
||||||
enumset = "0.3.3"
|
|
||||||
|
|
||||||
[dependencies.bear-lib-terminal]
|
[dependencies.bear-lib-terminal]
|
||||||
optional = true
|
optional = true
|
||||||
@ -59,6 +47,11 @@ features = ["wide"]
|
|||||||
optional = true
|
optional = true
|
||||||
version = "0.13"
|
version = "0.13"
|
||||||
|
|
||||||
|
[dependencies.pulldown-cmark]
|
||||||
|
default-features = false
|
||||||
|
optional = true
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies.termion]
|
[dependencies.termion]
|
||||||
optional = true
|
optional = true
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -69,14 +62,10 @@ rand = "0.4"
|
|||||||
[features]
|
[features]
|
||||||
blt-backend = ["bear-lib-terminal"]
|
blt-backend = ["bear-lib-terminal"]
|
||||||
default = ["ncurses-backend"]
|
default = ["ncurses-backend"]
|
||||||
|
markdown = ["pulldown-cmark"]
|
||||||
ncurses-backend = ["ncurses"]
|
ncurses-backend = ["ncurses"]
|
||||||
pancurses-backend = ["pancurses"]
|
pancurses-backend = ["pancurses"]
|
||||||
termion-backend = [
|
termion-backend = ["termion", "chan", "chan-signal"]
|
||||||
"termion",
|
|
||||||
"chan",
|
|
||||||
"chan-signal",
|
|
||||||
]
|
|
||||||
markdown = ["pulldown-cmark"]
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "cursive"
|
name = "cursive"
|
||||||
|
@ -34,10 +34,10 @@ fn draw(_: &(), p: &Printer) {
|
|||||||
for x in 0..x_max {
|
for x in 0..x_max {
|
||||||
for y in 0..y_max {
|
for y in 0..y_max {
|
||||||
// We'll use a different style for each cell
|
// We'll use a different style for each cell
|
||||||
let style = ColorStyle::Custom {
|
let style = ColorStyle::new(
|
||||||
front: front_color(x, y, x_max, y_max),
|
front_color(x, y, x_max, y_max),
|
||||||
back: back_color(x, y, x_max, y_max),
|
back_color(x, y, x_max, y_max),
|
||||||
};
|
);
|
||||||
|
|
||||||
p.with_color(style, |printer| {
|
p.with_color(style, |printer| {
|
||||||
printer.print((x, y), "+");
|
printer.print((x, y), "+");
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
extern crate cursive;
|
extern crate cursive;
|
||||||
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
#[cfg(feature = "markdown")]
|
|
||||||
use cursive::utils::markup::markdown;
|
|
||||||
use cursive::views::{Dialog, TextView};
|
use cursive::views::{Dialog, TextView};
|
||||||
|
|
||||||
// Make sure you compile with the `markdown` feature!
|
use cursive::theme::Color;
|
||||||
//
|
use cursive::theme::BaseColor;
|
||||||
// cargo run --example markup --features markdown
|
use cursive::theme::Style;
|
||||||
|
use cursive::theme::Effect;
|
||||||
|
use cursive::utils::markup::StyledString;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut siv = Cursive::new();
|
let mut siv = Cursive::new();
|
||||||
|
|
||||||
// If markdown is enabled, parse a small text.
|
let mut styled = StyledString::plain("Isn't ");
|
||||||
|
styled.append(StyledString::styled("that ", Color::Dark(BaseColor::Red)));
|
||||||
#[cfg(feature = "markdown")]
|
styled.append(StyledString::styled(
|
||||||
let text = markdown::parse("Isn't *that* **cool**?");
|
"cool?",
|
||||||
|
Style::from(Color::Light(BaseColor::Blue)).add(Effect::Bold),
|
||||||
#[cfg(not(feature = "markdown"))]
|
));
|
||||||
let text = "Rebuild with --features markdown ;)";
|
|
||||||
|
|
||||||
// TextView can natively accept StyledString.
|
// TextView can natively accept StyledString.
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
Dialog::around(TextView::new(text)).button("Hell yeah!", |s| s.quit()),
|
Dialog::around(TextView::new(styled))
|
||||||
|
.button("Hell yeah!", |s| s.quit()),
|
||||||
);
|
);
|
||||||
|
|
||||||
siv.run();
|
siv.run();
|
||||||
|
@ -208,10 +208,7 @@ impl cursive::view::View for BoardView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
printer.with_color(
|
printer.with_color(
|
||||||
ColorStyle::Custom {
|
ColorStyle::new(color, Color::Dark(BaseColor::Black)),
|
||||||
back: color,
|
|
||||||
front: Color::Dark(BaseColor::Black),
|
|
||||||
},
|
|
||||||
|printer| printer.print((x, y), text),
|
|printer| printer.print((x, y), text),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
extern crate cursive;
|
extern crate cursive;
|
||||||
|
|
||||||
use cursive::Cursive;
|
use cursive::Cursive;
|
||||||
use cursive::theme::{Color, Theme};
|
use cursive::theme::{Color, PaletteColor, Theme};
|
||||||
use cursive::views::TextView;
|
use cursive::views::TextView;
|
||||||
|
|
||||||
// This example sets the background color to the terminal default.
|
// This example sets the background color to the terminal default.
|
||||||
@ -30,7 +30,7 @@ fn custom_theme_from_cursive(siv: &Cursive) -> Theme {
|
|||||||
// We'll return the current theme with a small modification.
|
// We'll return the current theme with a small modification.
|
||||||
let mut theme = siv.current_theme().clone();
|
let mut theme = siv.current_theme().clone();
|
||||||
|
|
||||||
theme.colors.background = Color::TerminalDefault;
|
theme.palette.colors[PaletteColor::Background] = Color::TerminalDefault;
|
||||||
|
|
||||||
theme
|
theme
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,10 @@ fn main() {
|
|||||||
let layout = LinearLayout::vertical()
|
let layout = LinearLayout::vertical()
|
||||||
.child(TextView::new("This is a dynamic theme example!"))
|
.child(TextView::new("This is a dynamic theme example!"))
|
||||||
.child(EditView::new().content("Woo! colors!").style(
|
.child(EditView::new().content("Woo! colors!").style(
|
||||||
ColorStyle::Custom {
|
ColorStyle::new(
|
||||||
front: Color::Rgb(200, 150, 150),
|
Color::Rgb(200, 150, 150),
|
||||||
back: Color::Dark(BaseColor::Blue),
|
Color::Dark(BaseColor::Blue),
|
||||||
},
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
|
@ -167,14 +167,16 @@ impl Cursive {
|
|||||||
///
|
///
|
||||||
/// Users rarely have to call this directly.
|
/// Users rarely have to call this directly.
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
self.backend.clear(self.theme.colors.background);
|
self.backend
|
||||||
|
.clear(self.theme.palette.colors[theme::PaletteColor::Background]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a theme from the given file.
|
/// Loads a theme from the given file.
|
||||||
///
|
///
|
||||||
/// `filename` must point to a valid toml file.
|
/// `filename` must point to a valid toml file.
|
||||||
pub fn load_theme_file<P: AsRef<Path>>(
|
pub fn load_theme_file<P: AsRef<Path>>(
|
||||||
&mut self, filename: P
|
&mut self,
|
||||||
|
filename: P,
|
||||||
) -> Result<(), theme::Error> {
|
) -> Result<(), theme::Error> {
|
||||||
self.set_theme(try!(theme::load_theme_file(filename)));
|
self.set_theme(try!(theme::load_theme_file(filename)));
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -279,7 +281,9 @@ impl Cursive {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn call_on<V, F, R>(
|
pub fn call_on<V, F, R>(
|
||||||
&mut self, sel: &view::Selector, callback: F
|
&mut self,
|
||||||
|
sel: &view::Selector,
|
||||||
|
callback: F,
|
||||||
) -> Option<R>
|
) -> Option<R>
|
||||||
where
|
where
|
||||||
V: View + Any,
|
V: View + Any,
|
||||||
|
@ -65,6 +65,9 @@ extern crate enumset;
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate maplit;
|
extern crate maplit;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate enum_map;
|
||||||
|
|
||||||
extern crate num;
|
extern crate num;
|
||||||
extern crate owning_ref;
|
extern crate owning_ref;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
@ -5,7 +5,7 @@ use enumset::EnumSet;
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use theme::{BorderStyle, ColorStyle, Effect, Style, Theme};
|
use theme::{BorderStyle, ColorStyle, Effect, Style, Theme, PaletteColor};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use utils::lines::simple::prefix;
|
use utils::lines::simple::prefix;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
@ -51,7 +51,7 @@ impl<'a> Printer<'a> {
|
|||||||
///
|
///
|
||||||
/// Users rarely need to call this directly.
|
/// Users rarely need to call this directly.
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
self.backend.clear(self.theme.colors.background);
|
self.backend.clear(self.theme.palette.colors[PaletteColor::Background]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if nothing has been printed yet.
|
/// Returns `true` if nothing has been printed yet.
|
||||||
@ -123,7 +123,7 @@ impl<'a> Printer<'a> {
|
|||||||
/// # let b = backend::Concrete::init();
|
/// # let b = backend::Concrete::init();
|
||||||
/// # let t = theme::load_default();
|
/// # let t = theme::load_default();
|
||||||
/// # let printer = Printer::new((6,4), &t, &b);
|
/// # let printer = Printer::new((6,4), &t, &b);
|
||||||
/// printer.with_color(theme::ColorStyle::Highlight, |printer| {
|
/// printer.with_color(theme::ColorStyle::highlight(), |printer| {
|
||||||
/// printer.print((0,0), "This text is highlighted!");
|
/// printer.print((0,0), "This text is highlighted!");
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
@ -131,7 +131,7 @@ impl<'a> Printer<'a> {
|
|||||||
where
|
where
|
||||||
F: FnOnce(&Printer),
|
F: FnOnce(&Printer),
|
||||||
{
|
{
|
||||||
self.backend.with_color(c.resolve(self.theme), || f(self));
|
self.backend.with_color(c.resolve(&self.theme.palette), || f(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the given closure with a styled printer,
|
/// Call the given closure with a styled printer,
|
||||||
@ -239,8 +239,8 @@ impl<'a> Printer<'a> {
|
|||||||
{
|
{
|
||||||
let color = match self.theme.borders {
|
let color = match self.theme.borders {
|
||||||
BorderStyle::None => return,
|
BorderStyle::None => return,
|
||||||
BorderStyle::Outset if !invert => ColorStyle::Tertiary,
|
BorderStyle::Outset if !invert => ColorStyle::tertiary(),
|
||||||
_ => ColorStyle::Primary,
|
_ => ColorStyle::primary(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.with_color(color, f);
|
self.with_color(color, f);
|
||||||
@ -250,16 +250,16 @@ impl<'a> Printer<'a> {
|
|||||||
///
|
///
|
||||||
/// * If the theme's borders is `None`, return without calling `f`.
|
/// * If the theme's borders is `None`, return without calling `f`.
|
||||||
/// * If the theme's borders is "outset" and `invert` is `true`,
|
/// * If the theme's borders is "outset" and `invert` is `true`,
|
||||||
/// use `ColorStyle::Tertiary`.
|
/// use `ColorStyle::tertiary()`.
|
||||||
/// * Otherwise, use `ColorStyle::Primary`.
|
/// * Otherwise, use `ColorStyle::primary()`.
|
||||||
pub fn with_low_border<F>(&self, invert: bool, f: F)
|
pub fn with_low_border<F>(&self, invert: bool, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&Printer),
|
F: FnOnce(&Printer),
|
||||||
{
|
{
|
||||||
let color = match self.theme.borders {
|
let color = match self.theme.borders {
|
||||||
BorderStyle::None => return,
|
BorderStyle::None => return,
|
||||||
BorderStyle::Outset if invert => ColorStyle::Tertiary,
|
BorderStyle::Outset if invert => ColorStyle::tertiary(),
|
||||||
_ => ColorStyle::Primary,
|
_ => ColorStyle::primary(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.with_color(color, f);
|
self.with_color(color, f);
|
||||||
@ -267,21 +267,21 @@ impl<'a> Printer<'a> {
|
|||||||
|
|
||||||
/// Apply a selection style and call the given function.
|
/// Apply a selection style and call the given function.
|
||||||
///
|
///
|
||||||
/// * If `selection` is `false`, simply uses `ColorStyle::Primary`.
|
/// * If `selection` is `false`, simply uses `ColorStyle::primary()`.
|
||||||
/// * If `selection` is `true`:
|
/// * If `selection` is `true`:
|
||||||
/// * If the printer currently has the focus,
|
/// * If the printer currently has the focus,
|
||||||
/// uses `ColorStyle::Highlight`.
|
/// uses `ColorStyle::highlight()`.
|
||||||
/// * Otherwise, uses `ColorStyle::HighlightInactive`.
|
/// * Otherwise, uses `ColorStyle::highlight_inactive()`.
|
||||||
pub fn with_selection<F: FnOnce(&Printer)>(&self, selection: bool, f: F) {
|
pub fn with_selection<F: FnOnce(&Printer)>(&self, selection: bool, f: F) {
|
||||||
self.with_color(
|
self.with_color(
|
||||||
if selection {
|
if selection {
|
||||||
if self.focused {
|
if self.focused {
|
||||||
ColorStyle::Highlight
|
ColorStyle::highlight()
|
||||||
} else {
|
} else {
|
||||||
ColorStyle::HighlightInactive
|
ColorStyle::highlight_inactive()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ColorStyle::Primary
|
ColorStyle::primary()
|
||||||
},
|
},
|
||||||
f,
|
f,
|
||||||
);
|
);
|
||||||
|
@ -56,12 +56,16 @@ impl From<u8> for BaseColor {
|
|||||||
pub enum Color {
|
pub enum Color {
|
||||||
/// Represents a color, preset by terminal.
|
/// Represents a color, preset by terminal.
|
||||||
TerminalDefault,
|
TerminalDefault,
|
||||||
|
|
||||||
/// One of the 8 base colors.
|
/// One of the 8 base colors.
|
||||||
Dark(BaseColor),
|
Dark(BaseColor),
|
||||||
|
|
||||||
/// Lighter version of a base color.
|
/// Lighter version of a base color.
|
||||||
Light(BaseColor),
|
Light(BaseColor),
|
||||||
|
|
||||||
/// True-color, 24-bit.
|
/// True-color, 24-bit.
|
||||||
Rgb(u8, u8, u8),
|
Rgb(u8, u8, u8),
|
||||||
|
|
||||||
/// Low-resolution
|
/// Low-resolution
|
||||||
///
|
///
|
||||||
/// Each value should be `<= 5` (you'll get panics otherwise).
|
/// Each value should be `<= 5` (you'll get panics otherwise).
|
||||||
|
@ -5,6 +5,7 @@ use super::Color;
|
|||||||
pub struct ColorPair {
|
pub struct ColorPair {
|
||||||
/// Color used for the foreground.
|
/// Color used for the foreground.
|
||||||
pub front: Color,
|
pub front: Color,
|
||||||
|
|
||||||
/// Color used for the background.
|
/// Color used for the background.
|
||||||
pub back: Color,
|
pub back: Color,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{Color, ColorPair, Theme};
|
use super::{Color, ColorPair, Palette, PaletteColor};
|
||||||
|
|
||||||
/// Possible color style for a cell.
|
/// Possible color style for a cell.
|
||||||
///
|
///
|
||||||
@ -6,57 +6,141 @@ use super::{Color, ColorPair, Theme};
|
|||||||
///
|
///
|
||||||
/// The current theme will assign each role a foreground and background color.
|
/// The current theme will assign each role a foreground and background color.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ColorStyle {
|
pub struct ColorStyle {
|
||||||
/// Style set by terminal before entering a Cursive program.
|
/// Color used for the foreground (the text itself).
|
||||||
TerminalDefault,
|
pub front: ColorType,
|
||||||
/// Application background, where no view is present.
|
|
||||||
Background,
|
/// Color used for the background.
|
||||||
/// Color used by view shadows. Only background matters.
|
pub back: ColorType,
|
||||||
Shadow,
|
|
||||||
/// Main text with default background.
|
|
||||||
Primary,
|
|
||||||
/// Secondary text color, with default background.
|
|
||||||
Secondary,
|
|
||||||
/// Tertiary text color, with default background.
|
|
||||||
Tertiary,
|
|
||||||
/// Title text color with default background.
|
|
||||||
TitlePrimary,
|
|
||||||
/// Alternative color for a title.
|
|
||||||
TitleSecondary,
|
|
||||||
/// Alternate text with highlight background.
|
|
||||||
Highlight,
|
|
||||||
/// Highlight color for inactive views (not in focus).
|
|
||||||
HighlightInactive,
|
|
||||||
/// Directly specifies colors, independently of the theme.
|
|
||||||
Custom {
|
|
||||||
/// Foreground color
|
|
||||||
front: Color,
|
|
||||||
/// Background color
|
|
||||||
back: Color,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColorStyle {
|
impl ColorStyle {
|
||||||
|
/// Creates
|
||||||
|
pub fn new<F, B>(front: F, back: B) -> Self
|
||||||
|
where
|
||||||
|
F: Into<ColorType>,
|
||||||
|
B: Into<ColorType>,
|
||||||
|
{
|
||||||
|
let front = front.into();
|
||||||
|
let back = back.into();
|
||||||
|
Self { front, back }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Style set by terminal before entering a Cursive program.
|
||||||
|
pub fn terminal_default() -> Self {
|
||||||
|
Self::new(Color::TerminalDefault, Color::TerminalDefault)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Application background, where no view is present.
|
||||||
|
pub fn background() -> Self {
|
||||||
|
Self::new(PaletteColor::Background, PaletteColor::Background)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Color used by view shadows. Only background matters.
|
||||||
|
pub fn shadow() -> Self {
|
||||||
|
Self::new(PaletteColor::Shadow, PaletteColor::Shadow)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Main text with default background.
|
||||||
|
pub fn primary() -> Self {
|
||||||
|
Self::new(PaletteColor::Primary, PaletteColor::View)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Secondary text color, with default background.
|
||||||
|
pub fn secondary() -> Self {
|
||||||
|
Self::new(PaletteColor::Secondary, PaletteColor::View)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tertiary text color, with default background.
|
||||||
|
pub fn tertiary() -> Self {
|
||||||
|
Self::new(PaletteColor::Tertiary, PaletteColor::View)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Title text color with default background.
|
||||||
|
pub fn title_primary() -> Self {
|
||||||
|
Self::new(PaletteColor::TitlePrimary, PaletteColor::View)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alternative color for a title.
|
||||||
|
pub fn title_secondary() -> Self {
|
||||||
|
Self::new(PaletteColor::TitleSecondary, PaletteColor::View)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Alternate text with highlight background.
|
||||||
|
pub fn highlight() -> Self {
|
||||||
|
Self::new(PaletteColor::View, PaletteColor::Highlight)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Highlight color for inactive views (not in focus).
|
||||||
|
pub fn highlight_inactive() -> Self {
|
||||||
|
Self::new(PaletteColor::View, PaletteColor::HighlightInactive)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the color pair that this style represents.
|
/// Return the color pair that this style represents.
|
||||||
///
|
pub fn resolve(&self, palette: &Palette) -> ColorPair {
|
||||||
/// Returns `(front, back)`.
|
ColorPair {
|
||||||
pub fn resolve(&self, theme: &Theme) -> ColorPair {
|
front: self.front.resolve(palette),
|
||||||
let c = &theme.colors;
|
back: self.back.resolve(palette),
|
||||||
let (front, back) = match *self {
|
}
|
||||||
ColorStyle::TerminalDefault => {
|
}
|
||||||
(Color::TerminalDefault, Color::TerminalDefault)
|
}
|
||||||
}
|
|
||||||
ColorStyle::Background => (c.view, c.background),
|
impl From<Color> for ColorStyle {
|
||||||
ColorStyle::Shadow => (c.shadow, c.shadow),
|
fn from(color: Color) -> Self {
|
||||||
ColorStyle::Primary => (c.primary, c.view),
|
Self::new(color, PaletteColor::View)
|
||||||
ColorStyle::Secondary => (c.secondary, c.view),
|
}
|
||||||
ColorStyle::Tertiary => (c.tertiary, c.view),
|
}
|
||||||
ColorStyle::TitlePrimary => (c.title_primary, c.view),
|
|
||||||
ColorStyle::TitleSecondary => (c.title_secondary, c.view),
|
impl From<PaletteColor> for ColorStyle {
|
||||||
ColorStyle::Highlight => (c.view, c.highlight),
|
fn from(color: PaletteColor) -> Self {
|
||||||
ColorStyle::HighlightInactive => (c.view, c.highlight_inactive),
|
Self::new(color, PaletteColor::View)
|
||||||
ColorStyle::Custom { front, back } => (front, back),
|
}
|
||||||
};
|
}
|
||||||
ColorPair { front, back }
|
|
||||||
|
impl From<ColorType> for ColorStyle {
|
||||||
|
fn from(color: ColorType) -> Self {
|
||||||
|
Self::new(color, PaletteColor::View)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F, B> From<(F, B)> for ColorStyle
|
||||||
|
where
|
||||||
|
F: Into<ColorType>,
|
||||||
|
B: Into<ColorType>,
|
||||||
|
{
|
||||||
|
fn from((front, back): (F, B)) -> Self {
|
||||||
|
Self::new(front, back)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Either a color from the palette, or a direct color.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum ColorType {
|
||||||
|
/// Uses a color from the application palette.
|
||||||
|
Palette(PaletteColor),
|
||||||
|
|
||||||
|
/// Uses a direct color, independent of the current palette.
|
||||||
|
Color(Color),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorType {
|
||||||
|
/// Given a palette, resolve `self` to a concrete color.
|
||||||
|
pub fn resolve(self, palette: &Palette) -> Color {
|
||||||
|
match self {
|
||||||
|
ColorType::Color(color) => color,
|
||||||
|
ColorType::Palette(color) => color.resolve(palette),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Color> for ColorType {
|
||||||
|
fn from(color: Color) -> Self {
|
||||||
|
ColorType::Color(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PaletteColor> for ColorType {
|
||||||
|
fn from(color: PaletteColor) -> Self {
|
||||||
|
ColorType::Palette(color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,9 +124,9 @@ mod palette;
|
|||||||
pub use self::border_style::BorderStyle;
|
pub use self::border_style::BorderStyle;
|
||||||
pub use self::color::{BaseColor, Color};
|
pub use self::color::{BaseColor, Color};
|
||||||
pub use self::color_pair::ColorPair;
|
pub use self::color_pair::ColorPair;
|
||||||
pub use self::color_style::ColorStyle;
|
pub use self::color_style::{ColorStyle, ColorType};
|
||||||
pub use self::effect::Effect;
|
pub use self::effect::Effect;
|
||||||
pub use self::palette::Palette;
|
pub use self::palette::{Palette, PaletteColor};
|
||||||
pub use self::style::Style;
|
pub use self::style::Style;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -142,7 +142,7 @@ pub struct Theme {
|
|||||||
/// How view borders should be drawn.
|
/// How view borders should be drawn.
|
||||||
pub borders: BorderStyle,
|
pub borders: BorderStyle,
|
||||||
/// What colors should be used through the application?
|
/// What colors should be used through the application?
|
||||||
pub colors: Palette,
|
pub palette: Palette,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Theme {
|
impl Default for Theme {
|
||||||
@ -150,18 +150,7 @@ impl Default for Theme {
|
|||||||
Theme {
|
Theme {
|
||||||
shadow: true,
|
shadow: true,
|
||||||
borders: BorderStyle::Simple,
|
borders: BorderStyle::Simple,
|
||||||
colors: Palette {
|
palette: Palette::default(),
|
||||||
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),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +166,7 @@ impl Theme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(&toml::Value::Table(ref table)) = table.get("colors") {
|
if let Some(&toml::Value::Table(ref table)) = table.get("colors") {
|
||||||
self.colors.load(table);
|
self.palette.load(table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,52 +1,118 @@
|
|||||||
use super::Color;
|
use super::Color;
|
||||||
use toml;
|
use toml;
|
||||||
|
use enum_map::EnumMap;
|
||||||
|
|
||||||
/// Color configuration for the application.
|
/// Color configuration for the application.
|
||||||
///
|
///
|
||||||
/// Assign each color role an actual color.
|
/// Assign each color role an actual color.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Palette {
|
pub struct Palette {
|
||||||
/// Color used for the application background.
|
/// Color map for this palette
|
||||||
pub background: Color,
|
pub colors: EnumMap<PaletteColor, Color>,
|
||||||
/// Color used for View shadows.
|
}
|
||||||
pub shadow: Color,
|
|
||||||
/// Color used for View backgrounds.
|
impl Default for Palette {
|
||||||
pub view: Color,
|
fn default() -> Self {
|
||||||
/// Primary color used for the text.
|
use self::PaletteColor::*;
|
||||||
pub primary: Color,
|
use theme::Color::*;
|
||||||
/// Secondary color used for the text.
|
use theme::BaseColor::*;
|
||||||
pub secondary: Color,
|
|
||||||
/// Tertiary color used for the text.
|
Palette {
|
||||||
pub tertiary: Color,
|
colors: enum_map!{
|
||||||
/// Primary color used for title text.
|
Background => Dark(Blue),
|
||||||
pub title_primary: Color,
|
Shadow => Dark(Black),
|
||||||
/// Secondary color used for title text.
|
View => Dark(White),
|
||||||
pub title_secondary: Color,
|
Primary => Dark(Black),
|
||||||
/// Color used for highlighting text.
|
Secondary => Dark(Blue),
|
||||||
pub highlight: Color,
|
Tertiary => Dark(White),
|
||||||
/// Color used for highlighting inactive text.
|
TitlePrimary => Dark(Red),
|
||||||
pub highlight_inactive: Color,
|
TitleSecondary => Dark(Yellow),
|
||||||
|
Highlight => Dark(Red),
|
||||||
|
HighlightInactive => Dark(Blue),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Palette {
|
impl Palette {
|
||||||
/// Fills `self` with the colors from the given `table`.
|
/// Fills `self` with the colors from the given `table`.
|
||||||
pub(crate) fn load(&mut self, table: &toml::value::Table) {
|
pub(crate) fn load(&mut self, table: &toml::value::Table) {
|
||||||
load_color(&mut self.background, table.get("background"));
|
// TODO: use serde for that?
|
||||||
load_color(&mut self.shadow, table.get("shadow"));
|
// Problem: toml-rs doesn't do well with Enums...
|
||||||
load_color(&mut self.view, table.get("view"));
|
|
||||||
load_color(&mut self.primary, table.get("primary"));
|
|
||||||
load_color(&mut self.secondary, table.get("secondary"));
|
|
||||||
load_color(&mut self.tertiary, table.get("tertiary"));
|
|
||||||
load_color(&mut self.title_primary, table.get("title_primary"));
|
|
||||||
load_color(&mut self.title_secondary, table.get("title_secondary"));
|
|
||||||
load_color(&mut self.highlight, table.get("highlight"));
|
|
||||||
load_color(
|
load_color(
|
||||||
&mut self.highlight_inactive,
|
&mut self.colors[PaletteColor::Background],
|
||||||
|
table.get("background"),
|
||||||
|
);
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::Shadow],
|
||||||
|
table.get("shadow"),
|
||||||
|
);
|
||||||
|
load_color(&mut self.colors[PaletteColor::View], table.get("view"));
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::Primary],
|
||||||
|
table.get("primary"),
|
||||||
|
);
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::Secondary],
|
||||||
|
table.get("secondary"),
|
||||||
|
);
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::Tertiary],
|
||||||
|
table.get("tertiary"),
|
||||||
|
);
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::TitlePrimary],
|
||||||
|
table.get("title_primary"),
|
||||||
|
);
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::TitleSecondary],
|
||||||
|
table.get("title_secondary"),
|
||||||
|
);
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::Highlight],
|
||||||
|
table.get("highlight"),
|
||||||
|
);
|
||||||
|
load_color(
|
||||||
|
&mut self.colors[PaletteColor::HighlightInactive],
|
||||||
table.get("highlight_inactive"),
|
table.get("highlight_inactive"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Color entry in a palette.
|
||||||
|
///
|
||||||
|
/// Each ColorRole is used for a specific role in a default application.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumMap)]
|
||||||
|
pub enum PaletteColor {
|
||||||
|
/// Color used for the application background.
|
||||||
|
Background,
|
||||||
|
/// Color used for View shadows.
|
||||||
|
Shadow,
|
||||||
|
/// Color used for View backgrounds.
|
||||||
|
View,
|
||||||
|
/// Primary color used for the text.
|
||||||
|
Primary,
|
||||||
|
/// Secondary color used for the text.
|
||||||
|
Secondary,
|
||||||
|
/// Tertiary color used for the text.
|
||||||
|
Tertiary,
|
||||||
|
/// Primary color used for title text.
|
||||||
|
TitlePrimary,
|
||||||
|
/// Secondary color used for title text.
|
||||||
|
TitleSecondary,
|
||||||
|
/// Color used for highlighting text.
|
||||||
|
Highlight,
|
||||||
|
/// Color used for highlighting inactive text.
|
||||||
|
HighlightInactive,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PaletteColor {
|
||||||
|
/// Given a palette, resolve `self` to a concrete color.
|
||||||
|
pub fn resolve(self, palette: &Palette) -> Color {
|
||||||
|
palette.colors[self]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses `value` and fills `target` if it's a valid color.
|
/// Parses `value` and fills `target` if it's a valid color.
|
||||||
fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool {
|
fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{ColorStyle, Effect, Color};
|
use super::{ColorStyle, Effect, Color, PaletteColor, ColorType};
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
|
|
||||||
/// Combine a color and an effect.
|
/// Combine a color and an effect.
|
||||||
@ -73,3 +73,21 @@ impl From<ColorStyle> for Style {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Color> for Style {
|
||||||
|
fn from(color: Color) -> Self {
|
||||||
|
ColorStyle::from(color).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PaletteColor> for Style {
|
||||||
|
fn from(color: PaletteColor) -> Self {
|
||||||
|
ColorStyle::from(color).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ColorType> for Style {
|
||||||
|
fn from(color: ColorType) -> Self {
|
||||||
|
ColorStyle::from(color).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -277,9 +277,9 @@ impl ScrollBase {
|
|||||||
let start = self.scrollbar_thumb_y(height);
|
let start = self.scrollbar_thumb_y(height);
|
||||||
|
|
||||||
let color = if printer.focused {
|
let color = if printer.focused {
|
||||||
ColorStyle::Highlight
|
ColorStyle::highlight()
|
||||||
} else {
|
} else {
|
||||||
ColorStyle::HighlightInactive
|
ColorStyle::highlight_inactive()
|
||||||
};
|
};
|
||||||
|
|
||||||
let scrollbar_x = self.scrollbar_x(printer.size.x);
|
let scrollbar_x = self.scrollbar_x(printer.size.x);
|
||||||
|
@ -132,11 +132,11 @@ impl View for Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let style = if !self.enabled {
|
let style = if !self.enabled {
|
||||||
ColorStyle::Secondary
|
ColorStyle::secondary()
|
||||||
} else if !printer.focused {
|
} else if !printer.focused {
|
||||||
ColorStyle::Primary
|
ColorStyle::primary()
|
||||||
} else {
|
} else {
|
||||||
ColorStyle::Highlight
|
ColorStyle::highlight()
|
||||||
};
|
};
|
||||||
|
|
||||||
let offset =
|
let offset =
|
||||||
|
@ -119,7 +119,7 @@ impl View for Checkbox {
|
|||||||
self.draw_internal(printer)
|
self.draw_internal(printer)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
printer.with_color(ColorStyle::Secondary, |printer| {
|
printer.with_color(ColorStyle::secondary(), |printer| {
|
||||||
self.draw_internal(printer)
|
self.draw_internal(printer)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ impl Dialog {
|
|||||||
printer.print((x + len, 0), " ├");
|
printer.print((x + len, 0), " ├");
|
||||||
});
|
});
|
||||||
|
|
||||||
printer.with_color(ColorStyle::TitlePrimary, |p| {
|
printer.with_color(ColorStyle::title_primary(), |p| {
|
||||||
p.print((x, 0), &self.title)
|
p.print((x, 0), &self.title)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ impl EditView {
|
|||||||
secret: false,
|
secret: false,
|
||||||
filler: "_".to_string(),
|
filler: "_".to_string(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
style: ColorStyle::Secondary,
|
style: ColorStyle::secondary(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ fn show_child(s: &mut Cursive, offset: Vec2, menu: Rc<MenuTree>) {
|
|||||||
impl View for Menubar {
|
impl View for Menubar {
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer) {
|
||||||
// Draw the bar at the top
|
// Draw the bar at the top
|
||||||
printer.with_color(ColorStyle::Primary, |printer| {
|
printer.with_color(ColorStyle::primary(), |printer| {
|
||||||
printer.print_hline((0, 0), printer.size.x, " ");
|
printer.print_hline((0, 0), printer.size.x, " ");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ impl View for ProgressBar {
|
|||||||
let label = (self.label_maker)(value, (self.min, self.max));
|
let label = (self.label_maker)(value, (self.min, self.max));
|
||||||
let offset = HAlign::Center.get_offset(label.len(), printer.size.x);
|
let offset = HAlign::Center.get_offset(label.len(), printer.size.x);
|
||||||
|
|
||||||
printer.with_color(ColorStyle::Highlight, |printer| {
|
printer.with_color(ColorStyle::highlight(), |printer| {
|
||||||
printer.with_effect(Effect::Reverse, |printer| {
|
printer.with_effect(Effect::Reverse, |printer| {
|
||||||
printer.print((offset, 0), &label);
|
printer.print((offset, 0), &label);
|
||||||
});
|
});
|
||||||
|
@ -168,7 +168,7 @@ impl<T: 'static> View for RadioButton<T> {
|
|||||||
self.draw_internal(printer)
|
self.draw_internal(printer)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
printer.with_color(ColorStyle::Secondary, |printer| {
|
printer.with_color(ColorStyle::secondary(), |printer| {
|
||||||
self.draw_internal(printer)
|
self.draw_internal(printer)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -575,11 +575,11 @@ impl<T: 'static> View for SelectView<T> {
|
|||||||
|
|
||||||
if self.popup {
|
if self.popup {
|
||||||
let style = if !self.enabled {
|
let style = if !self.enabled {
|
||||||
ColorStyle::Secondary
|
ColorStyle::secondary()
|
||||||
} else if !printer.focused {
|
} else if !printer.focused {
|
||||||
ColorStyle::Primary
|
ColorStyle::primary()
|
||||||
} else {
|
} else {
|
||||||
ColorStyle::Highlight
|
ColorStyle::highlight()
|
||||||
};
|
};
|
||||||
let x = match printer.size.x.checked_sub(1) {
|
let x = match printer.size.x.checked_sub(1) {
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
@ -609,7 +609,7 @@ impl<T: 'static> View for SelectView<T> {
|
|||||||
self.scrollbase.draw(printer, |printer, i| {
|
self.scrollbase.draw(printer, |printer, i| {
|
||||||
printer.with_selection(i == self.focus(), |printer| {
|
printer.with_selection(i == self.focus(), |printer| {
|
||||||
if i != self.focus() && !self.enabled {
|
if i != self.focus() && !self.enabled {
|
||||||
printer.with_color(ColorStyle::Secondary, |printer| {
|
printer.with_color(ColorStyle::secondary(), |printer| {
|
||||||
self.draw_item(printer, i)
|
self.draw_item(printer, i)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,7 +87,7 @@ impl<T: View> ViewWrapper for ShadowView<T> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printer.with_color(ColorStyle::Shadow, |printer| {
|
printer.with_color(ColorStyle::shadow(), |printer| {
|
||||||
printer.print_hline((1, h - 1), w - 1, " ");
|
printer.print_hline((1, h - 1), w - 1, " ");
|
||||||
printer.print_vline((w - 1, 1), h - 1, " ");
|
printer.print_vline((w - 1, 1), h - 1, " ");
|
||||||
});
|
});
|
||||||
|
@ -123,9 +123,9 @@ impl View for SliderView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let color = if printer.focused {
|
let color = if printer.focused {
|
||||||
ColorStyle::Highlight
|
ColorStyle::highlight()
|
||||||
} else {
|
} else {
|
||||||
ColorStyle::HighlightInactive
|
ColorStyle::highlight_inactive()
|
||||||
};
|
};
|
||||||
printer.with_color(color, |printer| {
|
printer.with_color(color, |printer| {
|
||||||
printer.print(self.orientation.make_vec(self.value, 0), " ");
|
printer.print(self.orientation.make_vec(self.value, 0), " ");
|
||||||
|
@ -324,7 +324,7 @@ impl<R: Deref<Target = Child>, I: Iterator<Item = R>> Iterator
|
|||||||
impl View for StackView {
|
impl View for StackView {
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer) {
|
||||||
let last = self.layers.len();
|
let last = self.layers.len();
|
||||||
printer.with_color(ColorStyle::Primary, |printer| {
|
printer.with_color(ColorStyle::primary(), |printer| {
|
||||||
for (i, (v, offset)) in
|
for (i, (v, offset)) in
|
||||||
StackPositionIterator::new(self.layers.iter(), printer.size)
|
StackPositionIterator::new(self.layers.iter(), printer.size)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -413,7 +413,7 @@ impl View for TextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, printer: &Printer) {
|
fn draw(&self, printer: &Printer) {
|
||||||
printer.with_color(ColorStyle::Secondary, |printer| {
|
printer.with_color(ColorStyle::secondary(), |printer| {
|
||||||
let effect = if self.enabled {
|
let effect = if self.enabled {
|
||||||
Effect::Reverse
|
Effect::Reverse
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user