#pragma once #include #include #include #include // Geometry for the widgets floating over the game world view (REQ-UI-WORLD-SIZE). Their // owner places them in one ordered pass, each into the space the earlier ones left free, // and these are the rules they place themselves by. Pure geometry -- no widget is // involved, which is what lets the rules be tested without a display. // // Two distances run through these rules and are deliberately different (see // REQ-UI-SELECTION-PANEL). marginPx is the edge margin: what a widget keeps from the // view's edges and from the widgets it steps around. selectionGapPx is the gap the // selection panel keeps from the selection it describes -- half a tile, which is the // wider of the two, so the panel stands clear of the objects rather than touching them. // The lowest bottom edge available to a widget occupying the horizontal span // [leftPx, rightPx] inside band: the band's own bottom, or marginPx above the topmost // occupied rectangle whose horizontal extent meets that span. A rectangle beside the // span is not in the way and does not shorten it (REQ-UI-SELECTION-PANEL, // REQ-UI-CONTROLS-PANEL). The result is inclusive, as QRect::bottom() is. int getAvailableBottomPx(const QRect& band, const std::vector& occupiedRects, int leftPx, int rightPx, int marginPx); // Which side of the selection the panel stands on (REQ-UI-SELECTION-PANEL). enum class PanelSide { Right, Left }; // The side a panel widthPx wide takes beside anchorRect: the right of it where it fits // within band, otherwise the left, and where it fits on neither, whichever side leaves // more room -- the one case in which the panel ends up over the selection // (REQ-UI-SELECTION-PANEL). The room a side offers is what is left of it once the panel's // gap from the selection is taken off. Decided once when the selection starts and kept for // as long as it lasts, so a card that grows later never flips the panel across the object. PanelSide chooseSide(const QRect& band, const QRect& anchorRect, int widthPx, int selectionGapPx); // Where a panel of wantedSize stands beside anchorRect on the given side: separated from // it by selectionGapPx and growing away from it, its top edge on the anchor's top edge, // pushed inside band and above whatever occupies it. The gap is horizontal only -- the // panel's top sits level with the anchor's, however wide the gap. The returned height is // short of wantedSize's when there was not enough room, which is the caller's cue to // scroll its content (REQ-UI-SELECTION-PANEL). QRect placeBesideAnchor(const QRect& band, const QRect& anchorRect, PanelSide side, QSize wantedSize, const std::vector& occupiedRects, int selectionGapPx, int marginPx); // Where a panel of wantedSize stands once the player has dragged it to desiredTopLeftPx: // at that point, by the same rules that place it beside a selection -- pushed inside band, // lifted above whatever occupies its column, and capped in height where that leaves too // little room (REQ-UI-SELECTION-PANEL-DRAG). The desired point is an input only: it is // never corrected and handed back, which is what lets the caller keep it exactly as // dropped and return to it once the room is there again. QRect placeAtDesiredTopLeft(const QRect& band, const QPoint& desiredTopLeftPx, QSize wantedSize, const std::vector& occupiedRects, int marginPx);