css_style/
background.rs

1use crate::{color::Color, unit::*, Style, StyleUpdater};
2use derive_rich::Rich;
3
4/// ```
5/// use css_style::{prelude::*, Color, color, unit::em};
6///
7/// style()
8///     .and_background(|conf| {
9///         conf.image("/bg/fullpage.png")
10///             .color(color::named::WHITE)
11///             .scroll()
12///     });
13/// ```
14#[derive(Rich, Clone, Debug, PartialEq, Default)]
15pub struct Background {
16    #[rich(write)]
17    pub color: Option<Color>,
18    // TODO: support multiple images
19    #[rich(write, value_fns = { empty = Image::None })]
20    pub image: Option<Image>,
21    #[rich(value_fns = {
22        repeat_x = Repeat::RepeatX,
23        repeat_y = Repeat::RepeatY,
24        repeat = Repeat::Repeat,
25        repeat_with_space = Repeat::Space,
26        repeat_round = Repeat::Round,
27        no_repeat = Repeat::NoRepeat,
28        initial_repeat = Repeat::Initial,
29        inherit_repeat = Repeat::Inherit,
30    })]
31    pub repeat: Option<Repeat>,
32    #[rich(write(rename = attachment), value_fns = {
33        scroll = Attachment::Scroll,
34        fixed = Attachment::Fixed,
35        local = Attachment::Local,
36        initial_attachment = Attachment::Initial,
37        inherit_attachment = Attachment::Inherit,
38    })]
39    // #[derive(Clone, Debug, PartialEq, Display, From)]
40    // pub enum Position {
41    //     #[display(fmt = "{} {}", _0, _1)]
42    //     #[from]
43    //     Percent(Percent, Percent),
44    //     #[display(fmt = "{} {}", _0, _1)]
45    //     #[from]
46    //     Placement(Horizontal, Vertical),
47    // }
48    pub attachment: Option<Attachment>,
49    #[rich(write(rename = position), value_fns = {
50        center_top = (Horizontal::Center, Vertical::Top(None)),
51        center = (Horizontal::Center, Vertical::Center),
52        center_bottom = (Horizontal::Center, Vertical::Bottom(None)),
53        left_top = (Horizontal::Left(None), Vertical::Top(None)),
54        left_center = (Horizontal::Left(None), Vertical::Center),
55        left_bottom = (Horizontal::Left(None), Vertical::Bottom(None)),
56        right_top = (Horizontal::Right(None), Vertical::Top(None)),
57        right_center = (Horizontal::Right(None), Vertical::Center),
58        right_bottom = (Horizontal::Right(None), Vertical::Bottom(None)),
59    })]
60    pub position: Option<Position>,
61    #[rich(write(rename = clip), value_fns = {
62        fill_under_border = Clip::BorderBox,
63        fill_inside_border = Clip::PaddingBox,
64        fill_under_content = Clip::ContentBox,
65    })]
66    pub clip: Option<Clip>,
67    #[rich(write(rename = origin), value_fns = {
68        image_fill_under_border = Origin::BorderBox,
69        image_inside_border = Origin::PaddingBox,
70        image_under_content = Origin::ContentBox,
71    })]
72    pub origin: Option<Origin>,
73    #[rich(write(rename = size), value_fns = {
74        full = (1.0, 1.0),
75        half = (0.5, 0.5),
76        quarter = (0.25, 0.25),
77        auto_size = Size::Auto,
78        cover = Size::Cover,
79        contain = Size::Contain,
80    })]
81    pub size: Option<Size>,
82}
83
84impl<T: Into<Color>> From<T> for Background {
85    fn from(source: T) -> Self {
86        Background::default().color(source.into())
87    }
88}
89
90impl StyleUpdater for Background {
91    fn update_style(self, style: Style) -> Style {
92        style
93            .try_insert("background-color", self.color)
94            .try_insert("background-image", self.image.as_ref())
95            .try_insert("background-repeat", self.repeat)
96            .try_insert("background-attachment", self.attachment)
97            .try_insert("background-position", self.position)
98    }
99}
100
101#[derive(Clone, Debug, PartialEq, Display, From)]
102pub enum Image {
103    #[display(fmt = "none")]
104    None,
105    #[display(fmt = "url({})", _0)]
106    #[from(forward)]
107    Url(String),
108}
109
110#[derive(Clone, Copy, Debug, PartialEq, Display, From)]
111pub enum Repeat {
112    #[display(fmt = "repeat-x")]
113    RepeatX,
114    #[display(fmt = "repeat-y")]
115    RepeatY,
116    #[display(fmt = "repeat")]
117    Repeat,
118    #[display(fmt = "space")]
119    Space,
120    #[display(fmt = "round")]
121    Round,
122    #[display(fmt = "no-repeat")]
123    NoRepeat,
124    #[display(fmt = "initial")]
125    Initial,
126    #[display(fmt = "inherit")]
127    Inherit,
128}
129
130#[derive(Clone, Copy, Debug, PartialEq, Display, From)]
131pub enum Attachment {
132    #[display(fmt = "scroll")]
133    Scroll,
134    #[display(fmt = "fixed")]
135    Fixed,
136    #[display(fmt = "local")]
137    Local,
138    #[display(fmt = "initial")]
139    Initial,
140    #[display(fmt = "inherit")]
141    Inherit,
142}
143
144fn display_helper(v: &Option<impl ToString>) -> String {
145    v.as_ref()
146        .map_or("".into(), |s| format!(" {}", s.to_string()))
147}
148
149#[derive(Clone, Debug, PartialEq, Display)]
150pub enum Horizontal {
151    #[display(fmt = "center")]
152    Center,
153    #[display(fmt = "left{}", "display_helper(_0)")]
154    Left(Option<Length>),
155    #[display(fmt = "right{}", "display_helper(_0)")]
156    Right(Option<Length>),
157}
158
159#[derive(Clone, Debug, PartialEq, Display)]
160pub enum Vertical {
161    #[display(fmt = "center")]
162    Center,
163    #[display(fmt = "top{}", "display_helper(_0)")]
164    Top(Option<Length>),
165    #[display(fmt = "bottom{}", "display_helper(_0)")]
166    Bottom(Option<Length>),
167}
168
169#[derive(Clone, Debug, PartialEq, Display, From)]
170pub enum Position {
171    #[display(fmt = "{} {}", _0, _1)]
172    #[from]
173    Percent(Percent, Percent),
174    #[display(fmt = "{} {}", _0, _1)]
175    #[from]
176    Placement(Horizontal, Vertical),
177}
178
179impl From<(f32, f32)> for Position {
180    fn from((hor, ver): (f32, f32)) -> Self {
181        Position::Percent(hor.into(), ver.into())
182    }
183}
184
185#[derive(Clone, Copy, Debug, PartialEq, Display, From)]
186pub enum Box {
187    #[display(fmt = "border-box")]
188    BorderBox,
189    #[display(fmt = "padding-box")]
190    PaddingBox,
191    #[display(fmt = "content-box")]
192    ContentBox,
193    #[display(fmt = "initial")]
194    Initial,
195    #[display(fmt = "inherit")]
196    Inherit,
197}
198
199pub type Clip = Box;
200pub type Origin = Box;
201
202#[derive(Clone, Debug, PartialEq, Display, From)]
203pub enum Size {
204    #[display(fmt = "{} {}", _0, _1)]
205    WidthHeight(LengthPercent, LengthPercent),
206    #[display(fmt = "auto")]
207    Auto,
208    #[display(fmt = "cover")]
209    Cover,
210    #[display(fmt = "contain")]
211    Contain,
212    #[display(fmt = "initial")]
213    Initial,
214}
215
216impl From<(f32, f32)> for Size {
217    fn from((width, height): (f32, f32)) -> Self {
218        Self::WidthHeight(width.into(), height.into())
219    }
220}