Skip to main content

ferroui_base/media/
solid_color_brush.rs

1use crate::media::ref_adapter::RefAdapter;
2use crate::media::immutable::ImmutableSolidColorBrush;
3use crate::media::{Brush, BrushImpl, BrushImplExt, Color, IImmutableBrush, ServerBrushFactory};
4use crate::rendering::composition::generated::ServerCompositionSimpleSolidColorBrushProps;
5use crate::rendering::composition::server::ServerCompositionSimpleSolidColorBrush;
6use crate::rendering::composition::transport::BatchStreamWriter;
7use crate::rendering::composition::Compositor;
8use crate::utilities::FormatError;
9use crate::{ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl, FerroProperty, Ref, StyledProperty};
10use std::fmt;
11use std::rc::Rc;
12
13/// Fills an area with a solid color.
14#[repr(C)]
15pub struct SolidColorBrush {
16    base: Brush,
17}
18
19ferro_class!(SolidColorBrush: Brush);
20crate::ferro_class_info!(SolidColorBrush { new: SolidColorBrush::new });
21ferro_impl_classes!(SolidColorBrush: FerroObjectImpl);
22
23impl BrushImpl for SolidColorBrush {
24    fn factory(_this: &Self) -> Option<ServerBrushFactory> {
25        Some(|c| ServerCompositionSimpleSolidColorBrush::new(c))
26    }
27
28    fn serialize_changes(this: &Self, c: &Compositor, writer: &mut BatchStreamWriter<'_>) {
29        Self::parent_serialize_changes(this, c, writer);
30        ServerCompositionSimpleSolidColorBrushProps::serialize_all_changes(writer, this.color());
31    }
32}
33
34crate::ferro_properties! { impl SolidColorBrush {
35    ferro_property!(pub fn color_property() -> StyledProperty<Color> {
36        FerroProperty::register::<SolidColorBrush, _>("Color", Color::default())
37    });
38} }
39
40impl SolidColorBrush {
41    /// Creates the class data.
42    pub fn construct() -> Self {
43        Self { base: Brush::construct() }
44    }
45
46    pub fn new() -> Ref<Self> {
47        instantiate(Self::construct())
48    }
49
50    /// Creates a brush with the given color.
51    pub fn with_color(color: Color) -> Ref<Self> {
52        Self::with_color_and_opacity(color, 1.0)
53    }
54
55    /// Creates a brush with the given color and opacity.
56    pub fn with_color_and_opacity(color: Color, opacity: f64) -> Ref<Self> {
57        let result = Self::new();
58        result.set_color(color);
59        result.set_opacity(opacity);
60        result
61    }
62
63    /// Creates a brush with the color given as an `0xAARRGGBB` value.
64    pub fn from_uint32(color: u32) -> Ref<Self> {
65        Self::with_color(Color::from_uint32(color))
66    }
67
68    /// The color of the brush.
69    pub fn color(&self) -> Color {
70        self.get_value(Self::color_property())
71    }
72
73    pub fn set_color(&self, value: Color) {
74        self.set_value(Self::color_property(), value)
75    }
76
77    /// Parses a brush string.
78    pub fn parse(s: &str) -> Result<Ref<SolidColorBrush>, FormatError> {
79        let brush = Brush::parse(s)?;
80        let solid = brush.as_solid_color_brush().expect("parsed brushes are solid color brushes");
81        Ok(match brush.as_object().and_then(|o| o.downcast_ref::<SolidColorBrush>()) {
82            Some(solid) => solid.to_ref(),
83            None => SolidColorBrush::with_color(solid.color()),
84        })
85    }
86
87    /// Creates an immutable clone of the brush.
88    pub fn to_immutable(&self) -> Rc<dyn IImmutableBrush> {
89        Rc::new(ImmutableSolidColorBrush::from_brush(&RefAdapter(self.to_ref())))
90    }
91}
92
93/// Writes the brush's color.
94impl fmt::Display for SolidColorBrush {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        fmt::Display::fmt(&self.color(), f)
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::media::Colors;
104    use std::cell::Cell;
105
106    #[test]
107    fn changing_color_raises_invalidated() {
108        let target = SolidColorBrush::with_color(Colors::RED);
109        let raised = Rc::new(Cell::new(false));
110        let r = raised.clone();
111        target.invalidated(move || r.set(true));
112        target.set_color(Colors::GREEN);
113        assert!(raised.get());
114    }
115
116    #[test]
117    fn parse_creates_mutable_brush() {
118        let brush = SolidColorBrush::parse("#40ff8844").unwrap();
119        assert_eq!(Color::from_uint32(0x40ff8844), brush.color());
120        assert_eq!("Red", SolidColorBrush::parse("red").unwrap().to_string());
121        assert!(SolidColorBrush::parse("nope").is_err());
122    }
123
124    #[test]
125    fn to_immutable_copies_values() {
126        let brush = SolidColorBrush::with_color_and_opacity(Colors::RED, 0.5);
127        let immutable = brush.to_immutable();
128        assert_eq!(0.5, immutable.opacity());
129        assert_eq!(Some(Colors::RED), immutable.as_solid_color_brush().map(|b| b.color()));
130    }
131}