use super::composition_brush::{CompositionBrush, CompositionBrushKind};
use super::server_composition_effect_brush::EffectBrushChanges;
use super::{ServerCompositionBackdropBrush, ServerCompositionEffectBrush, ServerCompositionHostBackdropBrush};
use crate::rendering::composition::effects::{EffectGraph, EffectPropertyValue};
use crate::rendering::composition::generated::CompositionBrushProps;
use crate::rendering::composition::transport::{BatchStreamWriter, IRegisterForSerialization};
use crate::rendering::composition::{AsCompositionObject, CompositionPropertySet, Compositor};
use std::cell::{Cell, RefCell};
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
pub(crate) struct CompositionEffectBrushData {
pub(super) brush: CompositionBrushProps,
pub(super) graph: Arc<EffectGraph>,
sources: RefCell<Vec<(String, Option<Rc<CompositionBrush>>)>>,
sources_changed: Cell<bool>,
properties_sent: Cell<bool>,
}
impl CompositionEffectBrushData {
fn new(graph: Arc<EffectGraph>) -> Self {
let sources = graph.parameters.iter().map(|name| (name.clone(), None)).collect();
Self {
brush: CompositionBrushProps::new(),
graph,
sources: RefCell::new(sources),
sources_changed: Cell::new(false),
properties_sent: Cell::new(false),
}
}
pub(super) fn serialize_changes_core(&self, host: &CompositionBrush, writer: &mut BatchStreamWriter<'_>) {
self.brush.serialize_changes_core(host, writer);
let properties = if self.properties_sent.replace(true) {
None
} else {
host.object().properties().as_composition_object().server()
};
let sources = self.sources_changed.replace(false).then(|| {
self.sources
.borrow()
.iter()
.map(|(name, brush)| (name.clone(), brush.as_ref().map(|brush| brush.server())))
.collect::<Vec<_>>()
});
let changes = (properties.is_some() || sources.is_some()).then_some(EffectBrushChanges { properties, sources });
writer.write_value(changes);
}
}
#[derive(Clone)]
pub struct CompositionEffectBrush(Rc<CompositionBrush>);
impl Deref for CompositionEffectBrush {
type Target = Rc<CompositionBrush>;
fn deref(&self) -> &Rc<CompositionBrush> {
&self.0
}
}
impl CompositionEffectBrush {
pub(crate) fn new(compositor: &Rc<Compositor>, graph: Arc<EffectGraph>) -> CompositionEffectBrush {
let server_graph = graph.clone();
let brush = CompositionBrush::create(
compositor,
CompositionBrushKind::Effect(CompositionEffectBrushData::new(graph.clone())),
move |c| ServerCompositionEffectBrush::new(c, server_graph),
);
brush.initialize_defaults();
let properties = brush.object().properties();
for (key, value) in &graph.animatable {
match *value {
EffectPropertyValue::Scalar(value) => properties.insert_scalar(key, value),
EffectPropertyValue::Color(value) => properties.insert_color(key, value),
}
}
brush.register_for_serialization();
CompositionEffectBrush(brush)
}
pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionEffectBrush> {
matches!(brush.kind, CompositionBrushKind::Effect(_)).then(|| CompositionEffectBrush(brush.clone()))
}
fn data(&self) -> &CompositionEffectBrushData {
match &self.0.kind {
CompositionBrushKind::Effect(data) => data,
_ => unreachable!("an effect brush handle wraps an effect brush"),
}
}
pub fn brush(&self) -> &Rc<CompositionBrush> {
&self.0
}
pub fn properties(&self) -> Rc<CompositionPropertySet> {
self.0.object().properties()
}
pub fn source_parameter_names(&self) -> Vec<String> {
self.data().graph.parameters.clone()
}
pub fn get_source_parameter(&self, name: &str) -> Option<Rc<CompositionBrush>> {
self.data().sources.borrow().iter().find(|(existing, _)| existing == name).and_then(|(_, brush)| brush.clone())
}
pub fn set_source_parameter(&self, name: &str, source: Option<Rc<CompositionBrush>>) {
let data = self.data();
if data.graph.is_loaded() && !data.graph.has_parameter(name) {
panic!("the effect has no source parameter named {name}");
}
{
let mut sources = data.sources.borrow_mut();
match sources.iter_mut().find(|(existing, _)| existing == name) {
Some(entry) => entry.1 = source,
None => sources.push((name.to_owned(), source)),
}
}
data.sources_changed.set(true);
self.0.register_for_serialization();
}
}
#[derive(Clone)]
pub struct CompositionBackdropBrush(Rc<CompositionBrush>);
impl Deref for CompositionBackdropBrush {
type Target = Rc<CompositionBrush>;
fn deref(&self) -> &Rc<CompositionBrush> {
&self.0
}
}
impl CompositionBackdropBrush {
pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionBackdropBrush {
let brush = CompositionBrush::create(
compositor,
CompositionBrushKind::Backdrop(CompositionBrushProps::new()),
|c| ServerCompositionBackdropBrush::new(c),
);
brush.initialize_defaults();
CompositionBackdropBrush(brush)
}
pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionBackdropBrush> {
matches!(brush.kind, CompositionBrushKind::Backdrop(_)).then(|| CompositionBackdropBrush(brush.clone()))
}
}
#[derive(Clone)]
pub struct CompositionHostBackdropBrush(Rc<CompositionBrush>);
impl Deref for CompositionHostBackdropBrush {
type Target = Rc<CompositionBrush>;
fn deref(&self) -> &Rc<CompositionBrush> {
&self.0
}
}
impl CompositionHostBackdropBrush {
pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionHostBackdropBrush {
let brush = CompositionBrush::create(
compositor,
CompositionBrushKind::HostBackdrop(CompositionBrushProps::new()),
|c| ServerCompositionHostBackdropBrush::new(c),
);
brush.initialize_defaults();
CompositionHostBackdropBrush(brush)
}
pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionHostBackdropBrush> {
matches!(brush.kind, CompositionBrushKind::HostBackdrop(_)).then(|| CompositionHostBackdropBrush(brush.clone()))
}
}