Skip to main content

ferroui_base/media/
ellipse_geometry.rs

1use crate::media::{Geometry, GeometryImpl};
2use crate::platform::{self, IGeometryImpl};
3use crate::{
4    ferro_class, ferro_property, instantiate, FerroObjectImpl, FerroProperty, Point, Rect, Ref,
5    StyledProperty,
6};
7use std::sync::Arc;
8
9/// Represents the geometry of an ellipse or circle.
10#[repr(C)]
11pub struct EllipseGeometry {
12    base: Geometry,
13}
14
15ferro_class!(EllipseGeometry: Geometry);
16crate::ferro_class_info!(EllipseGeometry { new: EllipseGeometry::new });
17
18crate::ferro_impl_classes!(EllipseGeometry: FerroObjectImpl);
19
20impl GeometryImpl for EllipseGeometry {
21    fn clone_geometry(this: &Self) -> Ref<Geometry> {
22        // Note that the ellipse properties are used in two modes:
23        //
24        //  1. Rect-only Mode:
25        //     Directly set the rectangle bounds the ellipse will fill
26        //
27        //  2. Center + Radii Mode:
28        //     Set a center-point and then X/Y-axis radii that are used to
29        //     calculate the rectangle bounds the ellipse will fill.
30        //
31        // Rendering the ellipse will only ever use one of these two modes
32        // based on if the Rect property is set (not equal to default).
33        //
34        // This means it would normally be fine to copy ONLY the Rect property
35        // when it is set. However, while it would render the same, it isn't
36        // a true clone. We want to include all the properties here regardless
37        // of the rendering mode that will eventually be used.
38        let result = EllipseGeometry::new();
39        result.set_rect(this.rect());
40        result.set_radius_x(this.radius_x());
41        result.set_radius_y(this.radius_y());
42        result.set_center(this.center());
43        result.upcast()
44    }
45
46    fn create_defining_geometry(this: &Self) -> Option<Arc<dyn IGeometryImpl>> {
47        let factory = platform::render_interface();
48
49        let rect = this.rect();
50        if rect != Rect::default() {
51            return Some(factory.create_ellipse_geometry(rect));
52        }
53
54        let (center, radius_x, radius_y) = (this.center(), this.radius_x(), this.radius_y());
55        let origin_x = center.x - radius_x;
56        let origin_y = center.y - radius_y;
57        let width = radius_x * 2.0;
58        let height = radius_y * 2.0;
59
60        Some(factory.create_ellipse_geometry(Rect::new(origin_x, origin_y, width, height)))
61    }
62}
63
64crate::ferro_properties! { impl EllipseGeometry {
65    ferro_property!(pub fn rect_property() -> StyledProperty<Rect> {
66        FerroProperty::register::<EllipseGeometry, _>("Rect", Rect::default())
67    });
68
69    ferro_property!(pub fn radius_x_property() -> StyledProperty<f64> {
70        FerroProperty::register::<EllipseGeometry, _>("RadiusX", 0.0)
71    });
72
73    ferro_property!(pub fn radius_y_property() -> StyledProperty<f64> {
74        FerroProperty::register::<EllipseGeometry, _>("RadiusY", 0.0)
75    });
76
77    ferro_property!(pub fn center_property() -> StyledProperty<Point> {
78        FerroProperty::register::<EllipseGeometry, _>("Center", Point::default())
79    });
80} }
81
82impl EllipseGeometry {
83    fn static_constructor() {
84        Geometry::affects_geometry(&[
85            Self::rect_property().as_property(),
86            Self::radius_x_property().as_property(),
87            Self::radius_y_property().as_property(),
88            Self::center_property().as_property(),
89        ]);
90    }
91
92    /// Creates the class data.
93    pub fn construct() -> Self {
94        Self { base: Geometry::construct() }
95    }
96
97    pub fn new() -> Ref<Self> {
98        instantiate(Self::construct())
99    }
100
101    /// Creates an ellipse geometry filling the given bounds.
102    pub fn with_rect(rect: Rect) -> Ref<Self> {
103        let result = Self::new();
104        result.set_rect(rect);
105        result
106    }
107
108    /// A rect that defines the bounds of the ellipse. When set, this takes priority over the other properties that define an ellipse using a center point and X/Y-axis radii.
109    pub fn rect(&self) -> Rect {
110        self.get_value(Self::rect_property())
111    }
112
113    pub fn set_rect(&self, value: Rect) {
114        self.set_value(Self::rect_property(), value)
115    }
116
117    /// A double that defines the radius in the X-axis of the ellipse. In other words, the horizontal half-extent of the ellipse.
118    pub fn radius_x(&self) -> f64 {
119        self.get_value(Self::radius_x_property())
120    }
121
122    pub fn set_radius_x(&self, value: f64) {
123        self.set_value(Self::radius_x_property(), value)
124    }
125
126    /// A double that defines the radius in the Y-axis of the ellipse. In other words, the vertical half-extent of the ellipse.
127    pub fn radius_y(&self) -> f64 {
128        self.get_value(Self::radius_y_property())
129    }
130
131    pub fn set_radius_y(&self, value: f64) {
132        self.set_value(Self::radius_y_property(), value)
133    }
134
135    /// A point that defines the center of the ellipse.
136    pub fn center(&self) -> Point {
137        self.get_value(Self::center_property())
138    }
139
140    pub fn set_center(&self, value: Point) {
141        self.set_value(Self::center_property(), value)
142    }
143}