Skip to main content

pdfluent_forms/
text.rs

1//! Text field implementation (B.2).
2
3use crate::flags::FieldFlags;
4use crate::tree::*;
5
6/// Text field sub-kind.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum TextFieldKind {
9    Normal,
10    Multiline,
11    Password,
12    Comb,
13    RichText,
14    FileSelect,
15}
16
17/// Determine the text field sub-kind from field flags.
18pub fn text_field_kind(flags: FieldFlags) -> TextFieldKind {
19    if flags.file_select() {
20        TextFieldKind::FileSelect
21    } else if flags.comb() {
22        TextFieldKind::Comb
23    } else if flags.rich_text() {
24        TextFieldKind::RichText
25    } else if flags.password() {
26        TextFieldKind::Password
27    } else if flags.multiline() {
28        TextFieldKind::Multiline
29    } else {
30        TextFieldKind::Normal
31    }
32}
33
34/// Get the current text value of a text field.
35pub fn get_text_value(tree: &FieldTree, id: FieldId) -> Option<String> {
36    match tree.effective_value(id)? {
37        FieldValue::Text(s) => Some(s.clone()),
38        FieldValue::StringArray(arr) => arr.first().cloned(),
39    }
40}
41
42/// Set a text field's value, enforcing MaxLen if present.
43/// Returns `false` if the field is read-only.
44pub fn set_text_value(tree: &mut FieldTree, id: FieldId, text: &str) -> bool {
45    if tree.effective_flags(id).read_only() {
46        return false;
47    }
48    let max_len = tree.effective_max_len(id);
49    let value = if let Some(ml) = max_len {
50        text.chars().take(ml as usize).collect()
51    } else {
52        text.to_string()
53    };
54    tree.get_mut(id).value = Some(FieldValue::Text(value));
55    true
56}
57
58/// For comb fields, compute the width of each cell.
59pub fn comb_cell_width(tree: &FieldTree, id: FieldId) -> Option<f32> {
60    let max_len = tree.effective_max_len(id)?;
61    if max_len == 0 {
62        return None;
63    }
64    let rect = tree.get(id).rect?;
65    Some((rect[2] - rect[0]) / max_len as f32)
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    fn make_text_tree() -> (FieldTree, FieldId) {
72        let mut tree = FieldTree::new();
73        let id = tree.alloc(FieldNode {
74            partial_name: "text1".into(),
75            alternate_name: None,
76            mapping_name: None,
77            field_type: Some(FieldType::Text),
78            flags: FieldFlags::empty(),
79            value: Some(FieldValue::Text("hello".into())),
80            default_value: None,
81            default_appearance: None,
82            quadding: None,
83            max_len: None,
84            options: vec![],
85            top_index: None,
86            rect: Some([0.0, 0.0, 200.0, 20.0]),
87            appearance_state: None,
88            page_index: None,
89            parent: None,
90            children: vec![],
91            object_id: None,
92            has_actions: false,
93            mk: None,
94            border_style: None,
95        });
96        (tree, id)
97    }
98
99    #[test]
100    fn get_value() {
101        let (tree, id) = make_text_tree();
102        assert_eq!(get_text_value(&tree, id), Some("hello".into()));
103    }
104    #[test]
105    fn set_value() {
106        let (mut tree, id) = make_text_tree();
107        assert!(set_text_value(&mut tree, id, "world"));
108        assert_eq!(get_text_value(&tree, id), Some("world".into()));
109    }
110    #[test]
111    fn set_value_readonly() {
112        let (mut tree, id) = make_text_tree();
113        tree.get_mut(id).flags = FieldFlags::from_bits(1);
114        assert!(!set_text_value(&mut tree, id, "nope"));
115    }
116    #[test]
117    fn set_value_maxlen() {
118        let (mut tree, id) = make_text_tree();
119        tree.get_mut(id).max_len = Some(3);
120        assert!(set_text_value(&mut tree, id, "abcdef"));
121        assert_eq!(get_text_value(&tree, id), Some("abc".into()));
122    }
123    #[test]
124    fn kind_detection() {
125        assert_eq!(text_field_kind(FieldFlags::empty()), TextFieldKind::Normal);
126        assert_eq!(
127            text_field_kind(FieldFlags::from_bits(1 << 12)),
128            TextFieldKind::Multiline
129        );
130        assert_eq!(
131            text_field_kind(FieldFlags::from_bits(1 << 13)),
132            TextFieldKind::Password
133        );
134        assert_eq!(
135            text_field_kind(FieldFlags::from_bits(1 << 24)),
136            TextFieldKind::Comb
137        );
138    }
139    #[test]
140    fn comb_width() {
141        let (mut tree, id) = make_text_tree();
142        tree.get_mut(id).max_len = Some(10);
143        assert_eq!(comb_cell_width(&tree, id), Some(20.0));
144    }
145}