ferroui_base/rendering/composition/brushes/
composition_effect_brush.rs1use super::composition_brush::{CompositionBrush, CompositionBrushKind};
6use super::server_composition_effect_brush::EffectBrushChanges;
7use super::{ServerCompositionBackdropBrush, ServerCompositionEffectBrush, ServerCompositionHostBackdropBrush};
8use crate::rendering::composition::effects::{EffectGraph, EffectPropertyValue};
9use crate::rendering::composition::generated::CompositionBrushProps;
10use crate::rendering::composition::transport::{BatchStreamWriter, IRegisterForSerialization};
11use crate::rendering::composition::{AsCompositionObject, CompositionPropertySet, Compositor};
12use std::cell::{Cell, RefCell};
13use std::ops::Deref;
14use std::rc::Rc;
15use std::sync::Arc;
16
17pub(crate) struct CompositionEffectBrushData {
21 pub(super) brush: CompositionBrushProps,
22 pub(super) graph: Arc<EffectGraph>,
23 sources: RefCell<Vec<(String, Option<Rc<CompositionBrush>>)>>,
25 sources_changed: Cell<bool>,
26 properties_sent: Cell<bool>,
28}
29
30impl CompositionEffectBrushData {
31 fn new(graph: Arc<EffectGraph>) -> Self {
32 let sources = graph.parameters.iter().map(|name| (name.clone(), None)).collect();
33 Self {
34 brush: CompositionBrushProps::new(),
35 graph,
36 sources: RefCell::new(sources),
37 sources_changed: Cell::new(false),
38 properties_sent: Cell::new(false),
39 }
40 }
41
42 pub(super) fn serialize_changes_core(&self, host: &CompositionBrush, writer: &mut BatchStreamWriter<'_>) {
45 self.brush.serialize_changes_core(host, writer);
46 let properties = if self.properties_sent.replace(true) {
47 None
48 } else {
49 host.object().properties().as_composition_object().server()
50 };
51 let sources = self.sources_changed.replace(false).then(|| {
52 self.sources
53 .borrow()
54 .iter()
55 .map(|(name, brush)| (name.clone(), brush.as_ref().map(|brush| brush.server())))
56 .collect::<Vec<_>>()
57 });
58 let changes = (properties.is_some() || sources.is_some()).then_some(EffectBrushChanges { properties, sources });
59 writer.write_value(changes);
60 }
61}
62
63#[derive(Clone)]
91pub struct CompositionEffectBrush(Rc<CompositionBrush>);
92
93impl Deref for CompositionEffectBrush {
94 type Target = Rc<CompositionBrush>;
95
96 fn deref(&self) -> &Rc<CompositionBrush> {
97 &self.0
98 }
99}
100
101impl CompositionEffectBrush {
102 pub(crate) fn new(compositor: &Rc<Compositor>, graph: Arc<EffectGraph>) -> CompositionEffectBrush {
103 let server_graph = graph.clone();
104 let brush = CompositionBrush::create(
105 compositor,
106 CompositionBrushKind::Effect(CompositionEffectBrushData::new(graph.clone())),
107 move |c| ServerCompositionEffectBrush::new(c, server_graph),
108 );
109 brush.initialize_defaults();
110 let properties = brush.object().properties();
113 for (key, value) in &graph.animatable {
114 match *value {
115 EffectPropertyValue::Scalar(value) => properties.insert_scalar(key, value),
116 EffectPropertyValue::Color(value) => properties.insert_color(key, value),
117 }
118 }
119 brush.register_for_serialization();
120 CompositionEffectBrush(brush)
121 }
122
123 pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionEffectBrush> {
125 matches!(brush.kind, CompositionBrushKind::Effect(_)).then(|| CompositionEffectBrush(brush.clone()))
126 }
127
128 fn data(&self) -> &CompositionEffectBrushData {
129 match &self.0.kind {
130 CompositionBrushKind::Effect(data) => data,
131 _ => unreachable!("an effect brush handle wraps an effect brush"),
132 }
133 }
134
135 pub fn brush(&self) -> &Rc<CompositionBrush> {
137 &self.0
138 }
139
140 pub fn properties(&self) -> Rc<CompositionPropertySet> {
145 self.0.object().properties()
146 }
147
148 pub fn source_parameter_names(&self) -> Vec<String> {
151 self.data().graph.parameters.clone()
152 }
153
154 pub fn get_source_parameter(&self, name: &str) -> Option<Rc<CompositionBrush>> {
157 self.data().sources.borrow().iter().find(|(existing, _)| existing == name).and_then(|(_, brush)| brush.clone())
158 }
159
160 pub fn set_source_parameter(&self, name: &str, source: Option<Rc<CompositionBrush>>) {
167 let data = self.data();
168 if data.graph.is_loaded() && !data.graph.has_parameter(name) {
169 panic!("the effect has no source parameter named {name}");
170 }
171 {
172 let mut sources = data.sources.borrow_mut();
173 match sources.iter_mut().find(|(existing, _)| existing == name) {
174 Some(entry) => entry.1 = source,
175 None => sources.push((name.to_owned(), source)),
176 }
177 }
178 data.sources_changed.set(true);
179 self.0.register_for_serialization();
180 }
181}
182
183#[derive(Clone)]
192pub struct CompositionBackdropBrush(Rc<CompositionBrush>);
193
194impl Deref for CompositionBackdropBrush {
195 type Target = Rc<CompositionBrush>;
196
197 fn deref(&self) -> &Rc<CompositionBrush> {
198 &self.0
199 }
200}
201
202impl CompositionBackdropBrush {
203 pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionBackdropBrush {
204 let brush = CompositionBrush::create(
205 compositor,
206 CompositionBrushKind::Backdrop(CompositionBrushProps::new()),
207 |c| ServerCompositionBackdropBrush::new(c),
208 );
209 brush.initialize_defaults();
210 CompositionBackdropBrush(brush)
211 }
212
213 pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionBackdropBrush> {
215 matches!(brush.kind, CompositionBrushKind::Backdrop(_)).then(|| CompositionBackdropBrush(brush.clone()))
216 }
217}
218
219#[derive(Clone)]
229pub struct CompositionHostBackdropBrush(Rc<CompositionBrush>);
230
231impl Deref for CompositionHostBackdropBrush {
232 type Target = Rc<CompositionBrush>;
233
234 fn deref(&self) -> &Rc<CompositionBrush> {
235 &self.0
236 }
237}
238
239impl CompositionHostBackdropBrush {
240 pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionHostBackdropBrush {
241 let brush = CompositionBrush::create(
242 compositor,
243 CompositionBrushKind::HostBackdrop(CompositionBrushProps::new()),
244 |c| ServerCompositionHostBackdropBrush::new(c),
245 );
246 brush.initialize_defaults();
247 CompositionHostBackdropBrush(brush)
248 }
249
250 pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionHostBackdropBrush> {
252 matches!(brush.kind, CompositionBrushKind::HostBackdrop(_)).then(|| CompositionHostBackdropBrush(brush.clone()))
253 }
254}