Skip to main content

ferroui_base/rendering/composition/
sprite_visual.rs

1use super::generated::{SpriteVisualHooks, SpriteVisualProps};
2use super::server::ServerSpriteVisual;
3use super::visual::CompositionVisualKind;
4use super::{CompositionBrush, CompositionVisual, Compositor, DropShadow, ICompositionObject};
5use std::ops::Deref;
6use std::rc::Rc;
7
8impl SpriteVisualHooks for CompositionVisual {}
9
10/// A visual that paints its size with a composition brush and casts a
11/// shadow (WinUI `Microsoft.UI.Composition.SpriteVisual`): the shadow of its
12/// rectangle, then the brush over `(0, 0, size)`, then its children.
13///
14/// The brush is any [`CompositionBrush`]: the colour and gradient brushes
15/// fill the rectangle, a
16/// [`CompositionSurfaceBrush`](super::CompositionSurfaceBrush) lays out its
17/// surface in it. A change of the brush or of the shadow, an animation
18/// included, redraws the visual.
19///
20/// Unlike the other visuals of the compositor, a sprite visual does not
21/// clip to its bounds when it is created (`clip_to_bounds` is `false`), as
22/// a WinUI visual: its shadow and its children may extend beyond its size.
23#[derive(Clone)]
24pub struct SpriteVisual(Rc<CompositionVisual>);
25
26impl Deref for SpriteVisual {
27    type Target = Rc<CompositionVisual>;
28
29    fn deref(&self) -> &Rc<CompositionVisual> {
30        &self.0
31    }
32}
33
34impl SpriteVisual {
35    pub(crate) fn new(compositor: &Rc<Compositor>) -> SpriteVisual {
36        let visual = CompositionVisual::create(
37            compositor,
38            CompositionVisualKind::Sprite(SpriteVisualProps::new()),
39            || Box::new(ServerSpriteVisual::new()),
40        );
41        // A WinUI visual has no implicit clip.
42        visual.set_clip_to_bounds(false);
43        SpriteVisual(visual)
44    }
45
46    /// The handle of `visual` as a sprite visual, if it is one.
47    pub fn from_visual(visual: &Rc<CompositionVisual>) -> Option<SpriteVisual> {
48        matches!(visual.kind, CompositionVisualKind::Sprite(_)).then(|| SpriteVisual(visual.clone()))
49    }
50
51    /// The visual as a composition visual.
52    pub fn visual(&self) -> &Rc<CompositionVisual> {
53        &self.0
54    }
55
56    fn props(&self) -> &SpriteVisualProps {
57        match &self.0.kind {
58            CompositionVisualKind::Sprite(props) => props,
59            _ => unreachable!("a sprite visual handle wraps a sprite visual"),
60        }
61    }
62
63    /// The brush the visual paints its size with.
64    pub fn brush(&self) -> Option<Rc<CompositionBrush>> {
65        self.props().brush().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
66    }
67
68    pub fn set_brush(&self, value: Option<Rc<CompositionBrush>>) {
69        self.props().set_brush(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
70    }
71
72    /// The shadow of the visual.
73    pub fn shadow(&self) -> Option<Rc<DropShadow>> {
74        self.props().shadow().and_then(|shadow| shadow.into_any_rc().downcast::<DropShadow>().ok())
75    }
76
77    pub fn set_shadow(&self, value: Option<Rc<DropShadow>>) {
78        self.props().set_shadow(&*self.0, value.map(|shadow| shadow as Rc<dyn ICompositionObject>))
79    }
80}