Skip to main content

ferroui_base/rendering/composition/
shape_visual.rs

1use super::generated::{ShapeVisualHooks, ShapeVisualProps};
2use super::server::ServerShapeVisual;
3use super::visual::CompositionVisualKind;
4use super::{
5    CompositionShapeCollection, CompositionViewBox, CompositionVisual, Compositor, ICompositionObject,
6};
7use std::ops::Deref;
8use std::rc::Rc;
9
10impl ShapeVisualHooks for CompositionVisual {}
11
12/// A visual that draws shapes (WinUI `Microsoft.UI.Composition.ShapeVisual`):
13/// its [`shapes`](Self::shapes) in order, through its
14/// [`view_box`](Self::view_box) when it has one, then its children.
15///
16/// The shapes are clipped to the size of the visual (so a shape visual
17/// without a size shows no shapes, as in WinUI); the visual itself does not
18/// clip its children (`clip_to_bounds` is `false`, as for a sprite visual).
19/// A change of a shape, of its geometry or brushes, of the collections or
20/// of the view box, an animation included, redraws the visual.
21#[derive(Clone)]
22pub struct ShapeVisual(Rc<CompositionVisual>);
23
24impl Deref for ShapeVisual {
25    type Target = Rc<CompositionVisual>;
26
27    fn deref(&self) -> &Rc<CompositionVisual> {
28        &self.0
29    }
30}
31
32impl ShapeVisual {
33    pub(crate) fn new(compositor: &Rc<Compositor>) -> ShapeVisual {
34        let shapes = CompositionShapeCollection::new(compositor);
35        let visual = CompositionVisual::create(
36            compositor,
37            CompositionVisualKind::Shape(ShapeVisualProps::new()),
38            || Box::new(ServerShapeVisual::new()),
39        );
40        // A WinUI visual has no implicit clip.
41        visual.set_clip_to_bounds(false);
42        let visual = ShapeVisual(visual);
43        visual.props().set_shapes(&*visual.0, Some(shapes as Rc<dyn ICompositionObject>));
44        visual
45    }
46
47    /// The handle of `visual` as a shape visual, if it is one.
48    pub fn from_visual(visual: &Rc<CompositionVisual>) -> Option<ShapeVisual> {
49        matches!(visual.kind, CompositionVisualKind::Shape(_)).then(|| ShapeVisual(visual.clone()))
50    }
51
52    /// The visual as a composition visual.
53    pub fn visual(&self) -> &Rc<CompositionVisual> {
54        &self.0
55    }
56
57    fn props(&self) -> &ShapeVisualProps {
58        match &self.0.kind {
59            CompositionVisualKind::Shape(props) => props,
60            _ => unreachable!("a shape visual handle wraps a shape visual"),
61        }
62    }
63
64    /// The shapes the visual draws, in order.
65    pub fn shapes(&self) -> Rc<CompositionShapeCollection> {
66        self.props()
67            .shapes()
68            .and_then(|shapes| shapes.into_any_rc().downcast::<CompositionShapeCollection>().ok())
69            .expect("a shape visual has a shape collection")
70    }
71
72    /// The area of the shape coordinates the visual shows.
73    pub fn view_box(&self) -> Option<Rc<CompositionViewBox>> {
74        self.props().view_box().and_then(|view_box| view_box.into_any_rc().downcast::<CompositionViewBox>().ok())
75    }
76
77    pub fn set_view_box(&self, value: Option<Rc<CompositionViewBox>>) {
78        self.props().set_view_box(&*self.0, value.map(|view_box| view_box as Rc<dyn ICompositionObject>))
79    }
80}