Skip to main content

ferroui_base/media/
stream_geometry_context.rs

1use crate::media::precise_elliptic_arc_helper::PreciseEllipticArcHelper;
2use crate::media::{FillRule, SweepDirection};
3#[allow(deprecated)]
4use crate::platform::IStreamGeometryContextImpl;
5use crate::platform::IGeometryContext;
6use crate::{Point, Size};
7
8/// Describes a geometry using drawing commands.
9///
10/// This type is used to describe a stream geometry: obtain one by calling
11/// [`StreamGeometry::open`](crate::media::StreamGeometry::open). The context
12/// is completed when it is disposed or dropped.
13pub struct StreamGeometryContext {
14    context: Box<dyn IGeometryContext>,
15    current_point: Point,
16    is_disposed: bool,
17}
18
19impl StreamGeometryContext {
20    /// Creates a context over a platform implementation.
21    #[deprecated(note = "Use StreamGeometry::open instead.")]
22    #[allow(deprecated)]
23    pub fn new(impl_: Box<dyn IStreamGeometryContextImpl>) -> Self {
24        Self::from_context(impl_)
25    }
26
27    /// Creates a context that forwards the drawing commands to `context`.
28    pub(crate) fn from_context(context: Box<dyn IGeometryContext>) -> Self {
29        Self { context, current_point: Point::default(), is_disposed: false }
30    }
31
32    /// Draws an arc to the specified point using polylines, quadratic or cubic Bezier curves.
33    /// This is significantly more precise when drawing elliptic arcs with extreme width:height ratios.
34    ///
35    /// The parameters are those of [`IGeometryContext::arc_to`]:
36    ///
37    /// * `point` - The destination point where the arc ends.
38    /// * `size` - The radii of an ellipse whose path is used to draw the arc.
39    /// * `rotation_angle` - The rotation angle (in degrees) of the ellipse that specifies the path of
40    ///   the arc; positive values are clockwise. This will rotate the entire arc relative to the
41    ///   X-axis and is not commonly used.
42    /// * `is_large_arc` - Specifies whether the arc should follow the longer path around an ellipse
43    ///   rather than the shorter one. `true` to draw the arc greater than 180 degrees; otherwise,
44    ///   `false`.
45    /// * `sweep_direction` - A value that indicates whether the arc is drawn in the Clockwise or
46    ///   Counterclockwise direction.
47    pub fn precise_arc_to(
48        &mut self,
49        point: Point,
50        size: Size,
51        rotation_angle: f64,
52        is_large_arc: bool,
53        sweep_direction: SweepDirection,
54    ) {
55        let current_point = self.current_point;
56        PreciseEllipticArcHelper::arc_to(self, current_point, point, size, rotation_angle, is_large_arc, sweep_direction);
57    }
58}
59
60impl IGeometryContext for StreamGeometryContext {
61    fn set_fill_rule(&mut self, fill_rule: FillRule) {
62        self.context.set_fill_rule(fill_rule);
63    }
64
65    fn arc_to(
66        &mut self,
67        point: Point,
68        size: Size,
69        rotation_angle: f64,
70        is_large_arc: bool,
71        sweep_direction: SweepDirection,
72        is_stroked: bool,
73    ) {
74        self.context.arc_to(point, size, rotation_angle, is_large_arc, sweep_direction, is_stroked);
75        self.current_point = point;
76    }
77
78    fn begin_figure(&mut self, start_point: Point, is_filled: bool) {
79        self.context.begin_figure(start_point, is_filled);
80        self.current_point = start_point;
81    }
82
83    fn cubic_bezier_to(&mut self, control_point1: Point, control_point2: Point, end_point: Point, is_stroked: bool) {
84        self.context.cubic_bezier_to(control_point1, control_point2, end_point, is_stroked);
85        self.current_point = end_point;
86    }
87
88    fn quadratic_bezier_to(&mut self, control_point: Point, end_point: Point, is_stroked: bool) {
89        self.context.quadratic_bezier_to(control_point, end_point, is_stroked);
90        self.current_point = end_point;
91    }
92
93    fn line_to(&mut self, point: Point, is_stroked: bool) {
94        self.context.line_to(point, is_stroked);
95        self.current_point = point;
96    }
97
98    fn end_figure(&mut self, is_closed: bool) {
99        self.context.end_figure(is_closed);
100    }
101
102    /// Finishes the drawing session.
103    fn dispose(&mut self) {
104        if !self.is_disposed {
105            self.is_disposed = true;
106            self.context.dispose();
107        }
108    }
109}
110
111impl Drop for StreamGeometryContext {
112    fn drop(&mut self) {
113        self.dispose();
114    }
115}