allow to move the selection panel via mouse drag
This commit is contained in:
@@ -2,6 +2,39 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// The part every placement shares, whatever put the panel where it wants to be: it is
|
||||
// pushed inside band rather than hanging off it, shortened to what its own column has
|
||||
// free, and lifted by however much of it hangs below that. wantedLeftPx and wantedTopPx
|
||||
// are where the panel would stand if nothing were in the way.
|
||||
QRect fitInBand(const QRect& band, int wantedLeftPx, int wantedTopPx, QSize wantedSize,
|
||||
const std::vector<QRect>& occupiedRects, int marginPx)
|
||||
{
|
||||
const int widthPx = std::min(wantedSize.width(), band.width());
|
||||
|
||||
int leftPx = std::min(wantedLeftPx, band.right() - widthPx + 1);
|
||||
leftPx = std::max(leftPx, band.left());
|
||||
|
||||
// Only the widgets its own column meets can shorten it.
|
||||
const int bottomPx = getAvailableBottomPx(band, occupiedRects, leftPx,
|
||||
leftPx + widthPx - 1, marginPx);
|
||||
const int heightPx =
|
||||
std::min(wantedSize.height(), std::max(0, bottomPx - band.top() + 1));
|
||||
|
||||
// Never above the band: a panel taller than the space left is capped instead, and
|
||||
// scrolls.
|
||||
int topPx = std::max(wantedTopPx, band.top());
|
||||
topPx = std::min(topPx, bottomPx - heightPx + 1);
|
||||
topPx = std::max(topPx, band.top());
|
||||
|
||||
return QRect(leftPx, topPx, widthPx, heightPx);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
int getAvailableBottomPx(const QRect& band, const std::vector<QRect>& occupiedRects,
|
||||
int leftPx, int rightPx, int marginPx)
|
||||
{
|
||||
@@ -51,26 +84,27 @@ QRect placeBesideAnchor(const QRect& band, const QRect& anchorRect, PanelSide si
|
||||
const int widthPx = std::min(wantedSize.width(), band.width());
|
||||
|
||||
// Against the anchor on the chosen side, growing away from it: the edge facing the
|
||||
// selection is the one that stays put as the panel's content resizes.
|
||||
int leftPx = (side == PanelSide::Right) ? anchorRect.right() + marginPx + 1
|
||||
: anchorRect.left() - marginPx - widthPx;
|
||||
// A panel that does not fit there is pushed back inside the view rather than hanging
|
||||
// off it, which is what puts it over the selection when neither side had room.
|
||||
leftPx = std::min(leftPx, band.right() - widthPx + 1);
|
||||
leftPx = std::max(leftPx, band.left());
|
||||
|
||||
// Only the widgets its own column meets can shorten it.
|
||||
const int bottomPx = getAvailableBottomPx(band, occupiedRects, leftPx,
|
||||
leftPx + widthPx - 1, marginPx);
|
||||
const int heightPx =
|
||||
std::min(wantedSize.height(), std::max(0, bottomPx - band.top() + 1));
|
||||
// selection is the one that stays put as the panel's content resizes. A panel that
|
||||
// does not fit there is pushed back inside the view rather than hanging off it, which
|
||||
// is what puts it over the selection when neither side had room.
|
||||
const int wantedLeftPx = (side == PanelSide::Right)
|
||||
? anchorRect.right() + marginPx + 1
|
||||
: anchorRect.left() - marginPx - widthPx;
|
||||
|
||||
// Top-aligned with the anchor, then lifted by however much of it hangs below what is
|
||||
// free. Never above the band: a panel taller than the space left is capped instead,
|
||||
// and scrolls.
|
||||
int topPx = std::max(anchorRect.top(), band.top());
|
||||
topPx = std::min(topPx, bottomPx - heightPx + 1);
|
||||
topPx = std::max(topPx, band.top());
|
||||
|
||||
return QRect(leftPx, topPx, widthPx, heightPx);
|
||||
// free.
|
||||
return fitInBand(band, wantedLeftPx, anchorRect.top(), wantedSize, occupiedRects,
|
||||
marginPx);
|
||||
}
|
||||
|
||||
QRect placeAtDesiredTopLeft(const QRect& band, const QPoint& desiredTopLeftPx,
|
||||
QSize wantedSize, const std::vector<QRect>& occupiedRects,
|
||||
int marginPx)
|
||||
{
|
||||
// Where the player dropped it, resolved by the same rules as any other placement
|
||||
// (REQ-UI-SELECTION-PANEL-DRAG). Nothing here is written back to the desired point:
|
||||
// a panel lifted above the build button bar returns to where it was dropped as soon
|
||||
// as the bar stops meeting its column.
|
||||
return fitInBand(band, desiredTopLeftPx.x(), desiredTopLeftPx.y(), wantedSize,
|
||||
occupiedRects, marginPx);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QSize>
|
||||
|
||||
@@ -41,3 +42,13 @@ PanelSide chooseSide(const QRect& band, const QRect& anchorRect, int widthPx,
|
||||
QRect placeBesideAnchor(const QRect& band, const QRect& anchorRect, PanelSide side,
|
||||
QSize wantedSize, const std::vector<QRect>& occupiedRects,
|
||||
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<QRect>& occupiedRects,
|
||||
int marginPx);
|
||||
|
||||
Reference in New Issue
Block a user