orbtk_utils/
brush.rs

1use crate::prelude::*;
2
3/// A `Brush` defines the fill pattern of shapes.
4/// The syntax allows to express fill patterns in several ways:
5///
6/// * solid colors
7/// * colors with alpha channel
8/// * gradients of colors
9/// * gradients with directions
10/// * gradients with angles
11///
12/// The string declaration of a `Brush` is composed combining the following
13/// syntax elements:
14///
15/// 1. The `color name`
16/// 2. The `gradient` string
17///    * the gradient type (linear, repeating-linear)
18///    * gradient attributes (direction-identifier, angles, color names )
19///
20/// ## Examples
21/// Here are some implementations with declarations of colors, degrees, orientations and directions.
22///
23/// ```text
24/// .foreground("white")
25/// .background("black")
26/// .background("linear-gradient(0deg, #4b6cb7, #182848)")
27/// .background("repeating-linear-gradient(0.25turn, rgba(255, 255, 0, 0.6), dodgerblue, deepskyblue)")
28/// .background("linear-gradient(-90deg, hsv(201, 94%, 80.5%), steelblue)")
29/// .background("linear-gradient(to top right, white, skyblue 60%, lightskyblue 80%, yellow 83%, yellow)")
30/// ```
31/// Read on to see how the syntax is composed.
32///
33/// ## Definition of a color name
34/// With the given implementation you can choose between three methods
35/// to define a color.
36///
37/// A. `color codes`
38///
39/// You can define the value of a color with a symbol "#" followed
40/// by letters or numbers. These numbers are in hexadecimal numeral system.
41/// The short variant will use 3 numbers , the long variant will use 6
42/// numbers.
43/// For example `#f00` will give you red. If you write `#0000ff`, you will
44/// get blue.
45/// To include an alpha channel, the short variant takes 4 numbers.
46/// If you need a yellow with 50.2% opaque, you use `#ff08`.
47/// In the long form you need 8 numbers. `#0000ff80` represents 50.2% opaque
48/// (non-premultiplied) blue.
49///
50/// B. `color function`
51///
52/// Currently the unique available functions that interpret a color are
53/// distincted with the keywords `rgb`, `hsv`, `hsb`, `hsl`. There are
54/// `alpha variants` as well. `hsb` is an alias to `hsv`.
55/// Alpha variants are coded with the keywords `rgba`, `abgr`  or `argb`.
56/// Here is an example to define a color via the function method:
57/// `hsl(197, 71%, 73%)` will provide you a pretty skyblue color.
58/// For `rgb` and `rgba` the range of the values are 0-255.
59/// Any other keyword will use floating point integers to define the color
60/// value. `hsva(0.0-360.0, 0.0-1.0, 0.0-1.0, 0.0-1.0)` is such an example.
61/// In addition you can choose to use percent values (`%` sign) for the given
62/// parameters.
63/// When appending the `%` sign to the range parameters of the `rgb` function
64/// call, the values are mapped to 0.0-100.0 (percent) or 0.0-1.0 (min/max).
65/// For all other keywords (`hsv`, `hsb`, `hsl`) you are not allowed to append
66/// the percent sign to the first parameter. If you append `%` to the following
67/// parameters, OrbTk will interpret the values in a range between `0.0-100.0`.
68///
69/// C. `color name`
70///
71/// **WIP: The given implementation is using (utils/colors.txt). This has to be adopted!!!**
72///
73/// OrbTk maintains a list of color names as constants. You may
74/// directly choose their string value inside the code.
75///
76/// Example color names are:
77///
78///  * COLOR_WHITE
79///  * COLOR_RED
80///  * COLOR_OLIVE
81///  * COLOR_LINK_WATER
82///  * COLOR_SLATE_GRAY
83///
84/// ## Definition of a gradient
85/// The syntax of a gradient definition is structured as follows:
86///
87/// * Optional parameters are inside brackets (`[]`).
88/// * Within braces (`{}`) you define the appropriate parameter value.
89/// * The pipe (`|`) is offering mutual exclusive variants
90///   e.g: degrees(deg), radians(rad) or turns(turn).
91/// * Three points (`...`) refer to multiple stops.
92///   They are respected when a gradient is rendered.
93///
94/// To understand gradient directions, imagine a line or vector that
95/// starts at a given point inside the entity and points to an
96/// imaginary target point within the same entity. Gradients will be
97/// rendered along the choosen direction to reach its target
98/// poing. Supported directions are:
99///
100///  * "to bottom"
101///  * "to bottom left"
102///  * "to bottom right"
103///  * "to left"
104///  * "to right"
105///  * "to top
106///  * "to top left"
107///  * "to top right"
108///
109/// Displacement points tell the gradient algorithm to add
110/// (`positive`) or or substract (`negative`) the given pixel numbers
111/// from the original starting point.
112///
113/// Lets look at some examples. The first one shows the
114/// structure of an angled gradient
115///
116/// ```text
117/// [repeating-]linear-gradient({Gradient-angle}{deg|rad|turn}, ...) [{X Displacement}px {Y Displacement}px], {Color} [{Stop  position}{%|px}]
118/// ```
119///
120/// The next example shows the structure of a gradient that will be
121/// rendered in a given direction
122///
123/// ```text
124/// [repeating-]linear-gradient({direction-identifier}, {initial color-name}, {terminating color-name}
125/// ```
126///
127//#[cfg(feature = "nightly")]
128//#[doc(include = "../colors.md")]
129
130#[derive(Clone, PartialEq, Debug)]
131pub enum Brush {
132    /// Paints an area with a solid color.
133    SolidColor(Color),
134
135    /// Paints an area with a gradient.
136    Gradient(Gradient),
137}
138
139impl Brush {
140    pub fn is_transparent(&self) -> bool {
141        match self {
142            Brush::SolidColor(color) => color.a() == 0,
143            _ => false,
144        }
145    }
146}
147
148impl From<Brush> for Color {
149    fn from(b: Brush) -> Color {
150        match b {
151            Brush::SolidColor(color) => color,
152            _ => Color::rgb(0, 0, 0),
153        }
154    }
155}
156
157impl From<Brush> for Gradient {
158    fn from(b: Brush) -> Gradient {
159        match b {
160            Brush::Gradient(g) => g,
161            _ => Gradient::default(),
162        }
163    }
164}
165
166impl Default for Brush {
167    fn default() -> Self {
168        Brush::SolidColor(Color::rgba(0, 0, 0, 0))
169    }
170}
171
172impl From<Color> for Brush {
173    fn from(c: Color) -> Brush {
174        Brush::SolidColor(c)
175    }
176}
177
178impl From<Gradient> for Brush {
179    fn from(g: Gradient) -> Brush {
180        Brush::Gradient(g)
181    }
182}
183
184impl From<&str> for Brush {
185    fn from(s: &str) -> Brush {
186        Expression::from(s).brush().unwrap_or_default()
187    }
188}
189
190impl From<String> for Brush {
191    fn from(s: String) -> Brush {
192        Self::from(&s[..])
193    }
194}
195
196impl From<Value> for Brush {
197    fn from(v: Value) -> Self {
198        let value = v.get::<String>();
199        Brush::from(value)
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    //  use crate::prelude::*;
206    // todo: tbd after brush struct is finished
207}