ferroui_controls/shapes/
sector.rs1use super::{Shape, ShapeImpl};
2use crate::ControlImpl;
3use ferroui_base::input::InputElementImpl;
4use ferroui_base::interactivity::InteractiveImpl;
5use ferroui_base::layout::LayoutableImpl;
6use ferroui_base::media::{EllipseGeometry, Geometry, StreamGeometry, SweepDirection};
7use ferroui_base::platform::IGeometryContext;
8use ferroui_base::utilities::MathUtilities;
9use ferroui_base::{
10 ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl, FerroProperty,
11 Point, Rect, Ref, Size, StyledElementImpl, StyledProperty, Visual, VisualImpl,
12};
13
14#[repr(C)]
17pub struct Sector {
18 base: Shape,
19}
20
21ferro_class!(Sector: Shape);
22ferroui_base::ferro_class_info!(Sector { new: Sector::new });
23ferro_impl_classes!(
24 Sector: StyledElementImpl,
25 VisualImpl,
26 LayoutableImpl,
27 InteractiveImpl,
28 InputElementImpl,
29 ControlImpl
30);
31
32ferroui_base::ferro_impl_classes!(Sector: FerroObjectImpl);
33
34impl ShapeImpl for Sector {
35 fn create_defining_geometry(this: &Self) -> Option<Ref<Geometry>> {
36 let rect = Rect::from_size(this.bounds().size());
37 let deflated_rect = rect.deflate(this.stroke_thickness() * 0.5);
38 let sweep = this.sweep_angle();
39
40 if sweep >= 360.0 || sweep <= -360.0 {
41 return Some(EllipseGeometry::with_rect(deflated_rect).upcast());
42 }
43
44 if sweep == 0.0 {
45 return Some(StreamGeometry::new().upcast());
46 }
47
48 let (start_angle, end_angle) = MathUtilities::get_min_max_from_delta(
49 MathUtilities::deg2rad(this.start_angle()),
50 MathUtilities::deg2rad(sweep),
51 );
52
53 let centre = Point::new(rect.width * 0.5, rect.height * 0.5);
54 let radius_x = deflated_rect.width * 0.5;
55 let radius_y = deflated_rect.height * 0.5;
56 let start_curve_point = MathUtilities::get_ellipse_point(centre, radius_x, radius_y, start_angle);
57 let end_curve_point = MathUtilities::get_ellipse_point(centre, radius_x, radius_y, end_angle);
58 let size = Size::new(radius_x, radius_y);
59
60 let stream_geometry = StreamGeometry::new();
61 {
62 let mut context = stream_geometry.open();
63 context.begin_figure(start_curve_point, true);
64 context.arc_to(end_curve_point, size, 0.0, sweep.abs() > 180.0, SweepDirection::Clockwise, true);
65 context.line_to(centre, true);
66 context.end_figure(true);
67 context.dispose();
68 }
69
70 Some(stream_geometry.upcast())
71 }
72}
73
74ferroui_base::ferro_properties! { impl Sector {
75 ferro_property!(
76 pub fn start_angle_property() -> StyledProperty<f64> {
78 FerroProperty::register::<Sector, _>("StartAngle", 0.0)
79 }
80 );
81
82 ferro_property!(
83 pub fn sweep_angle_property() -> StyledProperty<f64> {
85 FerroProperty::register::<Sector, _>("SweepAngle", 0.0)
86 }
87 );
88} }
89
90impl Sector {
91 fn static_constructor() {
92 Shape::stroke_thickness_property().override_default_value::<Sector>(1.0);
93 Shape::affects_geometry::<Sector>(&[
94 Visual::bounds_property().as_property(),
95 Shape::stroke_thickness_property().as_property(),
96 Self::start_angle_property().as_property(),
97 Self::sweep_angle_property().as_property(),
98 ]);
99 }
100
101 pub fn construct() -> Self {
103 Self { base: Shape::construct() }
104 }
105
106 pub fn new() -> Ref<Self> {
107 instantiate(Self::construct())
108 }
109
110 pub fn start_angle(&self) -> f64 {
112 self.get_value(Self::start_angle_property())
113 }
114
115 pub fn set_start_angle(&self, value: f64) {
117 self.set_value(Self::start_angle_property(), value)
118 }
119
120 pub fn sweep_angle(&self) -> f64 {
124 self.get_value(Self::sweep_angle_property())
125 }
126
127 pub fn set_sweep_angle(&self, value: f64) {
131 self.set_value(Self::sweep_angle_property(), value)
132 }
133}