hwpforge_core/control/shapes.rs
1//! Shape geometry and visual style primitives for drawing controls.
2//!
3//! Houses [`ShapePoint`], [`LineStyle`], [`ArrowStyle`], [`Fill`], and
4//! [`ShapeStyle`] — the building blocks shared by the shape variants of
5//! [`Control`](super::Control).
6
7use hwpforge_foundation::{
8 ArrowSize, ArrowType, Color, DropCapStyle, Flip, GradientType, ImageFillMode, PatternType,
9};
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12
13use crate::error::CoreError;
14
15/// A 2D point in raw HWPUNIT coordinates for shape geometry.
16///
17/// Uses `i32` (not `HwpUnit`) because shape geometry points are raw
18/// coordinate values within a bounding box, not document-level measurements.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
20pub struct ShapePoint {
21 /// X coordinate (HWPUNIT).
22 pub x: i32,
23 /// Y coordinate (HWPUNIT).
24 pub y: i32,
25}
26
27impl ShapePoint {
28 /// Creates a new shape point with the given coordinates.
29 ///
30 /// # Examples
31 ///
32 /// ```
33 /// use hwpforge_core::control::ShapePoint;
34 ///
35 /// let pt = ShapePoint::new(100, 200);
36 /// assert_eq!(pt.x, 100);
37 /// assert_eq!(pt.y, 200);
38 /// ```
39 pub fn new(x: i32, y: i32) -> Self {
40 Self { x, y }
41 }
42}
43
44/// Line drawing style for shapes.
45///
46/// Controls how the stroke of a shape is rendered (solid, dashed, etc.).
47/// Maps to HWPX `<hc:lineShape>` `dash` attribute values.
48///
49/// # Examples
50///
51/// ```
52/// use hwpforge_core::control::LineStyle;
53///
54/// let style = LineStyle::Dash;
55/// assert_eq!(style.to_string(), "DASH");
56/// assert_eq!("DOT".parse::<LineStyle>().unwrap(), LineStyle::Dot);
57/// ```
58#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
59#[non_exhaustive]
60pub enum LineStyle {
61 /// Continuous solid line (default).
62 #[default]
63 Solid,
64 /// Dashed line.
65 Dash,
66 /// Dotted line.
67 Dot,
68 /// Alternating dash and dot.
69 DashDot,
70 /// Alternating dash, dot, dot.
71 DashDotDot,
72 /// No visible line.
73 None,
74}
75
76impl std::fmt::Display for LineStyle {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 Self::Solid => f.write_str("SOLID"),
80 Self::Dash => f.write_str("DASH"),
81 Self::Dot => f.write_str("DOT"),
82 Self::DashDot => f.write_str("DASH_DOT"),
83 Self::DashDotDot => f.write_str("DASH_DOT_DOT"),
84 Self::None => f.write_str("NONE"),
85 }
86 }
87}
88
89impl std::str::FromStr for LineStyle {
90 type Err = CoreError;
91
92 fn from_str(s: &str) -> Result<Self, Self::Err> {
93 match s {
94 "SOLID" | "Solid" | "solid" => Ok(Self::Solid),
95 "DASH" | "Dash" | "dash" => Ok(Self::Dash),
96 "DOT" | "Dot" | "dot" => Ok(Self::Dot),
97 "DASH_DOT" | "DashDot" | "dash_dot" => Ok(Self::DashDot),
98 "DASH_DOT_DOT" | "DashDotDot" | "dash_dot_dot" => Ok(Self::DashDotDot),
99 "NONE" | "None" | "none" => Ok(Self::None),
100 _ => Err(CoreError::InvalidStructure {
101 context: "LineStyle".to_string(),
102 reason: format!(
103 "unknown line style '{s}', valid: SOLID, DASH, DOT, DASH_DOT, DASH_DOT_DOT, NONE"
104 ),
105 }),
106 }
107 }
108}
109
110/// Arrowhead style for line endpoints.
111///
112/// # Examples
113///
114/// ```
115/// use hwpforge_core::control::ArrowStyle;
116/// use hwpforge_foundation::{ArrowType, ArrowSize};
117///
118/// let arrow = ArrowStyle {
119/// arrow_type: ArrowType::Normal,
120/// size: ArrowSize::Medium,
121/// filled: true,
122/// };
123/// ```
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
125pub struct ArrowStyle {
126 /// Shape of the arrowhead.
127 pub arrow_type: ArrowType,
128 /// Size of the arrowhead.
129 pub size: ArrowSize,
130 /// Whether the arrowhead is filled (true) or outlined (false).
131 pub filled: bool,
132}
133
134/// Fill specification for shapes.
135///
136/// Replaces simple `fill_color` for shapes that need gradient, pattern, or image fills.
137///
138/// # Examples
139///
140/// ```
141/// use hwpforge_core::control::Fill;
142/// use hwpforge_foundation::Color;
143///
144/// let solid = Fill::Solid { color: Color::from_rgb(255, 0, 0) };
145/// ```
146#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
147#[non_exhaustive]
148pub enum Fill {
149 /// Solid color fill.
150 Solid {
151 /// Fill color.
152 color: Color,
153 },
154 /// Gradient fill.
155 Gradient {
156 /// Gradient direction type.
157 gradient_type: GradientType,
158 /// Gradient angle in degrees.
159 angle: i32,
160 /// Color stops: (color, position 0-100).
161 colors: Vec<(Color, u32)>,
162 },
163 /// Hatch pattern fill.
164 Pattern {
165 /// Pattern type.
166 pattern_type: PatternType,
167 /// Foreground pattern color.
168 fg_color: Color,
169 /// Background color.
170 bg_color: Color,
171 },
172 /// Image fill.
173 Image {
174 /// Image binary data reference ID.
175 image_id: String,
176 /// Image fill mode (tile, stretch, etc.).
177 mode: ImageFillMode,
178 },
179}
180
181/// Visual style overrides for drawing shapes.
182///
183/// All fields are `Option`; `None` means "use the encoder's default"
184/// (typically black solid border, white fill, 0.12 mm stroke).
185///
186/// # Examples
187///
188/// ```
189/// use hwpforge_core::control::{ShapeStyle, LineStyle};
190/// use hwpforge_foundation::Color;
191///
192/// let style = ShapeStyle {
193/// line_color: Some(Color::from_rgb(255, 0, 0)),
194/// fill_color: Some(Color::from_rgb(0, 255, 0)),
195/// line_width: Some(100),
196/// line_style: Some(LineStyle::Dash),
197/// ..Default::default()
198/// };
199/// ```
200#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
201pub struct ShapeStyle {
202 /// Stroke/border color (e.g. `Color::from_rgb(255, 0, 0)` for red).
203 pub line_color: Option<Color>,
204 /// Fill color (e.g. `Color::from_rgb(0, 255, 0)` for green).
205 /// For advanced fills (gradient, pattern, image), use the `fill` field instead.
206 pub fill_color: Option<Color>,
207 /// Stroke width in HWPUNIT (33 ≈ 0.12mm, 100 ≈ 0.35mm).
208 pub line_width: Option<u32>,
209 /// Line drawing style (solid, dash, dot, etc.).
210 pub line_style: Option<LineStyle>,
211 /// Rotation angle in degrees (0-360). `None` means no rotation.
212 pub rotation: Option<f32>,
213 /// Flip/mirror state. `None` means no flip.
214 pub flip: Option<Flip>,
215 /// Arrowhead at the start of a line. Only meaningful for `Control::Line`.
216 pub head_arrow: Option<ArrowStyle>,
217 /// Arrowhead at the end of a line. Only meaningful for `Control::Line`.
218 pub tail_arrow: Option<ArrowStyle>,
219 /// Advanced fill (gradient, pattern, image). Overrides `fill_color` when present.
220 pub fill: Option<Fill>,
221 /// Drop cap style for the shape (HWPX `dropcapstyle` attribute).
222 /// Controls whether the shape participates in a drop-cap layout.
223 #[serde(default)]
224 pub drop_cap_style: DropCapStyle,
225}