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, PartialEq)]
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 on_state: Option<String>,
124 pub page_index: Option<usize>,
126 pub parent: Option<FieldId>,
128 pub children: Vec<FieldId>,
130 pub object_id: Option<(i32, i32)>,
132 pub has_actions: bool,
134 pub mk: Option<MkDict>,
136 pub border_style: Option<BorderStyle>,
138}
139
140#[derive(Debug)]
142pub struct FieldTree {
143 nodes: Vec<FieldNode>,
144 pub calculation_order: Vec<FieldId>,
146 pub document_da: Option<String>,
148 pub document_quadding: Option<Quadding>,
150 pub need_appearances: bool,
152 pub sig_flags: u32,
154}
155
156impl FieldTree {
157 pub fn new() -> Self {
159 Self {
160 nodes: Vec::new(),
161 calculation_order: Vec::new(),
162 document_da: None,
163 document_quadding: None,
164 need_appearances: false,
165 sig_flags: 0,
166 }
167 }
168
169 pub fn alloc(&mut self, node: FieldNode) -> FieldId {
171 let id = FieldId(self.nodes.len());
172 self.nodes.push(node);
173 id
174 }
175
176 pub fn get(&self, id: FieldId) -> &FieldNode {
178 &self.nodes[id.0]
179 }
180
181 pub fn get_mut(&mut self, id: FieldId) -> &mut FieldNode {
183 &mut self.nodes[id.0]
184 }
185
186 pub fn len(&self) -> usize {
188 self.nodes.len()
189 }
190
191 pub fn is_empty(&self) -> bool {
193 self.nodes.is_empty()
194 }
195
196 pub fn roots(&self) -> Vec<FieldId> {
198 self.nodes
199 .iter()
200 .enumerate()
201 .filter(|(_, n)| n.parent.is_none())
202 .map(|(i, _)| FieldId(i))
203 .collect()
204 }
205
206 pub fn terminal_fields(&self) -> Vec<FieldId> {
208 self.nodes
209 .iter()
210 .enumerate()
211 .filter(|(_, n)| n.children.is_empty())
212 .map(|(i, _)| FieldId(i))
213 .collect()
214 }
215
216 pub fn fully_qualified_name(&self, id: FieldId) -> String {
218 let mut parts = Vec::new();
219 let mut cur = Some(id);
220 while let Some(cid) = cur {
221 let node = self.get(cid);
222 if !node.partial_name.is_empty() {
223 parts.push(node.partial_name.as_str());
224 }
225 cur = node.parent;
226 }
227 parts.reverse();
228 parts.join(".")
229 }
230
231 pub fn effective_field_type(&self, id: FieldId) -> Option<FieldType> {
233 let mut cur = Some(id);
234 while let Some(cid) = cur {
235 if let Some(ft) = self.get(cid).field_type {
236 return Some(ft);
237 }
238 cur = self.get(cid).parent;
239 }
240 None
241 }
242
243 pub fn effective_value(&self, id: FieldId) -> Option<&FieldValue> {
245 let mut cur = Some(id);
246 while let Some(cid) = cur {
247 let node = self.get(cid);
248 if node.value.is_some() {
249 return node.value.as_ref();
250 }
251 cur = node.parent;
252 }
253 None
254 }
255
256 pub fn effective_da(&self, id: FieldId) -> Option<&str> {
258 let mut cur = Some(id);
259 while let Some(cid) = cur {
260 if let Some(ref da) = self.get(cid).default_appearance {
261 return Some(da.as_str());
262 }
263 cur = self.get(cid).parent;
264 }
265 self.document_da.as_deref()
266 }
267
268 pub fn effective_quadding(&self, id: FieldId) -> Quadding {
270 let mut cur = Some(id);
271 while let Some(cid) = cur {
272 if let Some(q) = self.get(cid).quadding {
273 return q;
274 }
275 cur = self.get(cid).parent;
276 }
277 self.document_quadding.unwrap_or_default()
278 }
279
280 pub fn effective_flags(&self, id: FieldId) -> FieldFlags {
282 self.get(id).flags
283 }
284
285 pub fn effective_max_len(&self, id: FieldId) -> Option<u32> {
291 let mut cur = Some(id);
292 while let Some(cid) = cur {
293 if let Some(ml) = self.get(cid).max_len {
294 return Some(ml);
295 }
296 cur = self.get(cid).parent;
297 }
298 None
299 }
300
301 pub fn find_by_name(&self, name: &str) -> Option<FieldId> {
303 self.terminal_fields()
304 .into_iter()
305 .find(|&id| self.fully_qualified_name(id) == name)
306 }
307
308 pub fn all_ids(&self) -> impl Iterator<Item = FieldId> {
310 (0..self.nodes.len()).map(FieldId)
311 }
312}
313
314impl Default for FieldTree {
315 fn default() -> Self {
316 Self::new()
317 }
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323
324 fn make_node(name: &str) -> FieldNode {
325 FieldNode {
326 partial_name: name.into(),
327 alternate_name: None,
328 mapping_name: None,
329 field_type: None,
330 flags: FieldFlags::empty(),
331 value: None,
332 default_value: None,
333 default_appearance: None,
334 quadding: None,
335 max_len: None,
336 options: vec![],
337 top_index: None,
338 rect: None,
339 appearance_state: None,
340 on_state: None,
341 page_index: None,
342 parent: None,
343 children: vec![],
344 object_id: None,
345 has_actions: false,
346 mk: None,
347 border_style: None,
348 }
349 }
350
351 #[test]
352 fn fqn_simple() {
353 let mut tree = FieldTree::new();
354 let root = tree.alloc(make_node("form"));
355 let mut child = make_node("name");
356 child.parent = Some(root);
357 child.field_type = Some(FieldType::Text);
358 let child_id = tree.alloc(child);
359 tree.get_mut(root).children.push(child_id);
360 assert_eq!(tree.fully_qualified_name(child_id), "form.name");
361 }
362
363 #[test]
364 fn inherited_field_type() {
365 let mut tree = FieldTree::new();
366 let mut parent = make_node("group");
367 parent.field_type = Some(FieldType::Button);
368 let parent_id = tree.alloc(parent);
369 let mut child = make_node("opt1");
370 child.parent = Some(parent_id);
371 let child_id = tree.alloc(child);
372 tree.get_mut(parent_id).children.push(child_id);
373 assert_eq!(tree.effective_field_type(child_id), Some(FieldType::Button));
374 }
375
376 #[test]
377 fn inherited_da() {
378 let mut tree = FieldTree::new();
379 tree.document_da = Some("0 g /Helv 12 Tf".into());
380 let id = tree.alloc(make_node("field"));
381 assert_eq!(tree.effective_da(id), Some("0 g /Helv 12 Tf"));
382 }
383
384 #[test]
385 fn inherited_max_len() {
386 let mut tree = FieldTree::new();
387 let mut parent = make_node("group");
389 parent.max_len = Some(10);
390 let parent_id = tree.alloc(parent);
391
392 let mut child = make_node("field");
393 child.parent = Some(parent_id);
394 let child_id = tree.alloc(child);
395 tree.get_mut(parent_id).children.push(child_id);
396
397 assert_eq!(tree.effective_max_len(child_id), Some(10));
398 }
399
400 #[test]
401 fn own_max_len_overrides_parent() {
402 let mut tree = FieldTree::new();
403 let mut parent = make_node("group");
404 parent.max_len = Some(10);
405 let parent_id = tree.alloc(parent);
406
407 let mut child = make_node("field");
408 child.parent = Some(parent_id);
409 child.max_len = Some(5);
410 let child_id = tree.alloc(child);
411 tree.get_mut(parent_id).children.push(child_id);
412
413 assert_eq!(tree.effective_max_len(child_id), Some(5));
414 }
415}