Skip to main content

ferroui_base/rendering/composition/server/
server_composition_simple_brush.rs

1//! The server-side counterparts of the mutable brushes.
2
3use super::{
4    impl_simple_server_render_resource, IServerObject, IServerRenderResource, ServerCompositor, SimpleServerRenderResource,
5};
6use crate::media::immutable::ImmutableGradientStop;
7use crate::media::{
8    AlignmentX, AlignmentY, Color, GradientSpreadMethod, IBrush, IConicGradientBrush, IGradientBrush, IGradientStop,
9    ILinearGradientBrush, IRadialGradientBrush, ISolidColorBrush, ITileBrush, ITransform, Stretch, TileMode,
10};
11use crate::rendering::composition::generated::{
12    ServerCompositionSimpleBrushHooks, ServerCompositionSimpleBrushProps, ServerCompositionSimpleConicGradientBrushHooks,
13    ServerCompositionSimpleConicGradientBrushProps, ServerCompositionSimpleLinearGradientBrushHooks,
14    ServerCompositionSimpleLinearGradientBrushProps, ServerCompositionSimpleRadialGradientBrushHooks,
15    ServerCompositionSimpleRadialGradientBrushProps, ServerCompositionSimpleSolidColorBrushHooks,
16    ServerCompositionSimpleSolidColorBrushProps, ServerCompositionSimpleTileBrushHooks,
17    ServerCompositionSimpleTileBrushProps,
18};
19use crate::rendering::composition::transport::BatchStreamReader;
20use crate::{RelativePoint, RelativeRect, RelativeScalar};
21use std::any::{Any, TypeId};
22use std::cell::{Cell, RefCell};
23use std::rc::{Rc, Weak};
24use std::time::Duration;
25
26/// The gradient part of the server-side gradient brushes: the brush
27/// properties, the stops and the spread method.
28///
29/// Embedded by the linear, radial and conic gradient brushes, whose
30/// generated properties read their changes after it.
31pub struct ServerCompositionSimpleGradientBrush {
32    brush: ServerCompositionSimpleBrushProps,
33    gradient_stops: RefCell<Vec<Rc<dyn IGradientStop>>>,
34    spread_method: Cell<GradientSpreadMethod>,
35}
36
37impl Default for ServerCompositionSimpleGradientBrush {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl ServerCompositionSimpleGradientBrush {
44    pub fn new() -> Self {
45        Self {
46            brush: ServerCompositionSimpleBrushProps::new(),
47            gradient_stops: RefCell::new(Vec::new()),
48            spread_method: Cell::new(GradientSpreadMethod::default()),
49        }
50    }
51
52    /// The brush properties.
53    pub fn brush(&self) -> &ServerCompositionSimpleBrushProps {
54        &self.brush
55    }
56
57    pub fn gradient_stops(&self) -> Vec<Rc<dyn IGradientStop>> {
58        self.gradient_stops.borrow().clone()
59    }
60
61    pub fn spread_method(&self) -> GradientSpreadMethod {
62        self.spread_method.get()
63    }
64
65    pub fn deserialize_changes_core(
66        &self,
67        host: &dyn ServerCompositionSimpleBrushHooks,
68        reader: &mut BatchStreamReader<'_>,
69        committed_at: Duration,
70    ) {
71        self.brush.deserialize_changes_core(host, reader, committed_at);
72        self.spread_method.set(reader.read::<GradientSpreadMethod>());
73        let mut gradient_stops = self.gradient_stops.borrow_mut();
74        gradient_stops.clear();
75        let count = reader.read::<i32>();
76        for _ in 0..count {
77            match reader.read_value::<ImmutableGradientStop>() {
78                Some(stop) => gradient_stops.push(Rc::new(stop)),
79                None => panic!("a batch lists a null gradient stop"),
80            }
81        }
82    }
83}
84
85/// Declares a server-side brush class: the struct, its constructor, the
86/// render resource contracts, `IServerObject` and `IBrush`.
87///
88/// `brush` is the path from `self` to the brush properties, `deserialize`
89/// the member that reads the changes of the whole class, `find` the lookup
90/// of generated property blocks, the optional `dispose` what the class
91/// releases before the base class is disposed, and the trailing items are
92/// the `as_*` members of `IBrush` the class answers.
93macro_rules! server_simple_brush {
94    (
95        $(#[$meta:meta])*
96        $name:ident { $($field:ident : $field_ty:ty = $field_init:expr),* $(,)? }
97        brush: |$b:ident| $brush:expr;
98        deserialize: |$d:ident, $reader:ident, $committed_at:ident| $deserialize:expr;
99        find: |$f:ident, $type_id:ident| $find:expr;
100        $(dispose: |$x:ident| $dispose:expr;)?
101        as: { $($as_fn:ident -> $as_trait:path),* $(,)? }
102    ) => {
103        $(#[$meta])*
104        pub struct $name {
105            base: SimpleServerRenderResource,
106            this: Weak<$name>,
107            $($field: $field_ty,)*
108        }
109
110        impl $name {
111            pub fn new(compositor: &Rc<ServerCompositor>) -> Rc<$name> {
112                Rc::new_cyclic(|this| {
113                    let this: Weak<$name> = this.clone();
114                    $name {
115                        base: SimpleServerRenderResource::new(compositor, this.clone()),
116                        this,
117                        $($field: $field_init,)*
118                    }
119                })
120            }
121
122            /// The shared handle of the object, while it is alive.
123            pub fn to_rc(&self) -> Option<Rc<$name>> {
124                self.this.upgrade()
125            }
126
127            pub fn is_disposed(&self) -> bool {
128                self.base.is_disposed()
129            }
130
131            /// The brush properties of the class.
132            pub fn brush_props(&self) -> &ServerCompositionSimpleBrushProps {
133                let $b = self;
134                $brush
135            }
136        }
137
138        impl_simple_server_render_resource!($name, base);
139
140        impl ServerCompositionSimpleBrushHooks for $name {}
141
142        impl IServerObject for $name {
143            fn deserialize_changes_core(&self, $reader: &mut BatchStreamReader<'_>, $committed_at: Duration) {
144                let $d = self;
145                $deserialize
146            }
147
148            fn values_invalidated(&self) {
149                self.base.core().invalidated(self);
150            }
151
152            fn dispose(&self) {
153                $(
154                    let $x = self;
155                    $dispose;
156                )?
157                self.base.core().dispose();
158            }
159
160            fn as_render_resource(self: Rc<Self>) -> Option<Rc<dyn IServerRenderResource>> {
161                Some(self)
162            }
163
164            fn as_brush(self: Rc<Self>) -> Option<Rc<dyn IBrush>> {
165                Some(self)
166            }
167
168            fn get_props(&self, $type_id: TypeId) -> Option<&dyn Any> {
169                let $f = self;
170                $find
171            }
172
173            fn as_any(&self) -> &dyn Any {
174                self
175            }
176
177            fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
178                self
179            }
180        }
181
182        impl IBrush for $name {
183            fn opacity(&self) -> f64 {
184                self.brush_props().opacity()
185            }
186
187            fn transform(&self) -> Option<Rc<dyn ITransform>> {
188                self.brush_props().transform().map(|transform| transform.value)
189            }
190
191            fn transform_origin(&self) -> RelativePoint {
192                self.brush_props().transform_origin()
193            }
194
195            fn relative_transform(&self) -> Option<Rc<dyn ITransform>> {
196                self.brush_props().relative_transform().map(|transform| transform.value)
197            }
198
199            fn as_any(&self) -> &dyn Any {
200                self
201            }
202
203            $(
204                fn $as_fn(&self) -> Option<&dyn $as_trait> {
205                    Some(self)
206                }
207            )*
208        }
209    };
210}
211
212pub(crate) use server_simple_brush;
213
214server_simple_brush! {
215    /// The server-side counterpart of a mutable brush: the properties all
216    /// brushes share.
217    ServerCompositionSimpleBrush { props: ServerCompositionSimpleBrushProps = ServerCompositionSimpleBrushProps::new() }
218    brush: |b| &b.props;
219    deserialize: |d, reader, committed_at| d.props.deserialize_changes_core(d, reader, committed_at);
220    find: |f, type_id| f.props.find_props(type_id);
221    as: {}
222}
223
224server_simple_brush! {
225    /// The server-side counterpart of a mutable solid color brush.
226    ServerCompositionSimpleSolidColorBrush {
227        props: ServerCompositionSimpleSolidColorBrushProps = ServerCompositionSimpleSolidColorBrushProps::new(),
228    }
229    brush: |b| b.props.base();
230    deserialize: |d, reader, committed_at| d.props.deserialize_changes_core(d, reader, committed_at);
231    find: |f, type_id| f.props.find_props(type_id);
232    as: { as_solid_color_brush -> ISolidColorBrush }
233}
234
235impl ServerCompositionSimpleSolidColorBrushHooks for ServerCompositionSimpleSolidColorBrush {}
236
237impl ServerCompositionSimpleSolidColorBrush {
238    /// The properties of the brush.
239    pub fn props(&self) -> &ServerCompositionSimpleSolidColorBrushProps {
240        &self.props
241    }
242
243    pub fn set_color(&self, value: Color) {
244        self.props.set_color(self, value)
245    }
246}
247
248impl ISolidColorBrush for ServerCompositionSimpleSolidColorBrush {
249    fn color(&self) -> Color {
250        self.props.color()
251    }
252}
253
254server_simple_brush! {
255    /// The server-side counterpart of a mutable tile brush.
256    ServerCompositionSimpleTileBrush {
257        props: ServerCompositionSimpleTileBrushProps = ServerCompositionSimpleTileBrushProps::new(),
258    }
259    brush: |b| b.props.base();
260    deserialize: |d, reader, committed_at| d.props.deserialize_changes_core(d, reader, committed_at);
261    find: |f, type_id| f.props.find_props(type_id);
262    as: { as_tile_brush -> ITileBrush }
263}
264
265impl ServerCompositionSimpleTileBrushHooks for ServerCompositionSimpleTileBrush {}
266
267impl ServerCompositionSimpleTileBrush {
268    /// The properties of the brush.
269    pub fn props(&self) -> &ServerCompositionSimpleTileBrushProps {
270        &self.props
271    }
272}
273
274impl ITileBrush for ServerCompositionSimpleTileBrush {
275    fn alignment_x(&self) -> AlignmentX {
276        self.props.alignment_x()
277    }
278
279    fn alignment_y(&self) -> AlignmentY {
280        self.props.alignment_y()
281    }
282
283    fn destination_rect(&self) -> RelativeRect {
284        self.props.destination_rect()
285    }
286
287    fn source_rect(&self) -> RelativeRect {
288        self.props.source_rect()
289    }
290
291    fn stretch(&self) -> Stretch {
292        self.props.stretch()
293    }
294
295    fn tile_mode(&self) -> TileMode {
296        self.props.tile_mode()
297    }
298}
299
300/// Declares a server-side gradient brush class on top of
301/// [`server_simple_brush!`].
302macro_rules! server_simple_gradient_brush {
303    ($(#[$meta:meta])* $name:ident, $props:ident, $hooks:ident, $as_fn:ident -> $as_trait:path) => {
304        server_simple_brush! {
305            $(#[$meta])*
306            $name {
307                gradient: ServerCompositionSimpleGradientBrush = ServerCompositionSimpleGradientBrush::new(),
308                props: $props = $props::new(),
309            }
310            brush: |b| b.gradient.brush();
311            deserialize: |d, reader, committed_at| d.props.deserialize_changes_core(d, reader, committed_at);
312            find: |f, type_id| f.props.find_props(type_id).or_else(|| f.gradient.brush().find_props(type_id));
313            as: { as_gradient_brush -> IGradientBrush, $as_fn -> $as_trait }
314        }
315
316        impl $hooks for $name {
317            fn base_deserialize_changes_core(&self, reader: &mut BatchStreamReader<'_>, committed_at: Duration) {
318                self.gradient.deserialize_changes_core(self, reader, committed_at);
319            }
320        }
321
322        impl $name {
323            /// The properties of the brush.
324            pub fn props(&self) -> &$props {
325                &self.props
326            }
327        }
328
329        impl IGradientBrush for $name {
330            fn gradient_stops(&self) -> Vec<Rc<dyn IGradientStop>> {
331                self.gradient.gradient_stops()
332            }
333
334            fn spread_method(&self) -> GradientSpreadMethod {
335                self.gradient.spread_method()
336            }
337        }
338    };
339}
340
341server_simple_gradient_brush!(
342    /// The server-side counterpart of a mutable conic gradient brush.
343    ServerCompositionSimpleConicGradientBrush,
344    ServerCompositionSimpleConicGradientBrushProps,
345    ServerCompositionSimpleConicGradientBrushHooks,
346    as_conic_gradient_brush -> IConicGradientBrush
347);
348
349impl IConicGradientBrush for ServerCompositionSimpleConicGradientBrush {
350    fn center(&self) -> RelativePoint {
351        self.props.center()
352    }
353
354    fn angle(&self) -> f64 {
355        self.props.angle()
356    }
357}
358
359server_simple_gradient_brush!(
360    /// The server-side counterpart of a mutable linear gradient brush.
361    ServerCompositionSimpleLinearGradientBrush,
362    ServerCompositionSimpleLinearGradientBrushProps,
363    ServerCompositionSimpleLinearGradientBrushHooks,
364    as_linear_gradient_brush -> ILinearGradientBrush
365);
366
367impl ILinearGradientBrush for ServerCompositionSimpleLinearGradientBrush {
368    fn start_point(&self) -> RelativePoint {
369        self.props.start_point()
370    }
371
372    fn end_point(&self) -> RelativePoint {
373        self.props.end_point()
374    }
375}
376
377server_simple_gradient_brush!(
378    /// The server-side counterpart of a mutable radial gradient brush.
379    ServerCompositionSimpleRadialGradientBrush,
380    ServerCompositionSimpleRadialGradientBrushProps,
381    ServerCompositionSimpleRadialGradientBrushHooks,
382    as_radial_gradient_brush -> IRadialGradientBrush
383);
384
385impl IRadialGradientBrush for ServerCompositionSimpleRadialGradientBrush {
386    fn center(&self) -> RelativePoint {
387        self.props.center()
388    }
389
390    fn gradient_origin(&self) -> RelativePoint {
391        self.props.gradient_origin()
392    }
393
394    fn radius_x(&self) -> RelativeScalar {
395        self.props.radius_x()
396    }
397
398    fn radius_y(&self) -> RelativeScalar {
399        self.props.radius_y()
400    }
401}