easyofd_core/page_description/
area.rs1use crate::basic_type::ST_Array;
6use crate::xml_element::{XmlElement, XmlElementError, XmlNode};
7
8#[derive(Debug, Clone, PartialEq, Default)]
12pub struct Area {
13 pub draw_param: Option<u32>,
15 pub ctm: Option<ST_Array>,
17 pub clip: Option<String>,
19}
20
21impl Area {
22 #[must_use]
24 pub fn new() -> Self {
25 Self::default()
26 }
27
28 #[must_use]
30 pub fn draw_param(mut self, id: u32) -> Self {
31 self.draw_param = Some(id);
32 self
33 }
34
35 #[must_use]
37 pub fn ctm(mut self, ctm: ST_Array) -> Self {
38 self.ctm = Some(ctm);
39 self
40 }
41
42 #[must_use]
44 pub fn clip(mut self, clip: impl Into<String>) -> Self {
45 self.clip = Some(clip.into());
46 self
47 }
48}
49
50impl XmlElement for Area {
51 fn element_name(&self) -> &'static str {
53 "Area"
54 }
55
56 fn attributes(&self) -> Vec<(String, String)> {
57 let mut attrs = Vec::new();
58 if let Some(dp) = self.draw_param {
59 attrs.push(("DrawParam".to_string(), dp.to_string()));
60 }
61 if let Some(ref ctm) = self.ctm {
62 attrs.push(("CTM".to_string(), ctm.to_xml_string()));
63 }
64 attrs
65 }
66
67 fn child_nodes(&self) -> Vec<XmlNode> {
68 let mut children = Vec::new();
69 if let Some(ref clip) = self.clip {
70 let mut clip_node = XmlNode::element("Clip");
71 clip_node.push_child(XmlNode::text_node(clip.clone()));
72 children.push(clip_node);
73 }
74 children
75 }
76
77 fn from_xml(node: &XmlNode) -> Result<Self, XmlElementError> {
78 let draw_param = node
79 .get_attr("DrawParam")
80 .map(|s| {
81 s.parse::<u32>()
82 .map_err(|e| XmlElementError(format!("解析 Area.DrawParam 失败: {e}")))
83 })
84 .transpose()?;
85 let ctm = node
86 .get_attr("CTM")
87 .map(|s| {
88 ST_Array::from_str(s)
89 .map_err(|e| XmlElementError(format!("解析 Area.CTM 失败: {e}")))
90 })
91 .transpose()?;
92 let clip = node.child("Clip").and_then(|c| c.text.clone());
93 Ok(Self {
94 draw_param,
95 ctm,
96 clip,
97 })
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::xml_parse::parse_xml_to_nodes;
105
106 #[test]
107 fn test_area_default() {
108 let a = Area::new();
109 assert!(a.draw_param.is_none());
110 assert!(a.ctm.is_none());
111 }
112
113 #[test]
114 fn test_area_builders() {
115 let a = Area::new()
116 .draw_param(5)
117 .ctm(ST_Array::transform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0))
118 .clip("M0 0 L10 0 L10 10 Z");
119 assert_eq!(a.draw_param, Some(5));
120 assert!(a.ctm.is_some());
121 assert_eq!(a.clip.as_deref(), Some("M0 0 L10 0 L10 10 Z"));
122 }
123
124 #[test]
125 fn test_xml_element_name() {
126 let a = Area::new();
127 assert_eq!(a.element_name(), "Area");
128 }
129
130 #[test]
131 fn test_xml_element_to_xml_contains_attrs() {
132 let a = Area::new()
133 .draw_param(3)
134 .ctm(ST_Array::transform(1.0, 0.0, 0.0, 1.0, 10.0, 20.0));
135 let xml = a.to_xml();
136 assert!(xml.contains("DrawParam=\"3\""));
137 assert!(xml.contains("CTM=\""));
138 }
139
140 #[test]
141 fn test_xml_element_roundtrip_full() {
142 let a = Area::new()
143 .draw_param(5)
144 .ctm(ST_Array::transform(1.0, 0.0, 0.0, 1.0, 10.0, 20.0))
145 .clip("M0 0 L10 0 L10 10 Z");
146 let xml = a.to_xml();
147 let node = parse_xml_to_nodes(&xml).unwrap();
148 let a2 = Area::from_xml(&node).unwrap();
149 assert_eq!(a, a2);
150 }
151
152 #[test]
153 fn test_xml_element_roundtrip_empty() {
154 let a = Area::new();
155 let xml = a.to_xml();
156 assert_eq!(xml, "<Area/>");
157 let node = parse_xml_to_nodes(&xml).unwrap();
158 let a2 = Area::from_xml(&node).unwrap();
159 assert_eq!(a, a2);
160 }
161}