ferroui_base/media/
gradient_brush.rs1use crate::media::media_collection::track_item_property_changed;
2use crate::media::immutable::ImmutableGradientStop;
3use crate::media::{Brush, BrushImpl, BrushImplExt, GradientSpreadMethod, GradientStops, IImmutableBrush};
4use crate::reactive::IDisposable;
5use crate::rendering::composition::transport::BatchStreamWriter;
6use crate::rendering::composition::Compositor;
7use crate::{
8 ferro_class, ferro_property, FerroObjectImpl, FerroObjectImplExt, FerroProperty, FerroPropertyChangedEventArgs,
9 StyledProperty,
10};
11use std::cell::RefCell;
12use std::rc::Rc;
13
14#[repr(C)]
16pub struct GradientBrush {
17 base: Brush,
18 gradient_stops_collection_subscription: RefCell<Option<Rc<dyn IDisposable>>>,
19 gradient_stops_subscription: RefCell<Option<Rc<dyn IDisposable>>>,
20}
21
22ferro_class! {
23 GradientBrush: Brush, virtuals GradientBrushImpl: BrushImpl {
24 fn to_immutable(this) -> Rc<dyn IImmutableBrush>;
26 }
27}
28
29impl FerroObjectImpl for GradientBrush {
30 fn constructed(this: &Self) {
31 Self::parent_constructed(this);
32 this.set_gradient_stops(GradientStops::new());
33 }
34
35 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
36 if change.property() == Self::gradient_stops_property().as_property() {
37 let (old_value, new_value) = change.get_old_and_new_value::<Option<GradientStops>>();
38
39 if old_value.is_some() {
40 if let Some(subscription) = this.gradient_stops_collection_subscription.take() {
41 subscription.dispose();
42 }
43 if let Some(subscription) = this.gradient_stops_subscription.take() {
44 subscription.dispose();
45 }
46 }
47
48 if let Some(new_value) = new_value {
49 let weak = this.to_ref().downgrade();
50 let collection_subscription = new_value.collection_changed({
51 let weak = weak.clone();
52 move |_| {
53 if let Some(this) = weak.upgrade() {
54 this.register_for_serialization();
55 this.raise_invalidated();
56 }
57 }
58 });
59 *this.gradient_stops_collection_subscription.borrow_mut() = Some(collection_subscription);
60
61 let subscription = track_item_property_changed(&new_value, move || {
62 if let Some(this) = weak.upgrade() {
63 this.register_for_serialization();
64 this.raise_invalidated();
65 }
66 });
67 *this.gradient_stops_subscription.borrow_mut() = Some(subscription);
68 }
69 }
70
71 Self::parent_on_property_changed(this, change);
72 }
73}
74
75impl BrushImpl for GradientBrush {
76 fn serialize_changes(this: &Self, c: &Compositor, writer: &mut BatchStreamWriter<'_>) {
77 Self::parent_serialize_changes(this, c, writer);
78 writer.write(this.spread_method());
79 let gradient_stops = this.gradient_stops();
80 writer.write(gradient_stops.len() as i32);
81 for stop in gradient_stops.iter() {
82 writer.write_value(Some(ImmutableGradientStop::new(stop.offset(), stop.color())));
84 }
85 }
86}
87
88impl GradientBrushImpl for GradientBrush {
89 fn to_immutable(_this: &Self) -> Rc<dyn IImmutableBrush> {
90 panic!("GradientBrush is abstract: 'to_immutable' must be implemented by the deriving class")
91 }
92}
93
94crate::ferro_properties! { impl GradientBrush {
95 ferro_property!(pub fn spread_method_property() -> StyledProperty<GradientSpreadMethod> {
96 FerroProperty::register::<GradientBrush, _>("SpreadMethod", GradientSpreadMethod::Pad)
97 });
98
99 ferro_property!(pub fn gradient_stops_property() -> StyledProperty<Option<GradientStops>> {
100 FerroProperty::register::<GradientBrush, _>("GradientStops", None)
101 });
102} }
103
104impl GradientBrush {
105 pub fn construct() -> Self {
107 Self {
108 base: Brush::construct(),
109 gradient_stops_collection_subscription: RefCell::new(None),
110 gradient_stops_subscription: RefCell::new(None),
111 }
112 }
113
114 pub fn spread_method(&self) -> GradientSpreadMethod {
117 self.get_value(Self::spread_method_property())
118 }
119
120 pub fn set_spread_method(&self, value: GradientSpreadMethod) {
121 self.set_value(Self::spread_method_property(), value)
122 }
123
124 pub fn gradient_stops(&self) -> GradientStops {
126 self.get_value(Self::gradient_stops_property()).expect("GradientStops is not set")
127 }
128
129 pub fn set_gradient_stops(&self, value: GradientStops) {
130 self.set_value(Self::gradient_stops_property(), Some(value))
131 }
132}