ferroui_base/media/
solid_color_brush.rs1use 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#[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 pub fn construct() -> Self {
43 Self { base: Brush::construct() }
44 }
45
46 pub fn new() -> Ref<Self> {
47 instantiate(Self::construct())
48 }
49
50 pub fn with_color(color: Color) -> Ref<Self> {
52 Self::with_color_and_opacity(color, 1.0)
53 }
54
55 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 pub fn from_uint32(color: u32) -> Ref<Self> {
65 Self::with_color(Color::from_uint32(color))
66 }
67
68 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 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 pub fn to_immutable(&self) -> Rc<dyn IImmutableBrush> {
89 Rc::new(ImmutableSolidColorBrush::from_brush(&RefAdapter(self.to_ref())))
90 }
91}
92
93impl 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}