place the selection panel beside what it describes
This commit is contained in:
76
src/lib/core/FloatingPanelPlacement.cpp
Normal file
76
src/lib/core/FloatingPanelPlacement.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "FloatingPanelPlacement.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
int getAvailableBottomPx(const QRect& band, const std::vector<QRect>& occupiedRects,
|
||||
int leftPx, int rightPx, int marginPx)
|
||||
{
|
||||
int bottomPx = band.bottom();
|
||||
for (const QRect& occupied : occupiedRects)
|
||||
{
|
||||
if (occupied.isEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Only what is actually in the way counts: a widget entirely to one side of this
|
||||
// span is not below it, however tall it is.
|
||||
if (occupied.right() < leftPx || occupied.left() > rightPx)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bottomPx = std::min(bottomPx, occupied.top() - marginPx - 1);
|
||||
}
|
||||
return bottomPx;
|
||||
}
|
||||
|
||||
PanelSide chooseSide(const QRect& band, const QRect& anchorRect, int widthPx,
|
||||
int marginPx)
|
||||
{
|
||||
// What each side offers: the gap between the anchor and that edge of the band, less
|
||||
// the margin the panel keeps from the anchor.
|
||||
const int roomRightPx = band.right() - anchorRect.right() - marginPx;
|
||||
const int roomLeftPx = anchorRect.left() - band.left() - marginPx;
|
||||
|
||||
if (roomRightPx >= widthPx)
|
||||
{
|
||||
return PanelSide::Right;
|
||||
}
|
||||
if (roomLeftPx >= widthPx)
|
||||
{
|
||||
return PanelSide::Left;
|
||||
}
|
||||
// Neither side can hold it without covering the selection, so it goes where it
|
||||
// covers the least of it.
|
||||
return (roomRightPx >= roomLeftPx) ? PanelSide::Right : PanelSide::Left;
|
||||
}
|
||||
|
||||
QRect placeBesideAnchor(const QRect& band, const QRect& anchorRect, PanelSide side,
|
||||
QSize wantedSize, const std::vector<QRect>& occupiedRects,
|
||||
int marginPx)
|
||||
{
|
||||
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));
|
||||
|
||||
// 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);
|
||||
}
|
||||
Reference in New Issue
Block a user