Skip to main content

ferroui_controls/shapes/
polyline.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 an open figure made of straight lines between points.
14#[repr(C)]
15pub struct Polyline {
16    base: Shape,
17}
18
19ferro_class!(Polyline: Shape);
20ferroui_base::ferro_class_info!(Polyline { new: Polyline::new });
21ferro_impl_classes!(
22    Polyline: StyledElementImpl,
23    VisualImpl,
24    LayoutableImpl,
25    InteractiveImpl,
26    InputElementImpl,
27    ControlImpl
28);
29
30impl FerroObjectImpl for Polyline {
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 Polyline {
39    fn create_defining_geometry(this: &Self) -> Option<Ref<Geometry>> {
40        let is_filled = this.fill().is_some();
41        let points = this.points();
42        let geometry = PolylineGeometry::with_points_and_fill_rule(
43            points.as_ref().map(|p| p.to_vec()).unwrap_or_default(),
44            is_filled,
45            this.fill_rule(),
46        );
47        // Re-assign the live collection so the geometry observes changes to it (#20565).
48        if let Some(points) = points {
49            geometry.set_points(points);
50        }
51        Some(geometry.upcast())
52    }
53}
54
55ferroui_base::ferro_properties! { impl Polyline {
56    ferro_property!(
57        /// Defines the `Points` property.
58        pub fn points_property() -> StyledProperty<Option<Points>> {
59            FerroProperty::register::<Polyline, _>("Points", None)
60        }
61    );
62
63    ferro_property!(
64        /// Defines the `FillRule` property.
65        pub fn fill_rule_property() -> StyledProperty<FillRule> {
66            FerroProperty::register::<Polyline, _>("FillRule", FillRule::EvenOdd)
67        }
68    );
69} }
70
71impl Polyline {
72    fn static_constructor() {
73        Shape::stroke_thickness_property().override_default_value::<Polyline>(1.0);
74        Shape::affects_geometry::<Polyline>(&[
75            Self::points_property().as_property(),
76            Self::fill_rule_property().as_property(),
77        ]);
78    }
79
80    /// Creates the class data; see [`ferroui_base::FerroObject::construct`].
81    pub fn construct() -> Self {
82        Self { base: Shape::construct() }
83    }
84
85    pub fn new() -> Ref<Self> {
86        instantiate(Self::construct())
87    }
88
89    /// The vertices of the polyline.
90    pub fn points(&self) -> Option<Points> {
91        self.get_value(Self::points_property())
92    }
93
94    pub fn set_points(&self, value: Option<Points>) {
95        self.set_value(Self::points_property(), value)
96    }
97
98    /// Gets how the interior of the polyline is determined when a fill is
99    /// applied.
100    pub fn fill_rule(&self) -> FillRule {
101        self.get_value(Self::fill_rule_property())
102    }
103
104    /// Sets how the interior of the polyline is determined when a fill is
105    /// applied.
106    pub fn set_fill_rule(&self, value: FillRule) {
107        self.set_value(Self::fill_rule_property(), value)
108    }
109}