Skip to main content

ferroui_base/rendering/composition/brushes/
composition_nine_grid_brush.rs

1//! The WinUI `CompositionNineGridBrush` and `CompositionMaskBrush` (phase 2,
2//! not from upstream): composition brushes painted by the visuals that show
3//! them, as the surface brush.
4
5use super::composition_brush::{CompositionBrush, CompositionBrushKind};
6use super::{ServerCompositionMaskBrush, ServerCompositionNineGridBrush};
7use crate::rendering::composition::generated::{CompositionMaskBrushProps, CompositionNineGridBrushProps};
8use crate::rendering::composition::{Compositor, ICompositionObject};
9use std::ops::Deref;
10use std::rc::Rc;
11
12/// A brush that paints another brush stretched as a nine-grid (WinUI
13/// `Microsoft.UI.Composition.CompositionNineGridBrush`): the source is cut
14/// by its four insets into corners, edges and a centre; the corners keep
15/// their size (the insets times the inset scales), the edges stretch along
16/// one axis, the centre along both.
17///
18/// The source is a colour or gradient brush (the nine regions of the area
19/// are filled with it, the frame only when the centre is hollow) or a
20/// [`CompositionSurfaceBrush`](super::CompositionSurfaceBrush), whose
21/// surface is cut at its natural size: the insets are in the units of the
22/// natural size of the surface. The insets and inset scales are animatable.
23///
24/// Deviation (winui-composition.md): the stretch, alignment and transform
25/// of a surface brush source are not applied; its surface is cut as it is.
26#[derive(Clone)]
27pub struct CompositionNineGridBrush(Rc<CompositionBrush>);
28
29impl Deref for CompositionNineGridBrush {
30    type Target = Rc<CompositionBrush>;
31
32    fn deref(&self) -> &Rc<CompositionBrush> {
33        &self.0
34    }
35}
36
37macro_rules! nine_grid_scalar {
38    ($($(#[$meta:meta])* $get:ident / $set:ident;)*) => {
39        impl CompositionNineGridBrush {$(
40            $(#[$meta])*
41            pub fn $get(&self) -> f32 {
42                self.props().$get()
43            }
44
45            pub fn $set(&self, value: f32) {
46                self.props().$set(&*self.0, value)
47            }
48        )*}
49    };
50}
51
52nine_grid_scalar! {
53    /// The width of the left column of the source (animatable as
54    /// `LeftInset`).
55    left_inset / set_left_inset;
56    /// The height of the top row of the source (animatable as `TopInset`).
57    top_inset / set_top_inset;
58    /// The width of the right column of the source (animatable as
59    /// `RightInset`).
60    right_inset / set_right_inset;
61    /// The height of the bottom row of the source (animatable as
62    /// `BottomInset`).
63    bottom_inset / set_bottom_inset;
64    /// The scale of the left inset in the painted area (default 1;
65    /// animatable as `LeftInsetScale`).
66    left_inset_scale / set_left_inset_scale;
67    /// The scale of the top inset in the painted area (default 1).
68    top_inset_scale / set_top_inset_scale;
69    /// The scale of the right inset in the painted area (default 1).
70    right_inset_scale / set_right_inset_scale;
71    /// The scale of the bottom inset in the painted area (default 1).
72    bottom_inset_scale / set_bottom_inset_scale;
73}
74
75impl CompositionNineGridBrush {
76    pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionNineGridBrush {
77        let brush = CompositionBrush::create(
78            compositor,
79            CompositionBrushKind::NineGrid(CompositionNineGridBrushProps::new()),
80            |c| ServerCompositionNineGridBrush::new(c),
81        );
82        brush.initialize_defaults();
83        CompositionNineGridBrush(brush)
84    }
85
86    /// The handle of `brush` as a nine-grid brush, if it is one.
87    pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionNineGridBrush> {
88        matches!(brush.kind, CompositionBrushKind::NineGrid(_)).then(|| CompositionNineGridBrush(brush.clone()))
89    }
90
91    /// The generated properties of the brush.
92    pub fn props(&self) -> &CompositionNineGridBrushProps {
93        match &self.0.kind {
94            CompositionBrushKind::NineGrid(props) => props,
95            _ => unreachable!("a nine-grid brush handle wraps a nine-grid brush"),
96        }
97    }
98
99    /// The brush that is cut into nine regions.
100    pub fn source(&self) -> Option<Rc<CompositionBrush>> {
101        self.props().source().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
102    }
103
104    pub fn set_source(&self, value: Option<Rc<CompositionBrush>>) {
105        self.props().set_source(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
106    }
107
108    /// Whether the centre region is left unpainted.
109    pub fn is_center_hollow(&self) -> bool {
110        self.props().is_center_hollow()
111    }
112
113    pub fn set_is_center_hollow(&self, value: bool) {
114        self.props().set_is_center_hollow(&*self.0, value)
115    }
116
117    /// `SetInsets(inset)`: the four insets.
118    pub fn set_insets(&self, inset: f32) {
119        self.set_insets_with(inset, inset, inset, inset);
120    }
121
122    /// `SetInsets(left, top, right, bottom)`.
123    pub fn set_insets_with(&self, left: f32, top: f32, right: f32, bottom: f32) {
124        self.set_left_inset(left);
125        self.set_top_inset(top);
126        self.set_right_inset(right);
127        self.set_bottom_inset(bottom);
128    }
129
130    /// `SetInsetScales(scale)`: the four inset scales.
131    pub fn set_inset_scales(&self, scale: f32) {
132        self.set_inset_scales_with(scale, scale, scale, scale);
133    }
134
135    /// `SetInsetScales(left, top, right, bottom)`.
136    pub fn set_inset_scales_with(&self, left: f32, top: f32, right: f32, bottom: f32) {
137        self.set_left_inset_scale(left);
138        self.set_top_inset_scale(top);
139        self.set_right_inset_scale(right);
140        self.set_bottom_inset_scale(bottom);
141    }
142}
143
144/// A brush that paints a source brush through the alpha of a mask brush
145/// (WinUI `Microsoft.UI.Composition.CompositionMaskBrush`).
146///
147/// A colour or gradient mask is the opacity mask of the drawing context. A
148/// surface (or other composition) brush as the mask is painted over the
149/// source in a layer with the destination-in blending of bitmaps.
150///
151/// Deviation (winui-composition.md): a mask that is not a colour or gradient
152/// brush masks through the bitmaps it draws only (a loaded image surface);
153/// shapes drawn by a visual surface used as a mask do not mask.
154#[derive(Clone)]
155pub struct CompositionMaskBrush(Rc<CompositionBrush>);
156
157impl Deref for CompositionMaskBrush {
158    type Target = Rc<CompositionBrush>;
159
160    fn deref(&self) -> &Rc<CompositionBrush> {
161        &self.0
162    }
163}
164
165impl CompositionMaskBrush {
166    pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionMaskBrush {
167        let brush = CompositionBrush::create(
168            compositor,
169            CompositionBrushKind::Mask(CompositionMaskBrushProps::new()),
170            |c| ServerCompositionMaskBrush::new(c),
171        );
172        brush.initialize_defaults();
173        CompositionMaskBrush(brush)
174    }
175
176    /// The handle of `brush` as a mask brush, if it is one.
177    pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionMaskBrush> {
178        matches!(brush.kind, CompositionBrushKind::Mask(_)).then(|| CompositionMaskBrush(brush.clone()))
179    }
180
181    /// The generated properties of the brush.
182    pub fn props(&self) -> &CompositionMaskBrushProps {
183        match &self.0.kind {
184            CompositionBrushKind::Mask(props) => props,
185            _ => unreachable!("a mask brush handle wraps a mask brush"),
186        }
187    }
188
189    /// The brush that is painted.
190    pub fn source(&self) -> Option<Rc<CompositionBrush>> {
191        self.props().source().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
192    }
193
194    pub fn set_source(&self, value: Option<Rc<CompositionBrush>>) {
195        self.props().set_source(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
196    }
197
198    /// The brush whose alpha masks the source.
199    pub fn mask(&self) -> Option<Rc<CompositionBrush>> {
200        self.props().mask().and_then(|brush| brush.into_any_rc().downcast::<CompositionBrush>().ok())
201    }
202
203    pub fn set_mask(&self, value: Option<Rc<CompositionBrush>>) {
204        self.props().set_mask(&*self.0, value.map(|brush| brush as Rc<dyn ICompositionObject>))
205    }
206}