1use crate::flags::FieldFlags;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub struct FieldId(pub(crate) usize);
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum FieldType {
12 Text,
14 Button,
16 Choice,
18 Signature,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
24pub enum Quadding {
25 #[default]
27 Left,
28 Center,
30 Right,
32}
33
34#[derive(Debug, Clone, PartialEq)]
36pub enum FieldValue {
37 Text(String),
39 StringArray(Vec<String>),
41}
42
43#[derive(Debug, Clone)]
45pub struct ChoiceOption {
46 pub export: String,
48 pub display: String,
50}
51
52#[derive(Debug, Clone, Default)]
54pub struct MkDict {
55 pub border_color: Option<Vec<f32>>,
57 pub background_color: Option<Vec<f32>>,
59 pub caption: Option<String>,
61 pub rollover_caption: Option<String>,
63 pub alternate_caption: Option<String>,
65 pub text_position: Option<u32>,
67 pub rotation: Option<u32>,
69}
70
71#[derive(Debug, Clone)]
73pub struct BorderStyle {
74 pub width: f32,
76 pub style: u8,
78}
79
80impl Default for BorderStyle {
81 fn default() -> Self {
82 Self {
83 width: 1.0,
84 style: b'S',
85 }
86 }
87}
88
89#[derive(Debug, Clone)]
91pub struct FieldNode {
92 pub partial_name: String,
94 pub alternate_name: Option<String>,
96 pub mapping_name: Option<String>,
98 pub field_type: Option<FieldType>,
100 pub flags: FieldFlags,
102 pub value: Option<FieldValue>,
104 pub default_value: Option<FieldValue>,
106 pub default_appearance: Option<String>,
108 pub quadding: Option<Quadding>,
110 pub max_len: Option<u32>,
112 pub options: Vec<ChoiceOption>,
114 pub top_index: Option<u32>,
116 pub rect: Option<[f32; 4]>,
118 pub appearance_state: Option<String>,
120 pub page_index: Option<usize>,
122 pub parent: Option<FieldId>,
124 pub children: Vec<FieldId>,
126 pub object_id: Option<(i32, i32)>,
128 pub has_actions: bool,
130 pub mk: Option<MkDict>,
132 pub border_style: Option<BorderStyle>,
134}
135
136#[derive(Debug)]
138pub struct FieldTree {
139 nodes: Vec<FieldNode>,
140 pub calculation_order: Vec<FieldId>,
142 pub document_da: Option<String>,
144 pub document_quadding: Option<Quadding>,
146 pub need_appearances: bool,
148 pub sig_flags: u32,
150}
151
152impl FieldTree {
153 pub fn new() -> Self {
155 Self {
156 nodes: Vec::new(),
157 calculation_order: Vec::new(),
158 document_da: None,
159 document_quadding: None,
160 need_appearances: false,
161 sig_flags: 0,
162 }
163 }
164
165 pub fn alloc(&mut self, node: FieldNode) -> FieldId {
167 let id = FieldId(self.nodes.len());
168 self.nodes.push(node);
169 id
170 }
171
172 pub fn get(&self, id: FieldId) -> &FieldNode {
174 &self.nodes[id.0]
175 }
176
177 pub fn get_mut(&mut self, id: FieldId) -> &mut FieldNode {
179 &mut self.nodes[id.0]
180 }
181
182 pub fn len(&self) -> usize {
184 self.nodes.len()
185 }
186
187 pub fn is_empty(&self) -> bool {
189 self.nodes.is_empty()
190 }
191
192 pub fn roots(&self) -> Vec<FieldId> {
194 self.nodes
195 .iter()
196 .enumerate()
197 .filter(|(_, n)| n.parent.is_none())
198 .map(|(i, _)| FieldId(i))
199 .collect()
200 }
201
202 pub fn terminal_fields(&self) -> Vec<FieldId> {
204 self.nodes
205 .iter()
206 .enumerate()
207 .filter(|(_, n)| n.children.is_empty())
208 .map(|(i, _)| FieldId(i))
209 .collect()
210 }
211
212 pub fn fully_qualified_name(&self, id: FieldId) -> String {
214 let mut parts = Vec::new();
215 let mut cur = Some(id);
216 while let Some(cid) = cur {
217 let node = self.get(cid);
218 if !node.partial_name.is_empty() {
219 parts.push(node.partial_name.as_str());
220 }
221 cur = node.parent;
222 }
223 parts.reverse();
224 parts.join(".")
225 }
226
227 pub fn effective_field_type(&self, id: FieldId) -> Option<FieldType> {
229 let mut cur = Some(id);
230 while let Some(cid) = cur {
231 if let Some(ft) = self.get(cid).field_type {
232 return Some(ft);
233 }
234 cur = self.get(cid).parent;
235 }
236 None
237 }
238
239 pub fn effective_value(&self, id: FieldId) -> Option<&FieldValue> {
241 let mut cur = Some(id);
242 while let Some(cid) = cur {
243 let node = self.get(cid);
244 if node.value.is_some() {
245 return node.value.as_ref();
246 }
247 cur = node.parent;
248 }
249 None
250 }
251
252 pub fn effective_da(&self, id: FieldId) -> Option<&str> {
254 let mut cur = Some(id);
255 while let Some(cid) = cur {
256 if let Some(ref da) = self.get(cid).default_appearance {
257 return Some(da.as_str());
258 }
259 cur = self.get(cid).parent;
260 }
261 self.document_da.as_deref()
262 }
263
264 pub fn effective_quadding(&self, id: FieldId) -> Quadding {
266 let mut cur = Some(id);
267 while let Some(cid) = cur {
268 if let Some(q) = self.get(cid).quadding {
269 return q;
270 }
271 cur = self.get(cid).parent;
272 }
273 self.document_quadding.unwrap_or_default()
274 }
275
276 pub fn effective_flags(&self, id: FieldId) -> FieldFlags {
278 self.get(id).flags
279 }
280
281 pub fn effective_max_len(&self, id: FieldId) -> Option<u32> {
287 let mut cur = Some(id);
288 while let Some(cid) = cur {
289 if let Some(ml) = self.get(cid).max_len {
290 return Some(ml);
291 }
292 cur = self.get(cid).parent;
293 }
294 None
295 }
296
297 pub fn find_by_name(&self, name: &str) -> Option<FieldId> {
299 self.terminal_fields()
300 .into_iter()
301 .find(|&id| self.fully_qualified_name(id) == name)
302 }
303
304 pub fn all_ids(&self) -> impl Iterator<Item = FieldId> {
306 (0..self.nodes.len()).map(FieldId)
307 }
308}
309
310impl Default for FieldTree {
311 fn default() -> Self {
312 Self::new()
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 fn make_node(name: &str) -> FieldNode {
321 FieldNode {
322 partial_name: name.into(),
323 alternate_name: None,
324 mapping_name: None,
325 field_type: None,
326 flags: FieldFlags::empty(),
327 value: None,
328 default_value: None,
329 default_appearance: None,
330 quadding: None,
331 max_len: None,
332 options: vec![],
333 top_index: None,
334 rect: None,
335 appearance_state: None,
336 page_index: None,
337 parent: None,
338 children: vec![],
339 object_id: None,
340 has_actions: false,
341 mk: None,
342 border_style: None,
343 }
344 }
345
346 #[test]
347 fn fqn_simple() {
348 let mut tree = FieldTree::new();
349 let root = tree.alloc(make_node("form"));
350 let mut child = make_node("name");
351 child.parent = Some(root);
352 child.field_type = Some(FieldType::Text);
353 let child_id = tree.alloc(child);
354 tree.get_mut(root).children.push(child_id);
355 assert_eq!(tree.fully_qualified_name(child_id), "form.name");
356 }
357
358 #[test]
359 fn inherited_field_type() {
360 let mut tree = FieldTree::new();
361 let mut parent = make_node("group");
362 parent.field_type = Some(FieldType::Button);
363 let parent_id = tree.alloc(parent);
364 let mut child = make_node("opt1");
365 child.parent = Some(parent_id);
366 let child_id = tree.alloc(child);
367 tree.get_mut(parent_id).children.push(child_id);
368 assert_eq!(tree.effective_field_type(child_id), Some(FieldType::Button));
369 }
370
371 #[test]
372 fn inherited_da() {
373 let mut tree = FieldTree::new();
374 tree.document_da = Some("0 g /Helv 12 Tf".into());
375 let id = tree.alloc(make_node("field"));
376 assert_eq!(tree.effective_da(id), Some("0 g /Helv 12 Tf"));
377 }
378
379 #[test]
380 fn inherited_max_len() {
381 let mut tree = FieldTree::new();
382 let mut parent = make_node("group");
384 parent.max_len = Some(10);
385 let parent_id = tree.alloc(parent);
386
387 let mut child = make_node("field");
388 child.parent = Some(parent_id);
389 let child_id = tree.alloc(child);
390 tree.get_mut(parent_id).children.push(child_id);
391
392 assert_eq!(tree.effective_max_len(child_id), Some(10));
393 }
394
395 #[test]
396 fn own_max_len_overrides_parent() {
397 let mut tree = FieldTree::new();
398 let mut parent = make_node("group");
399 parent.max_len = Some(10);
400 let parent_id = tree.alloc(parent);
401
402 let mut child = make_node("field");
403 child.parent = Some(parent_id);
404 child.max_len = Some(5);
405 let child_id = tree.alloc(child);
406 tree.get_mut(parent_id).children.push(child_id);
407
408 assert_eq!(tree.effective_max_len(child_id), Some(5));
409 }
410}