mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-31 07:39:08 +00:00
M6: calculation checks: the page's steps are chosen by a function the tests reach
steps() takes the widgets by object, so each of two fields sharing a name gets its own step; a test checks it, unfocused and with a focus (from the review: no test failed with the step looked up by name). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P6yUtvWGPsJpMLyh6pxSXG
This commit is contained in:
1 parent
50a4a19a1a
commit
fefb99a786
1 file changed
+43
-10
@@ -920,16 +920,9 @@ pub(crate) fn paint_page(
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k, (f, row)) in listed.order.fields.iter().zip(&listed.rows).enumerate() {
|
||||
let Some(r) = by_obj.get(&f.obj) else { continue };
|
||||
let shown = match &focused {
|
||||
Some((_, related)) => related(f.name.as_str(), f.obj),
|
||||
None => row.tone != Tone::Ok || !f.listed,
|
||||
};
|
||||
if !shown {
|
||||
continue;
|
||||
}
|
||||
let fill = match row.tone {
|
||||
let related = focused.as_ref().map(|(_, related)| related as Related<'_>);
|
||||
for (k, r, tone) in steps(&listed, &by_obj, related) {
|
||||
let fill = match tone {
|
||||
Tone::Ok => STEP,
|
||||
Tone::Late => LINK_LATE,
|
||||
Tone::Loop | Tone::Missing => LINK_LOOP,
|
||||
@@ -943,6 +936,27 @@ pub(crate) fn paint_page(
|
||||
hovered
|
||||
}
|
||||
|
||||
/// Whether a field, by name and object, is at an end of the focus's links or is the focus.
|
||||
type Related<'a> = &'a dyn Fn(&str, ObjRef) -> bool;
|
||||
|
||||
/// The steps the page shows: each one's place in the order (from 0), the widget it goes on (its
|
||||
/// own field's, so fields that share a name each get theirs) and its tone. With a focus, the
|
||||
/// steps of the fields `related` to it; without one, those whose place is wrong.
|
||||
fn steps(listed: &Listed, by_obj: &HashMap<ObjRef, Rect>, related: Option<Related<'_>>) -> Vec<(usize, Rect, Tone)> {
|
||||
listed
|
||||
.order
|
||||
.fields
|
||||
.iter()
|
||||
.zip(&listed.rows)
|
||||
.enumerate()
|
||||
.filter(|(_, (f, row))| match related {
|
||||
Some(related) => related(&f.name, f.obj),
|
||||
None => row.tone != Tone::Ok || !f.listed,
|
||||
})
|
||||
.filter_map(|(k, (f, row))| Some((k, *by_obj.get(&f.obj)?, row.tone)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Where a ray from `r`'s centre in direction `dir` (a unit vector) leaves `r`.
|
||||
fn edge(r: Rect, dir: Vec2) -> Pos2 {
|
||||
let half = r.size() / 2.0;
|
||||
@@ -1166,6 +1180,25 @@ mod tests {
|
||||
assert!(related("total", first) && related("total", second) && related("tax", elsewhere), "a selected name is every field of it");
|
||||
}
|
||||
|
||||
/// Each step goes on its own field's widget: two fields named `total` get one each, and a
|
||||
/// focus on one shows its step and its reader's, not the other's.
|
||||
#[test]
|
||||
fn a_step_goes_on_its_own_field_when_names_are_shared() {
|
||||
let (calculated, links) = two_totals();
|
||||
let [first, second, grand] = calculated.each_ref().map(|f| f.obj);
|
||||
let at = |x: f32| Rect::from_min_size(pos2(x, 0.0), vec2(10.0, 10.0));
|
||||
let by_obj = HashMap::from([(first, at(0.0)), (second, at(100.0)), (grand, at(200.0))]);
|
||||
let rows = rows(&calculated, &[]);
|
||||
let mut order = CalculationOrder::default();
|
||||
order.fields = calculated.to_vec();
|
||||
let listed = Listed { order, rows, links };
|
||||
// Unfocused, the two broken formulas show their steps.
|
||||
assert_eq!(steps(&listed, &by_obj, None), [(0, at(0.0), Tone::Missing), (1, at(100.0), Tone::Missing)]);
|
||||
let focus = Focus::row(&calculated[0]);
|
||||
let (_, related) = focus_links(&listed.links, &focus);
|
||||
assert_eq!(steps(&listed, &by_obj, Some(&related)), [(0, at(0.0), Tone::Missing), (2, at(200.0), Tone::Ok)]);
|
||||
}
|
||||
|
||||
/// A missing field outranks a loop on the row, but the field is still in its loop.
|
||||
#[test]
|
||||
fn a_missing_field_marks_the_row_and_keeps_its_loop() {
|
||||
|
||||
Reference in new issue
Block a user