Merge pull request #116 from storytold/fix/93-95-prepare-form
Prepare a form: Detect form fields in the panel, delete several fields at once (#93, #95)
This commit is contained in:
commit
3751978d0e
|
|
@ -323,6 +323,7 @@ pub static TOOL_GROUPS: &[ToolGroup] = &[
|
|||
title: "Fields",
|
||||
items: &[
|
||||
item("Field list", "list", "form.fields", Ready),
|
||||
item("Detect form fields", "scan", "form.detect", Ready),
|
||||
item("Clear form", "eraser", "form.clear", Ready),
|
||||
item("Field properties", "settings-2", "form.field.properties", Ready),
|
||||
item("Tab order by rows", "rows-3", "form.tab_order.row", Ready),
|
||||
|
|
|
|||
|
|
@ -1485,9 +1485,9 @@ pub fn document_area(app: &mut PrintCraftApp, index: usize, ui: &mut egui::Ui) {
|
|||
ui.close();
|
||||
}
|
||||
ui.separator();
|
||||
if ui.add_enabled(can_modify, egui::Button::new("Delete")).clicked() {
|
||||
view.prepare.selected = None;
|
||||
view.pending_edit = Some(printcraft_engine::Edit::DeleteField { name });
|
||||
let delete = if view.prepare.also.is_empty() { "Delete" } else { "Delete selected fields" };
|
||||
if ui.add_enabled(can_modify, egui::Button::new(delete)).clicked() {
|
||||
view.pending_edit = crate::prepare::delete_selected(view);
|
||||
ui.close();
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -498,16 +498,34 @@ pub(crate) fn paint_page(ui: &egui::Ui, painter: &egui::Painter, xf: &PageXform,
|
|||
}
|
||||
}
|
||||
|
||||
/// Delete removes the selected field; Escape clears the selection.
|
||||
/// Delete the selected field and every field selected with it (#95), as one undoable step, and
|
||||
/// clear the selection.
|
||||
pub(crate) fn delete_selected(view: &mut DocView) -> Option<Edit> {
|
||||
let (first, _) = view.prepare.selected.take()?;
|
||||
let mut names = vec![first];
|
||||
for (name, _) in std::mem::take(&mut view.prepare.also) {
|
||||
if !names.contains(&name) {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
if names.len() == 1 {
|
||||
return names.pop().map(|name| Edit::DeleteField { name });
|
||||
}
|
||||
let label = format!("Delete {} fields", names.len());
|
||||
Some(Edit::Batch { label, edits: names.into_iter().map(|name| Edit::DeleteField { name }).collect() })
|
||||
}
|
||||
|
||||
/// Delete removes the selected fields; Escape clears the selection.
|
||||
pub(crate) fn keys(ctx: &egui::Context, view: &mut DocView) {
|
||||
if view.prepare.selected.is_none() || ctx.egui_wants_keyboard_input() {
|
||||
return;
|
||||
}
|
||||
let (del, esc) = ctx.input(|i| (i.key_pressed(egui::Key::Delete) || i.key_pressed(egui::Key::Backspace), i.key_pressed(egui::Key::Escape)));
|
||||
if del && let Some((name, _)) = view.prepare.selected.take() {
|
||||
view.pending_edit = Some(Edit::DeleteField { name });
|
||||
if del {
|
||||
view.pending_edit = delete_selected(view);
|
||||
} else if esc {
|
||||
view.prepare.selected = None;
|
||||
view.prepare.also.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -285,6 +285,35 @@ fn aligning_distributing_and_sizing_several_fields() {
|
|||
assert!(arrange(&form(&h), &a, &[("b".into(), 0)], Arrange::DistributeV).is_none(), "distributing needs three");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deleting_several_selected_fields_and_detecting_fields_from_the_panel() {
|
||||
let mut h = harness();
|
||||
for (name, x) in [("a", 20.0), ("b", 120.0), ("c", 220.0)] {
|
||||
h.state_mut().apply_edit(printcraft_engine::Edit::AddField {
|
||||
page: 0,
|
||||
rect: [x, 300.0, x + 60.0, 320.0],
|
||||
kind: printcraft_engine::NewField::Text { multiline: false },
|
||||
name: Some(name.into()),
|
||||
});
|
||||
}
|
||||
assert!(h.state_mut().execute("form.prepare"));
|
||||
h.run_steps(2);
|
||||
// #93: field detection is in the panel, not only run when a form has no fields.
|
||||
h.get_by_label("Detect form fields");
|
||||
// #95: Delete removes every selected field, as one undoable step.
|
||||
{
|
||||
let p = &mut h.state_mut().views[0].prepare;
|
||||
p.selected = Some(("a".into(), 0));
|
||||
p.also = vec![("b".into(), 0), ("c".into(), 0)];
|
||||
}
|
||||
h.key_press(egui::Key::Delete);
|
||||
h.run_steps(3);
|
||||
let left = names(&h);
|
||||
assert!(!["a", "b", "c"].iter().any(|n| left.iter().any(|l| l == n)), "{left:?}");
|
||||
assert_eq!(h.state().session.get(h.state().views[0].id).unwrap().can_undo(), Some("Delete 3 fields"));
|
||||
assert!(h.state().views[0].prepare.selected.is_none() && h.state().views[0].prepare.also.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_fills_the_form_and_locked_fields_keep_their_properties() {
|
||||
let mut h = harness();
|
||||
|
|
|
|||
|
|
@ -4650,8 +4650,8 @@ milestone = "M6"
|
|||
status = "shipped"
|
||||
commands = ["form.prepare"]
|
||||
tools = ["form_add_field", "form_set_props", "form_delete_field"]
|
||||
evidence = ["crates/ui-egui/tests/prepare.rs::placing_moving_editing_and_deleting_a_field", "crates/engine/src/tests.rs::preparing_a_form_adds_renames_and_deletes_fields"]
|
||||
notes = "fields shown with blue fill and name tags; select, move, resize by corners, Delete; field tools return to Select after one field"
|
||||
evidence = ["crates/ui-egui/tests/prepare.rs::placing_moving_editing_and_deleting_a_field", "crates/ui-egui/tests/prepare.rs::deleting_several_selected_fields_and_detecting_fields_from_the_panel", "crates/engine/src/tests.rs::preparing_a_form_adds_renames_and_deletes_fields"]
|
||||
notes = "fields shown with blue fill and name tags; select, move, resize by corners, Delete (every selected field, one undo step); field tools return to Select after one field. Not yet: editing shared properties of several fields at once"
|
||||
|
||||
[[feature]]
|
||||
id = "form.add-text-field"
|
||||
|
|
@ -4986,8 +4986,8 @@ milestone = "M6"
|
|||
status = "partial"
|
||||
commands = ["form.detect", "form.prepare"]
|
||||
tools = ["form_detect_fields"]
|
||||
evidence = ["crates/forms/src/tests.rs::detection_finds_blanks_rules_boxes_and_names_them", "crates/engine/src/tests.rs::detecting_fields_on_a_printed_form", "crates/automation/tests/automation.rs::detecting_form_fields_through_tools", "crates/ui-egui/tests/javascript.rs::prepare_a_form_detects_fields_on_a_paper_form"]
|
||||
notes = "Underscore runs, rules, empty boxes and small squares (check boxes); runs when Prepare a form starts on a document without fields. Not yet: comb boxes, tables of cells, scanned forms (needs OCR first), radio groups."
|
||||
evidence = ["crates/forms/src/tests.rs::detection_finds_blanks_rules_boxes_and_names_them", "crates/engine/src/tests.rs::detecting_fields_on_a_printed_form", "crates/automation/tests/automation.rs::detecting_form_fields_through_tools", "crates/ui-egui/tests/javascript.rs::prepare_a_form_detects_fields_on_a_paper_form", "crates/ui-egui/tests/prepare.rs::deleting_several_selected_fields_and_detecting_fields_from_the_panel"]
|
||||
notes = "Underscore runs, rules, empty boxes and small squares (check boxes); runs when Prepare a form starts on a document without fields, and from Prepare a form ▸ Detect form fields at any time (existing fields are skipped). Not yet: comb boxes, tables of cells, scanned forms (needs OCR first), radio groups."
|
||||
|
||||
[[feature]]
|
||||
id = "form.auto-name-fields"
|
||||
|
|
|
|||
Loading…
Reference in New Issue