ferroui_base/media/
polyline_geometry.rs1use crate::media::{FillRule, Geometry, GeometryImpl, Points};
2use crate::platform::{self, IGeometryImpl};
3use crate::reactive::IDisposable;
4use crate::{
5 ferro_class, ferro_property, instantiate, DirectProperty, FerroObjectImpl, FerroProperty,
6 Point, Ref, StyledProperty,
7};
8use std::cell::RefCell;
9use std::rc::Rc;
10use std::sync::Arc;
11
12#[repr(C)]
14pub struct PolylineGeometry {
15 base: Geometry,
16 points: RefCell<Option<Points>>,
17 points_observer: RefCell<Option<Rc<dyn IDisposable>>>,
18 fill_rule: FillRule,
19}
20
21ferro_class!(PolylineGeometry: Geometry);
22crate::ferro_class_info!(PolylineGeometry { new: PolylineGeometry::new });
23
24crate::ferro_impl_classes!(PolylineGeometry: FerroObjectImpl);
25
26impl GeometryImpl for PolylineGeometry {
27 fn clone_geometry(this: &Self) -> Ref<Geometry> {
28 let result = PolylineGeometry::with_points_and_fill_rule(this.points().iter(), this.is_filled(), this.fill_rule);
29 result.set_transform(this.transform());
30 result.upcast()
31 }
32
33 fn create_defining_geometry(this: &Self) -> Option<Arc<dyn IGeometryImpl>> {
34 let factory = platform::render_interface();
35 let mut builder = factory.create_stream_geometry_builder(None);
36
37 builder.set_fill_rule(this.fill_rule);
38 let points = this.points().to_vec();
39 let is_filled = this.is_filled();
40 if !points.is_empty() {
41 builder.begin_figure(points[0], is_filled);
42 for point in &points[1..] {
43 builder.line_to(*point, true);
44 }
45 builder.end_figure(is_filled);
46 }
47
48 let geometry = builder.to_geometry();
49 builder.dispose();
50 Some(geometry)
51 }
52}
53
54crate::ferro_properties! { impl PolylineGeometry {
55 ferro_property!(pub fn points_property() -> DirectProperty<PolylineGeometry, Option<Points>> {
56 FerroProperty::register_direct::<PolylineGeometry, _>(
57 "Points",
58 |g| g.points.borrow().clone(),
59 Some(|g, f| {
60 g.set_and_raise(PolylineGeometry::points_property(), &g.points, f);
61 }),
62 None,
63 )
64 });
65
66 ferro_property!(pub fn is_filled_property() -> StyledProperty<bool> {
67 FerroProperty::register::<PolylineGeometry, _>("IsFilled", false)
68 });
69} }
70
71impl PolylineGeometry {
72 fn static_constructor() {
73 Geometry::affects_geometry(&[Self::is_filled_property().as_property()]);
74 Self::points_property().changed().add_class_handler::<PolylineGeometry>(|s, e| {
75 s.on_points_changed(e.get_new_value::<Option<Points>>())
76 });
77 }
78
79 pub fn construct() -> Self {
81 Self::construct_with(Points::new(), FillRule::EvenOdd)
82 }
83
84 fn construct_with(points: Points, fill_rule: FillRule) -> Self {
85 Self {
86 base: Geometry::construct(),
87 points: RefCell::new(Some(points)),
88 points_observer: RefCell::new(None),
89 fill_rule,
90 }
91 }
92
93 pub fn new() -> Ref<Self> {
94 instantiate(Self::construct())
95 }
96
97 pub fn with_points(points: impl IntoIterator<Item = Point>, is_filled: bool) -> Ref<Self> {
99 Self::with_points_and_fill_rule(points, is_filled, FillRule::EvenOdd)
100 }
101
102 pub fn with_points_and_fill_rule(
105 points: impl IntoIterator<Item = Point>,
106 is_filled: bool,
107 fill_rule: FillRule,
108 ) -> Ref<Self> {
109 let result = instantiate(Self::construct_with(Points::from_items(points), fill_rule));
110 result.set_is_filled(is_filled);
111 result
112 }
113
114 pub fn points(&self) -> Points {
116 self.points.borrow().clone().expect("Points is not set")
117 }
118
119 pub fn set_points(&self, value: Points) {
120 self.set_and_raise(Self::points_property(), &self.points, Some(value));
121 }
122
123 pub fn is_filled(&self) -> bool {
125 self.get_value(Self::is_filled_property())
126 }
127
128 pub fn set_is_filled(&self, value: bool) {
129 self.set_value(Self::is_filled_property(), value)
130 }
131
132 pub fn fill_rule(&self) -> FillRule {
134 self.fill_rule
135 }
136
137 fn on_points_changed(&self, new_value: Option<Points>) {
138 if let Some(observer) = self.points_observer.take() {
139 observer.dispose();
140 }
141
142 if let Some(new_value) = new_value {
143 let weak = self.to_ref().downgrade();
144 let observer = new_value.collection_changed(move |_| {
145 if let Some(this) = weak.upgrade() {
146 this.invalidate_geometry();
147 }
148 });
149 *self.points_observer.borrow_mut() = Some(observer);
150 }
151 }
152}