place the selection panel beside what it describes
The panel was anchored to the right edge of the view, which is nowhere near whatever the player just clicked. It now stands beside the selection: right of it where it fits, otherwise left, otherwise the roomier side pushed inside the view -- the one case where it covers part of what it describes. Nothing told the panel where the selection was. The selection events carry ids only, and the mode that separates a fresh selection from an expanded one is consumed inside SelectionController before they are built, so the view now publishes the selection's screen bounds itself, immediately before selecting and only when the selection is starting. Freezing that rectangle is what holds the panel still: it does not chase a scrolling view, a ship flying off, or a selection being added to. Only the panel's own size still moves it, and even then it keeps its side and the edge facing the selection. The rectangles come from what the renderer was already computing for the selection outlines, now shared rather than duplicated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JcReq7hVk4KUPhTDKWAG7K
This commit is contained in:
@@ -66,3 +66,91 @@ TEST_CASE("A widget filling the column leaves nothing", "[layout]")
|
||||
const std::vector<QRect> occupied = { QRect(0, 0, 1000, 600) };
|
||||
REQUIRE(getAvailableBottomPx(makeBand(), occupied, 0, 999, kMarginPx) == -9);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Which side of the selection the panel takes
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("The panel stands to the right of the selection where it fits", "[layout]")
|
||||
{
|
||||
// REQ-UI-SELECTION-PANEL: right of the anchor is the first choice.
|
||||
REQUIRE(chooseSide(makeBand(), QRect(100, 100, 60, 60), 300, kMarginPx)
|
||||
== PanelSide::Right);
|
||||
}
|
||||
|
||||
TEST_CASE("The panel goes left when the right cannot hold it", "[layout]")
|
||||
{
|
||||
// A selection near the right edge leaves 100 px there, not enough for a 300 px
|
||||
// panel, and the left is wide open.
|
||||
REQUIRE(chooseSide(makeBand(), QRect(880, 100, 20, 60), 300, kMarginPx)
|
||||
== PanelSide::Left);
|
||||
}
|
||||
|
||||
TEST_CASE("Fitting on neither side, the panel takes the roomier one", "[layout]")
|
||||
{
|
||||
// A bounding box spanning most of the view: 192 px free on the left, 92 on the
|
||||
// right, and a 300 px panel fits in neither. It covers as little as it can.
|
||||
REQUIRE(chooseSide(makeBand(), QRect(200, 100, 700, 200), 300, kMarginPx)
|
||||
== PanelSide::Left);
|
||||
REQUIRE(chooseSide(makeBand(), QRect(100, 100, 700, 200), 300, kMarginPx)
|
||||
== PanelSide::Right);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Where it then stands
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("The panel sits beside the anchor with its top edges aligned", "[layout]")
|
||||
{
|
||||
// REQ-UI-SELECTION-PANEL: separated by the margin, growing away from the selection,
|
||||
// top edge on the anchor's top edge.
|
||||
const QRect placed = placeBesideAnchor(makeBand(), QRect(100, 120, 60, 60),
|
||||
PanelSide::Right, QSize(300, 200), {},
|
||||
kMarginPx);
|
||||
REQUIRE(placed == QRect(168, 120, 300, 200));
|
||||
|
||||
const QRect placedLeft = placeBesideAnchor(makeBand(), QRect(500, 120, 60, 60),
|
||||
PanelSide::Left, QSize(300, 200), {},
|
||||
kMarginPx);
|
||||
REQUIRE(placedLeft == QRect(192, 120, 300, 200));
|
||||
}
|
||||
|
||||
TEST_CASE("A panel that would hang below the view is lifted", "[layout]")
|
||||
{
|
||||
// Top-aligning with a selection low in the view would put the panel's bottom past
|
||||
// the band, so it rises until it fits rather than overrunning it.
|
||||
const QRect placed = placeBesideAnchor(makeBand(), QRect(100, 500, 60, 60),
|
||||
PanelSide::Right, QSize(300, 200), {},
|
||||
kMarginPx);
|
||||
REQUIRE(placed == QRect(168, 400, 300, 200));
|
||||
}
|
||||
|
||||
TEST_CASE("A panel standing over another widget rises above it", "[layout]")
|
||||
{
|
||||
// The controls panel in the bottom-left is in the way of a panel placed to the left
|
||||
// of a selection: it clears the top of it by the margin (REQ-UI-CONTROLS-PANEL).
|
||||
const std::vector<QRect> occupied = { QRect(0, 300, 260, 300) };
|
||||
const QRect placed = placeBesideAnchor(makeBand(), QRect(500, 250, 60, 60),
|
||||
PanelSide::Left, QSize(300, 200), occupied,
|
||||
kMarginPx);
|
||||
REQUIRE(placed == QRect(192, 92, 300, 200));
|
||||
}
|
||||
|
||||
TEST_CASE("A panel taller than the space left is capped", "[layout]")
|
||||
{
|
||||
// Capping is the caller's cue to scroll: it asked for 700 and got what there was.
|
||||
const QRect placed = placeBesideAnchor(makeBand(), QRect(100, 100, 60, 60),
|
||||
PanelSide::Right, QSize(300, 700), {},
|
||||
kMarginPx);
|
||||
REQUIRE(placed == QRect(168, 0, 300, 600));
|
||||
}
|
||||
|
||||
TEST_CASE("A panel that fits on neither side is pushed inside the view", "[layout]")
|
||||
{
|
||||
// The one case where it covers part of the selection (REQ-UI-SELECTION-PANEL): it
|
||||
// stands as far from the anchor as the band allows, not off the edge of it.
|
||||
const QRect placed = placeBesideAnchor(makeBand(), QRect(100, 100, 700, 200),
|
||||
PanelSide::Right, QSize(300, 200), {},
|
||||
kMarginPx);
|
||||
REQUIRE(placed == QRect(700, 100, 300, 200));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user