1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use super::Color;
use enum_map::EnumMap;
use toml;

/// Color configuration for the application.
///
/// Assign each color role an actual color.
///
/// It implements `Index` and `IndexMut` to access and modify this mapping:
///
/// # Example
///
/// ```rust
/// # use cursive::theme;
/// use cursive::theme::PaletteColor::*;
/// use cursive::theme::Color::*;
/// use cursive::theme::BaseColor::*;
///
/// let mut palette = theme::default_palette();
///
/// assert_eq!(palette[Background], Dark(Blue));
/// palette[Shadow] = Light(Red);
/// ```
pub type Palette = EnumMap<PaletteColor, Color>;

/// Returns the default palette for a cursive application.
///
/// * `Background` => `Dark(Blue)`
/// * `Shadow` => `Dark(Black)`
/// * `View` => `Dark(White)`
/// * `Primary` => `Dark(Black)`
/// * `Secondary` => `Dark(Blue)`
/// * `Tertiary` => `Dark(White)`
/// * `TitlePrimary` => `Dark(Red)`
/// * `TitleSecondary` => `Dark(Yellow)`
/// * `Highlight` => `Dark(Red)`
/// * `HighlightInactive` => `Dark(Blue)`
pub fn default_palette() -> Palette {
    use self::PaletteColor::*;
    use theme::BaseColor::*;
    use theme::Color::*;

    enum_map!{
        Background => Dark(Blue),
        Shadow => Dark(Black),
        View => Dark(White),
        Primary => Dark(Black),
        Secondary => Dark(Blue),
        Tertiary => Dark(White),
        TitlePrimary => Dark(Red),
        TitleSecondary => Dark(Yellow),
        Highlight => Dark(Red),
        HighlightInactive => Dark(Blue),
    }
}

/// Fills `palette` with the colors from the given `table`.
pub(crate) fn load_table(palette: &mut Palette, table: &toml::value::Table) {
    // TODO: use serde for that?
    // Problem: toml-rs doesn't do well with Enums...
    load_color(
        &mut palette[PaletteColor::Background],
        table.get("background"),
    );
    load_color(&mut palette[PaletteColor::Shadow], table.get("shadow"));
    load_color(&mut palette[PaletteColor::View], table.get("view"));
    load_color(&mut palette[PaletteColor::Primary], table.get("primary"));
    load_color(
        &mut palette[PaletteColor::Secondary],
        table.get("secondary"),
    );
    load_color(&mut palette[PaletteColor::Tertiary], table.get("tertiary"));
    load_color(
        &mut palette[PaletteColor::TitlePrimary],
        table.get("title_primary"),
    );
    load_color(
        &mut palette[PaletteColor::TitleSecondary],
        table.get("title_secondary"),
    );
    load_color(
        &mut palette[PaletteColor::Highlight],
        table.get("highlight"),
    );
    load_color(
        &mut palette[PaletteColor::HighlightInactive],
        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[self]
    }
}

/// Parses `value` and fills `target` if it's a valid color.
fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool {
    if let Some(value) = value {
        match *value {
            toml::Value::String(ref value) => {
                if let Some(color) = Color::parse(value) {
                    *target = color;
                    true
                } else {
                    false
                }
            }
            toml::Value::Array(ref array) => {
                array.iter().any(|item| load_color(target, Some(item)))
            }
            _ => false,
        }
    } else {
        false
    }
}