Skip to main content

ferroui_base/rendering/composition/
layer_visual.rs

1use super::generated::{LayerVisualHooks, LayerVisualProps};
2use super::server::ServerLayerVisual;
3use super::visual::CompositionVisualKind;
4use super::{CompositionBrush, CompositionEffectBrush, CompositionVisual, Compositor, DropShadow, ICompositionObject};
5use std::ops::Deref;
6use std::rc::Rc;
7
8impl LayerVisualHooks for CompositionVisual {}
9
10/// A container visual whose children are composed into one offscreen layer,
11/// which is then drawn with the opacity of the visual and its shadow (WinUI
12/// `Microsoft.UI.Composition.LayerVisual`).
13///
14/// The shadow of a layer visual follows the alpha of the composed children
15/// where the drawing context can draw a drop shadow of a layer (the Skia
16/// and Vello backends); elsewhere it is the box shadow of the rectangle of
17/// the visual, as the shadow of a sprite visual.
18///
19/// The effect (an effect brush) is applied to the composed children: they
20/// are the first source parameter of its graph, and the rest of the graph
21/// is drawn around them (a blur pushes the blur effect of the drawing
22/// context around the layer, a composite draws its other sources under and
23/// over it).
24///
25/// Like a sprite visual, a layer visual does not clip to its bounds when it
26/// is created (`clip_to_bounds` is `false`).
27#[derive(Clone)]
28pub struct LayerVisual(Rc<CompositionVisual>);
29
30impl Deref for LayerVisual {
31    type Target = Rc<CompositionVisual>;
32
33    fn deref(&self) -> &Rc<CompositionVisual> {
34        &self.0
35    }
36}
37
38impl LayerVisual {
39    pub(crate) fn new(compositor: &Rc<Compositor>) -> LayerVisual {
40        let visual = CompositionVisual::create(
41            compositor,
42            CompositionVisualKind::Layer(LayerVisualProps::new()),
43            || Box::new(ServerLayerVisual::new()),
44        );
45        // A WinUI visual has no implicit clip.
46        visual.set_clip_to_bounds(false);
47        LayerVisual(visual)
48    }
49
50    /// The handle of `visual` as a layer visual, if it is one.
51    pub fn from_visual(visual: &Rc<CompositionVisual>) -> Option<LayerVisual> {
52        matches!(visual.kind, CompositionVisualKind::Layer(_)).then(|| LayerVisual(visual.clone()))
53    }
54
55    /// The visual as a composition visual.
56    pub fn visual(&self) -> &Rc<CompositionVisual> {
57        &self.0
58    }
59
60    fn props(&self) -> &LayerVisualProps {
61        match &self.0.kind {
62            CompositionVisualKind::Layer(props) => props,
63            _ => unreachable!("a layer visual handle wraps a layer visual"),
64        }
65    }
66
67    /// The shadow of the composed layer.
68    pub fn shadow(&self) -> Option<Rc<DropShadow>> {
69        self.props().shadow().and_then(|shadow| shadow.into_any_rc().downcast::<DropShadow>().ok())
70    }
71
72    pub fn set_shadow(&self, value: Option<Rc<DropShadow>>) {
73        self.props().set_shadow(&*self.0, value.map(|shadow| shadow as Rc<dyn ICompositionObject>))
74    }
75
76    /// `Effect`: the effect brush applied to the composed children, which
77    /// are the first source parameter of its graph. (The upstream `effect`
78    /// of every visual, an image effect, is `visual().effect()`.)
79    pub fn effect(&self) -> Option<CompositionEffectBrush> {
80        self.props()
81            .effect_brush()
82            .and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
83            .and_then(|brush| CompositionEffectBrush::from_brush(&brush))
84    }
85
86    pub fn set_effect(&self, value: Option<CompositionEffectBrush>) {
87        self.props().set_effect_brush(
88            &*self.0,
89            value.map(|brush| brush.brush().clone() as Rc<dyn ICompositionObject>),
90        )
91    }
92}