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