Skip to main content

ferroui_controls/shapes/
polygon.rs

1use super::{Shape, ShapeImpl};
2use crate::ControlImpl;
3use ferroui_base::data::BindingPriority;
4use ferroui_base::input::InputElementImpl;
5use ferroui_base::interactivity::InteractiveImpl;
6use ferroui_base::layout::LayoutableImpl;
7use ferroui_base::media::{FillRule, Geometry, Points, PolylineGeometry};
8use ferroui_base::{
9    ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl, FerroObjectImplExt, FerroProperty,
10    Ref, StyledElementImpl, StyledProperty, VisualImpl,
11};
12
13/// Represents a closed figure made of straight lines between points.
14#[repr(C)]
15pub struct Polygon {
16    base: Shape,
17}
18
19ferro_class!(Polygon: Shape);
20ferroui_base::ferro_class_info!(Polygon { new: Polygon::new });
21ferro_impl_classes!(
22    Polygon: StyledElementImpl,
23    VisualImpl,
24    LayoutableImpl,
25    InteractiveImpl,
26    InputElementImpl,
27    ControlImpl
28);
29
30impl FerroObjectImpl for Polygon {
31    fn constructed(this: &Self) {
32        Self::parent_constructed(this);
33
34        this.set_value_with_priority(Self::points_property(), Some(Points::new()), BindingPriority::Template);
35    }
36}
37
38impl ShapeImpl for Polygon {
39    fn create_defining_geometry(this: &Self) -> Option<Ref<Geometry>> {
40        let points = this.points();
41        let geometry = PolylineGeometry::with_points_and_fill_rule(
42            points.as_ref().map(|p| p.to_vec()).unwrap_or_default(),
43            true,
44            this.fill_rule(),
45        );
46        // Re-assign the live collection so the geometry observes changes to it (#20565).
47        if let Some(points) = points {
48            geometry.set_points(points);
49        }
50        Some(geometry.upcast())
51    }
52}
53
54ferroui_base::ferro_properties! { impl Polygon {
55    ferro_property!(
56        /// Defines the `Points` property.
57        pub fn points_property() -> StyledProperty<Option<Points>> {
58            FerroProperty::register::<Polygon, _>("Points", None)
59        }
60    );
61
62    ferro_property!(
63        /// Defines the `FillRule` property.
64        pub fn fill_rule_property() -> StyledProperty<FillRule> {
65            FerroProperty::register::<Polygon, _>("FillRule", FillRule::EvenOdd)
66        }
67    );
68} }
69
70impl Polygon {
71    fn static_constructor() {
72        Shape::affects_geometry::<Polygon>(&[
73            Self::points_property().as_property(),
74            Self::fill_rule_property().as_property(),
75        ]);
76    }
77
78    /// Creates the class data; see [`ferroui_base::FerroObject::construct`].
79    pub fn construct() -> Self {
80        Self { base: Shape::construct() }
81    }
82
83    pub fn new() -> Ref<Self> {
84        instantiate(Self::construct())
85    }
86
87    /// The vertices of the polygon.
88    pub fn points(&self) -> Option<Points> {
89        self.get_value(Self::points_property())
90    }
91
92    pub fn set_points(&self, value: Option<Points>) {
93        self.set_value(Self::points_property(), value)
94    }
95
96    /// Gets how the interior of the polygon is determined when a fill is
97    /// applied.
98    pub fn fill_rule(&self) -> FillRule {
99        self.get_value(Self::fill_rule_property())
100    }
101
102    /// Sets how the interior of the polygon is determined when a fill is
103    /// applied.
104    pub fn set_fill_rule(&self, value: FillRule) {
105        self.set_value(Self::fill_rule_property(), value)
106    }
107}