| 1393 |
1393 |
|
}
|
| 1394 |
1394 |
|
}
|
| 1395 |
1395 |
|
|
|
1396 |
+ |
/// A band whose members were said to share one row.
|
|
1397 |
+ |
fn run_of(fallback: layout::Fallback, members: [(&str, layout::Priority); 3]) -> Screen {
|
|
1398 |
+ |
let mut band = Slot::new("bar", RegionKind::Band).across(fallback);
|
|
1399 |
+ |
for (label, priority) in members {
|
|
1400 |
+ |
band = band.beside(
|
|
1401 |
+ |
Node::Act(Act::new(label, Action::post(format!("/{label}")))),
|
|
1402 |
+ |
priority,
|
|
1403 |
+ |
);
|
|
1404 |
+ |
}
|
|
1405 |
+ |
Screen::sidebar_content("Test").with(band)
|
|
1406 |
+ |
}
|
|
1407 |
+ |
|
|
1408 |
+ |
#[test]
|
|
1409 |
+ |
fn a_member_of_a_run_is_drawn_at_all() {
|
|
1410 |
+ |
// The defect: `region` walked `body` and nothing walked `run`, so a
|
|
1411 |
+ |
// description that said `across` and then `part` contributed controls that
|
|
1412 |
+ |
// were never painted and could never be pressed. `Row::menu`'s bug of
|
|
1413 |
+ |
// 2026-08-17 in a second place, and silent in the same way.
|
|
1414 |
+ |
let screen = run_of(
|
|
1415 |
+ |
layout::Fallback::Wrap,
|
|
1416 |
+ |
[
|
|
1417 |
+ |
("Import", layout::Priority::Essential),
|
|
1418 |
+ |
("Export", layout::Priority::Essential),
|
|
1419 |
+ |
("Settings", layout::Priority::Essential),
|
|
1420 |
+ |
],
|
|
1421 |
+ |
);
|
|
1422 |
+ |
let mut host = Host::new();
|
|
1423 |
+ |
host.settle(&screen);
|
|
1424 |
+ |
|
|
1425 |
+ |
assert_eq!(
|
|
1426 |
+ |
host.click(&screen, "Export").map(|fired| fired.action),
|
|
1427 |
+ |
Some(Action::post("/Export")),
|
|
1428 |
+ |
"a described control in a row must send what it said it sends"
|
|
1429 |
+ |
);
|
|
1430 |
+ |
}
|
|
1431 |
+ |
|
|
1432 |
+ |
#[test]
|
|
1433 |
+ |
fn a_run_puts_its_members_across_rather_than_down() {
|
|
1434 |
+ |
// What the row is for. Three controls in a band drew one per line before
|
|
1435 |
+ |
// this, which is the shape a toolbar is not.
|
|
1436 |
+ |
let screen = run_of(
|
|
1437 |
+ |
layout::Fallback::Wrap,
|
|
1438 |
+ |
[
|
|
1439 |
+ |
("Import", layout::Priority::Essential),
|
|
1440 |
+ |
("Export", layout::Priority::Essential),
|
|
1441 |
+ |
("Settings", layout::Priority::Essential),
|
|
1442 |
+ |
],
|
|
1443 |
+ |
);
|
|
1444 |
+ |
let mut host = Host::new();
|
|
1445 |
+ |
host.settle(&screen);
|
|
1446 |
+ |
|
|
1447 |
+ |
let first = host.find("Import");
|
|
1448 |
+ |
let second = host.find("Export");
|
|
1449 |
+ |
let third = host.find("Settings");
|
|
1450 |
+ |
assert!(
|
|
1451 |
+ |
(first.y - second.y).abs() < 1.0 && (second.y - third.y).abs() < 1.0,
|
|
1452 |
+ |
"the members left the row: {first:?} {second:?} {third:?}"
|
|
1453 |
+ |
);
|
|
1454 |
+ |
assert!(
|
|
1455 |
+ |
first.x < second.x && second.x < third.x,
|
|
1456 |
+ |
"the members are out of the order they were said in: {first:?} {second:?} {third:?}"
|
|
1457 |
+ |
);
|
|
1458 |
+ |
}
|
|
1459 |
+ |
|
|
1460 |
+ |
#[test]
|
|
1461 |
+ |
fn a_run_that_sheds_keeps_what_the_description_called_essential() {
|
|
1462 |
+ |
// The half a webview cannot do at all: there is no
|
|
1463 |
+ |
// `@container (inline-size < min-content)`, so `Shed` wraps there. This
|
|
1464 |
+ |
// renderer is holding the width, so it can honour the word.
|
|
1465 |
+ |
let screen = run_of(
|
|
1466 |
+ |
layout::Fallback::Shed,
|
|
1467 |
+ |
[
|
|
1468 |
+ |
("Import", layout::Priority::Essential),
|
|
1469 |
+ |
("Export", layout::Priority::Secondary),
|
|
1470 |
+ |
("Settings", layout::Priority::Optional),
|
|
1471 |
+ |
],
|
|
1472 |
+ |
);
|
|
1473 |
+ |
let ctx = egui::Context::default();
|
|
1474 |
+ |
let immediate = renderer();
|
|
1475 |
+ |
|
|
1476 |
+ |
let narrow = painted(&ctx, &immediate, &screen, &mut View::new(), 500.0);
|
|
1477 |
+ |
assert!(narrow.contains("Import"), "the essential member was shed");
|
|
1478 |
+ |
assert!(
|
|
1479 |
+ |
!narrow.contains("Export") && !narrow.contains("Settings"),
|
|
1480 |
+ |
"a shed row kept what it said it would drop: {narrow}"
|
|
1481 |
+ |
);
|
|
1482 |
+ |
|
|
1483 |
+ |
// And nothing is dropped when there is room for all three, or the cutoff
|
|
1484 |
+ |
// would be a permanent narrowing rather than a measurement.
|
|
1485 |
+ |
let wide = painted(&ctx, &immediate, &screen, &mut View::new(), 1000.0);
|
|
1486 |
+ |
assert!(
|
|
1487 |
+ |
wide.contains("Export") && wide.contains("Settings"),
|
|
1488 |
+ |
"{wide}"
|
|
1489 |
+ |
);
|
|
1490 |
+ |
}
|
|
1491 |
+ |
|
|
1492 |
+ |
#[test]
|
|
1493 |
+ |
fn a_run_that_menus_keeps_every_member_reachable() {
|
|
1494 |
+ |
// `Shed` and `Menu` drop the same members. What separates them is where the
|
|
1495 |
+ |
// dropped ones go, and a `Menu` that dropped them on the floor would be
|
|
1496 |
+ |
// this renderer answering with `Shed`.
|
|
1497 |
+ |
let screen = run_of(
|
|
1498 |
+ |
layout::Fallback::Menu,
|
|
1499 |
+ |
[
|
|
1500 |
+ |
("Import", layout::Priority::Essential),
|
|
1501 |
+ |
("Export", layout::Priority::Secondary),
|
|
1502 |
+ |
("Settings", layout::Priority::Optional),
|
|
1503 |
+ |
],
|
|
1504 |
+ |
);
|
|
1505 |
+ |
let ctx = egui::Context::default();
|
|
1506 |
+ |
let immediate = renderer();
|
|
1507 |
+ |
|
|
1508 |
+ |
let narrow = painted(&ctx, &immediate, &screen, &mut View::new(), 500.0);
|
|
1509 |
+ |
assert!(narrow.contains("Import"));
|
|
1510 |
+ |
assert!(
|
|
1511 |
+ |
narrow.contains("2 more"),
|
|
1512 |
+ |
"the two shed members went nowhere a reader could follow: {narrow}"
|
|
1513 |
+ |
);
|
|
1514 |
+ |
}
|
|
1515 |
+ |
|
|
1516 |
+ |
#[test]
|
|
1517 |
+ |
fn a_region_with_no_run_draws_exactly_what_it_did_before() {
|
|
1518 |
+ |
// The change is additive at the call site, so a description written before
|
|
1519 |
+ |
// runs existed must paint the same picture.
|
|
1520 |
+ |
let screen = screen_of([Node::Act(Act::new("Save", Action::post("/save")))]);
|
|
1521 |
+ |
let ctx = egui::Context::default();
|
|
1522 |
+ |
let immediate = renderer();
|
|
1523 |
+ |
|
|
1524 |
+ |
let before = painted(&ctx, &immediate, &screen, &mut View::new(), 900.0);
|
|
1525 |
+ |
assert!(before.contains("Save"));
|
|
1526 |
+ |
assert!(
|
|
1527 |
+ |
!before.contains("more"),
|
|
1528 |
+ |
"a region with no run grew a control out of nothing: {before}"
|
|
1529 |
+ |
);
|
|
1530 |
+ |
}
|
|
1531 |
+ |
|
| 1396 |
1532 |
|
/// A list of two rows, the first offering both an opening route and a menu.
|
| 1397 |
1533 |
|
fn menu_list() -> Screen {
|
| 1398 |
1534 |
|
use quasi_router::Row;
|