diff --git a/foo.improv b/foo.improv new file mode 100644 index 0000000..464b737 --- /dev/null +++ b/foo.improv @@ -0,0 +1,4562 @@ +{ + "name": "New Model", + "categories": { + "Type": { + "id": 0, + "name": "Type", + "items": { + "Food": { + "id": 0, + "name": "Food", + "group": null + }, + "Gas": { + "id": 1, + "name": "Gas", + "group": null + }, + "Medical": { + "id": 2, + "name": "Medical", + "group": null + }, + "Clothing": { + "id": 3, + "name": "Clothing", + "group": null + } + }, + "groups": [], + "next_item_id": 4 + }, + "Month": { + "id": 1, + "name": "Month", + "items": { + "Jan": { + "id": 0, + "name": "Jan", + "group": null + }, + "Feb": { + "id": 1, + "name": "Feb", + "group": null + }, + "Mar": { + "id": 2, + "name": "Mar", + "group": null + }, + "Apr": { + "id": 3, + "name": "Apr", + "group": null + }, + "May": { + "id": 4, + "name": "May", + "group": null + }, + "Jun": { + "id": 5, + "name": "Jun", + "group": null + } + }, + "groups": [], + "next_item_id": 6 + }, + "Recipient": { + "id": 2, + "name": "Recipient", + "items": { + "Joe": { + "id": 0, + "name": "Joe", + "group": null + }, + "Bob": { + "id": 1, + "name": "Bob", + "group": null + }, + "Alice": { + "id": 2, + "name": "Alice", + "group": null + }, + "Jane": { + "id": 3, + "name": "Jane", + "group": null + } + }, + "groups": [], + "next_item_id": 4 + }, + "Signer": { + "id": 3, + "name": "Signer", + "items": { + "Ed": { + "id": 0, + "name": "Ed", + "group": null + }, + "Bernadette": { + "id": 1, + "name": "Bernadette", + "group": null + } + }, + "groups": [], + "next_item_id": 2 + } + }, + "data": [ + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 9492.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 23425.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 756.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 2342.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 394.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 64.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 234.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 29.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 45.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 20.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 82.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 4940.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 495.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 4930.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 6343.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 4030.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 9628.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 453.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 76745.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 60.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 304.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 457.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 8655.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 9.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 49.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 8676.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 5658.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 12.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 23.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 492.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 63.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 39.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 3939.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 1.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 2346.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 233.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 920.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 34534.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 72.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 5335.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 575.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 304.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 3.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 9203.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 7655.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 9304.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 2974.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 920.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 49.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 23.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 22.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 3453.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 9304.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 5765.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 2957.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 293.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 203.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 21.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 65343.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 6533.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 6434.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 43.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 5738.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 12.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 543.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 304.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 6533.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 12312.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 8394.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 3494.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 543.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 3453.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 234.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 3959.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 234.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 49233.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 493.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 453543.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 5673.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 856.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 9203.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 9204.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 34.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 293.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 9602.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 920.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 453.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 8768689.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 646.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 4543.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 6594.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 545.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 34534.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 52.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 19.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 64.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 23.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 12.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 7645645.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 29394.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 9503.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 43.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 654.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 2342.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 345.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 23423.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 5.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 2343.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 72.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 544.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 593.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 53.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 234.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 34543.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 7665.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 293.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 405.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 65.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 7657.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 29394.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 234.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 62.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 940.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 23.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 2453.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 675.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 34.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 3424.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 232.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 2342.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 12331.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 684.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 53.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 92.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 84.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 788.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 23.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 34.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 594.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 39.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 4545.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 23.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 28492.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 5654.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 582.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 9402.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 5494.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 5464.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 345.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 23443.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 86940.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 673.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 3404.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 23456.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 40.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 653.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 3434.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 2937.0 + } + ], + [ + [ + [ + "Month", + "Jan" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 12.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 4343.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 463.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 353.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 34.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 9683.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 83.0 + } + ], + [ + [ + [ + "Month", + "Feb" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 83.0 + } + ], + [ + [ + [ + "Month", + "Mar" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Food" + ] + ], + { + "Number": 564373.0 + } + ], + [ + [ + [ + "Month", + "Apr" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 5645543.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 343.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Bob" + ], + [ + "Signer", + "Bernadette" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 3453.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Jane" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Gas" + ] + ], + { + "Number": 9204.0 + } + ], + [ + [ + [ + "Month", + "Jun" + ], + [ + "Recipient", + "Alice" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Clothing" + ] + ], + { + "Number": 4032.0 + } + ], + [ + [ + [ + "Month", + "May" + ], + [ + "Recipient", + "Joe" + ], + [ + "Signer", + "Ed" + ], + [ + "Type", + "Medical" + ] + ], + { + "Number": 2930.0 + } + ] + ], + "formulas": [], + "views": { + "Default": { + "name": "Default", + "category_axes": { + "Type": "column", + "Month": "row", + "Recipient": "column", + "Signer": "page" + }, + "page_selections": { + "Recipient": "Jane", + "Signer": "Ed" + }, + "hidden_items": {}, + "collapsed_groups": {}, + "number_format": ",.0", + "row_offset": 0, + "col_offset": 0, + "selected": [ + 0, + 0 + ] + } + }, + "active_view": "Default", + "next_category_id": 4 +} \ No newline at end of file diff --git a/src/ui/app.rs b/src/ui/app.rs index 507e187..9f81263 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -219,9 +219,11 @@ impl App { (KeyCode::Char('d'), KeyModifiers::CONTROL) => { self.scroll_rows(5); } (KeyCode::Char('u'), KeyModifiers::CONTROL) => { self.scroll_rows(-5); } + // Enter = advance (down, wrapping to top of next column) + (KeyCode::Enter, _) => { self.enter_advance(); } + // ── Editing ──────────────────────────────────────────────────── - (KeyCode::Enter, _) - | (KeyCode::Char('i'), KeyModifiers::NONE) + (KeyCode::Char('i'), KeyModifiers::NONE) | (KeyCode::Char('a'), KeyModifiers::NONE) => { let current = self.selected_cell_key() .and_then(|k| self.model.get_cell(&k).cloned()) @@ -1107,10 +1109,33 @@ impl App { self.mode = AppMode::ImportWizard; } + /// Advance selection down one row; when at the last row, wrap to row 0 of + /// the next column (typewriter-style). Does nothing if the grid is empty. + pub fn enter_advance(&mut self) { + let (row_max, col_max) = { + let layout = GridLayout::new(&self.model, self.model.active_view()); + (layout.row_count().saturating_sub(1), layout.col_count().saturating_sub(1)) + }; + let view = self.model.active_view_mut(); + let (r, c) = view.selected; + let (nr, nc) = if r < row_max { + (r + 1, c) + } else if c < col_max { + (0, c + 1) + } else { + (r, c) // already at bottom-right; stay + }; + view.selected = (nr, nc); + if nr < view.row_offset { view.row_offset = nr; } + if nr >= view.row_offset + 20 { view.row_offset = nr.saturating_sub(19); } + if nc < view.col_offset { view.col_offset = nc; } + if nc >= view.col_offset + 8 { view.col_offset = nc.saturating_sub(7); } + } + /// Hint text for the status bar (context-sensitive) pub fn hint_text(&self) -> &'static str { match &self.mode { - AppMode::Normal => "hjkl:nav i:edit x:clear /:search F/C/V:panels T:tiles [:]:page ::cmd", + AppMode::Normal => "hjkl:nav Enter:advance i:edit x:clear /:search F/C/V:panels T:tiles [:]:page ::cmd", AppMode::Editing { .. } => "Enter:commit Esc:cancel", AppMode::FormulaPanel => "n:new d:delete jk:nav Esc:back", AppMode::FormulaEdit { .. } => "Enter:save Esc:cancel — type: Name = expression", @@ -1126,3 +1151,45 @@ impl App { } } +#[cfg(test)] +mod tests { + use super::*; + use crate::model::Model; + + fn two_col_model() -> App { + let mut m = Model::new("T"); + m.add_category("Row").unwrap(); // → Row axis + m.add_category("Col").unwrap(); // → Column axis + m.category_mut("Row").unwrap().add_item("A"); + m.category_mut("Row").unwrap().add_item("B"); + m.category_mut("Row").unwrap().add_item("C"); + m.category_mut("Col").unwrap().add_item("X"); + m.category_mut("Col").unwrap().add_item("Y"); + App::new(m, None) + } + + #[test] + fn enter_advance_moves_down_within_column() { + let mut app = two_col_model(); + app.model.active_view_mut().selected = (0, 0); + app.enter_advance(); + assert_eq!(app.model.active_view().selected, (1, 0)); + } + + #[test] + fn enter_advance_wraps_to_top_of_next_column() { + let mut app = two_col_model(); + // row_max = 2 (A,B,C), col 0 → should wrap to (0, 1) + app.model.active_view_mut().selected = (2, 0); + app.enter_advance(); + assert_eq!(app.model.active_view().selected, (0, 1)); + } + + #[test] + fn enter_advance_stays_at_bottom_right() { + let mut app = two_col_model(); + app.model.active_view_mut().selected = (2, 1); + app.enter_advance(); + assert_eq!(app.model.active_view().selected, (2, 1)); + } +} diff --git a/src/ui/grid.rs b/src/ui/grid.rs index 845f6d7..28511b2 100644 --- a/src/ui/grid.rs +++ b/src/ui/grid.rs @@ -35,34 +35,53 @@ impl<'a> GridWidget<'a> { let col_offset = view.col_offset; let (fmt_comma, fmt_decimals) = parse_number_format(&view.number_format); + let n_col_levels = layout.col_cats.len().max(1); + let n_row_levels = layout.row_cats.len().max(1); + + // Sub-column widths for row header area + let sub_col_w = ROW_HEADER_WIDTH / n_row_levels as u16; + let sub_widths: Vec = (0..n_row_levels).map(|d| { + if d < n_row_levels - 1 { sub_col_w } + else { ROW_HEADER_WIDTH.saturating_sub(sub_col_w * (n_row_levels as u16 - 1)) } + }).collect(); + let available_cols = ((area.width.saturating_sub(ROW_HEADER_WIDTH)) / COL_WIDTH) as usize; let visible_col_range = col_offset..(col_offset + available_cols.max(1)).min(layout.col_count()); - let available_rows = area.height.saturating_sub(2) as usize; + let header_rows = n_col_levels as u16 + 1; // +1 for separator + let available_rows = area.height.saturating_sub(header_rows) as usize; let visible_row_range = row_offset..(row_offset + available_rows.max(1)).min(layout.row_count()); let mut y = area.y; - // Column headers + // Column headers — one row per level, with repeat suppression let header_style = Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD); - buf.set_string(area.x, y, - format!("{:width$}", truncate(&label, COL_WIDTH as usize), width = COL_WIDTH as usize), - styled); - x += COL_WIDTH; - if x >= area.x + area.width { break; } + for d in 0..n_col_levels { + buf.set_string(area.x, y, + format!("{:width$}", truncate(&label, COL_WIDTH as usize), width = COL_WIDTH as usize), + styled); + x += COL_WIDTH; + if x >= area.x + area.width { break; } + } + y += 1; } - y += 1; // Separator buf.set_string(area.x, y, @@ -74,15 +93,28 @@ impl<'a> GridWidget<'a> { for ri in visible_row_range.clone() { if y >= area.y + area.height { break; } - let row_label = layout.row_label(ri); let row_style = if ri == sel_row { Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD) } else { Style::default() }; - buf.set_string(area.x, y, - format!("{: