WIP: Anchor.cpp now builds
This commit is contained in:
@@ -538,276 +538,13 @@ int MultiSplitterLayout::placeholderCount() const
|
||||
return count() - visibleCount();
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::removeAnchor(Anchor *anchor)
|
||||
{
|
||||
if (!m_inDestructor)
|
||||
m_anchors.removeOne(anchor);
|
||||
}
|
||||
|
||||
QPair<int, int> MultiSplitterLayout::boundPositionsForAnchor(Anchor *anchor) const
|
||||
{
|
||||
if (anchor->isStatic()) {
|
||||
if (anchor == m_leftAnchor || anchor == m_topAnchor) {
|
||||
return {0, 0};
|
||||
} else if (anchor == m_rightAnchor || anchor == m_bottomAnchor) {
|
||||
const int max = length(anchor->orientation()) - Anchor::thickness(true);
|
||||
return {max, max};
|
||||
}
|
||||
}
|
||||
|
||||
if (anchor->isFollowing())
|
||||
anchor = anchor->endFollowee();
|
||||
|
||||
const int minSide1Length = anchor->cumulativeMinLength(Anchor::Side1);
|
||||
const int minSide2Length = anchor->cumulativeMinLength(Anchor::Side2);
|
||||
const int length = anchor->isVertical() ? width() : height();
|
||||
|
||||
const int bound1 = qMax(0, minSide1Length - anchor->thickness());
|
||||
const int bound2 = qMax(0, length - minSide2Length);
|
||||
|
||||
if (bound2 < bound1) {
|
||||
qWarning() << Q_FUNC_INFO << "Invalid bounds"
|
||||
<< "; bound1=" << bound1
|
||||
<< "; bound2=" << bound2
|
||||
<< "; layout.size=" << size()
|
||||
<< "; layout.min=" << minimumSize()
|
||||
<< "; anchor=" << anchor
|
||||
<< "; orientation=" << anchor->orientation()
|
||||
<< "; minSide1Length=" << minSide1Length
|
||||
<< "; minSide2Length=" << minSide2Length
|
||||
<< "; side1=" << anchor->side1Items()
|
||||
<< "; side2=" << anchor->side2Items()
|
||||
<< "; followee=" << anchor->followee()
|
||||
<< "; thickness=" << anchor->thickness();
|
||||
}
|
||||
|
||||
return { bound1, bound2 };
|
||||
}
|
||||
|
||||
QHash<Anchor *, QPair<int, int> > MultiSplitterLayout::boundPositionsForAllAnchors() const
|
||||
{
|
||||
QHash<Anchor *, QPair<int, int> > result;
|
||||
for (Anchor *anchor : m_anchors)
|
||||
result.insert(anchor, boundPositionsForAnchor(anchor));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int MultiSplitterLayout::boundPositionForAnchor(Anchor *anchor, Anchor::Side direction) const
|
||||
{
|
||||
auto bounds = boundPositionsForAnchor(anchor);
|
||||
return direction == Anchor::Side1 ? bounds.first
|
||||
: bounds.second;
|
||||
}
|
||||
|
||||
MultiSplitterLayout::Length MultiSplitterLayout::availableLengthForDrop(Location location, const Item *relativeTo) const
|
||||
{
|
||||
Length result;
|
||||
|
||||
const bool relativeToThis = relativeTo == nullptr;
|
||||
|
||||
AnchorGroup anchors = relativeToThis ? staticAnchorGroup()
|
||||
: relativeTo->anchorGroup();
|
||||
|
||||
Anchor *anchor = nullptr;
|
||||
|
||||
int thisLength = 0;
|
||||
|
||||
switch (location) {
|
||||
case KDDockWidgets::Location_None:
|
||||
qWarning() << "MultiSplitterLayout::availableLengthForDrop invalid location for dropping";
|
||||
return result;
|
||||
case KDDockWidgets::Location_OnLeft:
|
||||
anchor = anchors.left;
|
||||
thisLength = width();
|
||||
break;
|
||||
case KDDockWidgets::Location_OnTop:
|
||||
anchor = anchors.top;
|
||||
thisLength = height();
|
||||
break;
|
||||
case KDDockWidgets::Location_OnRight:
|
||||
anchor = anchors.right;
|
||||
thisLength = width();
|
||||
break;
|
||||
case KDDockWidgets::Location_OnBottom:
|
||||
anchor = anchors.bottom;
|
||||
thisLength = height();
|
||||
break;
|
||||
}
|
||||
|
||||
anchor = anchor->isFollowing() ? anchor->endFollowee() : anchor;
|
||||
|
||||
const int minForAlreadyOccupied1 = anchor->cumulativeMinLength(Anchor::Side1) - anchor->thickness(); // TODO: Check if this is correct, we're discounting the anchor twice
|
||||
const int minForAlreadyOccupied2 = anchor->cumulativeMinLength(Anchor::Side2) - anchor->thickness();
|
||||
|
||||
const int side1AvailableLength = anchor->position() - minForAlreadyOccupied1;
|
||||
const int side2AvailableLength = thisLength - (anchor->position() + anchor->thickness()) - minForAlreadyOccupied2;
|
||||
|
||||
const bool needsNewAnchor = hasVisibleItems(); // If a new anchor is needed then we need space for the drag handle and such.
|
||||
const int newAnchorThickness = needsNewAnchor ? Anchor::thickness(/*static=*/false) : 0;
|
||||
|
||||
// This useless space doesn't belong to side1 or side2 specifically. So account for it separately.
|
||||
const int unusableSpace = newAnchorThickness;
|
||||
|
||||
const int usableLength = qMax(0, side1AvailableLength + side2AvailableLength - unusableSpace);
|
||||
if (usableLength > 0) {
|
||||
qreal factor = (side1AvailableLength * 1.0) / (side1AvailableLength + side2AvailableLength);
|
||||
result.side1Length = int(qRound(usableLength * factor)); // rounding not really needed, but makes things more fair probably
|
||||
result.side2Length = usableLength - result.side1Length;
|
||||
}
|
||||
|
||||
qCDebug(sizing) << Q_FUNC_INFO
|
||||
<< "; available=" << result.length() << result.side1Length << result.side2Length
|
||||
<< "; side1AvailableLength=" << side1AvailableLength
|
||||
<< "; side2AvailableLength=" << side2AvailableLength
|
||||
<< "; minForAlreadyOccupied1=" << minForAlreadyOccupied1
|
||||
<< "; minForAlreadyOccupied2=" << minForAlreadyOccupied2
|
||||
<< "; thisLength=" << thisLength
|
||||
<< "; anchorPos=" << anchor->position()
|
||||
<< "; unusableSpace=" << unusableSpace;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int MultiSplitterLayout::availableLengthForOrientation(Qt::Orientation orientation) const
|
||||
{
|
||||
Length l = availableLengthForDrop(orientation == Qt::Vertical ? Location_OnLeft
|
||||
: Location_OnTop, nullptr);
|
||||
|
||||
return l.length();
|
||||
}
|
||||
|
||||
QSize MultiSplitterLayout::availableSize() const
|
||||
{
|
||||
return { availableLengthForOrientation(Qt::Vertical), availableLengthForOrientation(Qt::Horizontal) };
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the width or height the widget will get when dropped.
|
||||
*/
|
||||
MultiSplitterLayout::Length MultiSplitterLayout::lengthForDrop(const QWidgetOrQuick *widget, Location location,
|
||||
const Item *relativeTo) const
|
||||
{
|
||||
Q_ASSERT(location != Location_None);
|
||||
|
||||
const Qt::Orientation anchorOrientation = anchorOrientationForLocation(location);
|
||||
const int widgetCurrentLength = widgetLength(widget, anchorOrientation);
|
||||
Length available = availableLengthForDrop(location, relativeTo);
|
||||
|
||||
const int requiredAtLeast = widgetMinLength(widget, anchorOrientation);
|
||||
if (available.length() < requiredAtLeast) {
|
||||
qCDebug(sizing) << Q_FUNC_INFO
|
||||
<< "\n Not enough space. available=" << available.length()
|
||||
<< "; required=" << requiredAtLeast
|
||||
<< "; m_size=" << m_size;
|
||||
return {};
|
||||
}
|
||||
|
||||
const int suggestedLength = qMin(widgetCurrentLength, int(0.4 * length(anchorOrientation)));
|
||||
available.setLength(qBound(requiredAtLeast, suggestedLength, available.length()));
|
||||
|
||||
qCDebug(sizing) << "MultiSplitterLayout::lengthForDrop length=" << available.length()
|
||||
<< "; s1=" << available.side1Length << "; s2="<< available.side2Length
|
||||
<< "; relativeTo=" << relativeTo
|
||||
<< "; relativeTo.geo=" << (relativeTo ? relativeTo->geometry() : QRect())
|
||||
<< "; widgetCurrentLength=" << widgetCurrentLength;
|
||||
return available;
|
||||
}
|
||||
|
||||
QRect MultiSplitterLayout::rectForDrop(MultiSplitterLayout::Length lfd, Location location, QRect relativeToRect) const
|
||||
{
|
||||
QRect result;
|
||||
const int widgetLength = lfd.length();
|
||||
const int newAnchorThickness = isEmpty() ? 0 : Anchor::thickness(/*static=*/false);
|
||||
const int side1Length = lfd.side1Length;
|
||||
const int staticAnchorThickness = Anchor::thickness(/**static=*/true);
|
||||
|
||||
switch (location) {
|
||||
case Location_OnLeft:
|
||||
result = QRect(qMax(0, relativeToRect.x() - side1Length), relativeToRect.y(),
|
||||
widgetLength, relativeToRect.height());
|
||||
break;
|
||||
case Location_OnTop:
|
||||
result = QRect(relativeToRect.x(), qMax(0, relativeToRect.y() - side1Length),
|
||||
relativeToRect.width(), widgetLength);
|
||||
break;
|
||||
case Location_OnRight:
|
||||
result = QRect(qMin(relativeToRect.right() + 1 - side1Length + newAnchorThickness,
|
||||
width() - widgetLength - staticAnchorThickness), relativeToRect.y(), widgetLength, relativeToRect.height());
|
||||
break;
|
||||
case Location_OnBottom:
|
||||
result = QRect(relativeToRect.x(), qMin(relativeToRect.bottom() + 1 - side1Length + newAnchorThickness,
|
||||
height() - widgetLength - staticAnchorThickness),
|
||||
relativeToRect.width(), widgetLength);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
qCDebug(sizing) << "MultiSplitterLayout::rectForDrop rect=" << result
|
||||
<< "; result.bottomRight=" << result.bottomRight()
|
||||
<< "; location=" << location
|
||||
<< "; s1=" << side1Length
|
||||
<< "; relativeToRect.bottomRight=" << relativeToRect.bottomRight();
|
||||
return result;
|
||||
}
|
||||
|
||||
QRect MultiSplitterLayout::rectForDrop(const QWidgetOrQuick *widgetBeingDropped, Location location,
|
||||
const Item *relativeTo) const
|
||||
{
|
||||
Q_ASSERT(widgetBeingDropped);
|
||||
Length lfd = lengthForDrop(widgetBeingDropped, location, relativeTo);
|
||||
const bool needsMoreSpace = lfd.isNull();
|
||||
if (needsMoreSpace) {
|
||||
// This is the case with the drop indicators. If there's not enough space let's still
|
||||
// draw some indicator drop. The window will resize to accommodate the drop.
|
||||
lfd.side1Length = INDICATOR_MINIMUM_LENGTH / 2;
|
||||
lfd.side2Length = INDICATOR_MINIMUM_LENGTH - lfd.side1Length;
|
||||
}
|
||||
|
||||
const int staticAnchorThickness = Anchor::thickness(/**static=*/true);
|
||||
const bool relativeToThis = relativeTo == nullptr;
|
||||
const QRect relativeToRect = relativeToThis ? m_multiSplitter->rect().adjusted(staticAnchorThickness, staticAnchorThickness,
|
||||
-staticAnchorThickness, -staticAnchorThickness)
|
||||
: relativeTo->geometry();
|
||||
|
||||
// This function is split in two just so we can unit-test the math in the second one, which is more involved
|
||||
QRect result = rectForDrop(lfd, location, relativeToRect);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::setAnchorBeingDragged(Anchor *anchor)
|
||||
{
|
||||
m_anchorBeingDragged = anchor;
|
||||
}
|
||||
|
||||
Anchor::List MultiSplitterLayout::anchorsFollowing(Anchor *followee) const
|
||||
{
|
||||
if (!followee)
|
||||
return {};
|
||||
|
||||
Anchor::List followers;
|
||||
|
||||
for (Anchor *a : m_anchors) {
|
||||
if (a->followee() == followee)
|
||||
followers.push_back(a);
|
||||
}
|
||||
|
||||
return followers;
|
||||
}
|
||||
|
||||
int MultiSplitterLayout::numAchorsFollowing() const
|
||||
{
|
||||
int count = 0;
|
||||
for (Anchor *a : m_anchors) {
|
||||
if (a->isFollowing())
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int MultiSplitterLayout::numVisibleAnchors() const
|
||||
{
|
||||
int count = 0;
|
||||
@@ -819,193 +556,15 @@ int MultiSplitterLayout::numVisibleAnchors() const
|
||||
return count;
|
||||
}
|
||||
|
||||
Anchor *MultiSplitterLayout::staticAnchor(Anchor::Type type) const
|
||||
{
|
||||
if (type == Anchor::Type_TopStatic)
|
||||
return m_topAnchor;
|
||||
|
||||
if (type == Anchor::Type_BottomStatic)
|
||||
return m_bottomAnchor;
|
||||
|
||||
if (type == Anchor::Type_LeftStatic)
|
||||
return m_leftAnchor;
|
||||
|
||||
if (type == Anchor::Type_RightStatic)
|
||||
return m_rightAnchor;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::dumpDebug() const
|
||||
{
|
||||
Q_EMIT aboutToDumpDebug();
|
||||
qDebug() << Q_FUNC_INFO << "m_size=" << m_size
|
||||
<< "; minimumSize=" << minimumSize()
|
||||
<< "; parentWidget.size=" << multiSplitter()->size()
|
||||
<< "; window=" << multiSplitter()->window()
|
||||
<< "; window.size=" << multiSplitter()->window()->size();
|
||||
|
||||
qDebug() << "Items:";
|
||||
for (auto item : items()) {
|
||||
qDebug() <<" " << item
|
||||
<< "; min.width=" << item->minLength(Qt::Vertical)
|
||||
<< "; min.height=" << item->minLength(Qt::Horizontal)
|
||||
<< "; geometry=" << item->geometry()
|
||||
<< "; isPlaceholder=" << item->isPlaceholder()
|
||||
<< "; refCount=" << item->refCount();
|
||||
|
||||
if (Frame *frame = item->frame())
|
||||
frame->dumpDebug();
|
||||
}
|
||||
|
||||
qDebug() << "Anchors:";
|
||||
for (Anchor *anchor : m_anchors) {
|
||||
auto side1Widgets = anchor->items(Anchor::Side1);
|
||||
auto side2Widgets = anchor->items(Anchor::Side2);
|
||||
auto bounds = anchor->isStatic() ? QPair<int, int>() : boundPositionsForAnchor(anchor);
|
||||
qDebug() << "\n " << anchor
|
||||
<< "; side1=" << side1Widgets
|
||||
<< "; side2=" << side2Widgets
|
||||
<< "; pos=" << anchor->position()
|
||||
<< "; sepWidget.pos=" << (anchor->isVertical() ? anchor->separatorWidget()->x()
|
||||
: anchor->separatorWidget()->y())
|
||||
<< "; sepWidget.visible=" << anchor->separatorWidget()->isVisible()
|
||||
<< "; geo=" << anchor->geometry()
|
||||
<< "; sep.geo=" << anchor->separatorWidget()->geometry()
|
||||
<< "; bounds=" << bounds
|
||||
<< "; orientation=" << anchor->orientation()
|
||||
<< "; isFollowing=" << anchor->isFollowing()
|
||||
<< "; followee=" << anchor->followee()
|
||||
<< "; from=" << ((void*)anchor->from())
|
||||
<< "; to=" << ((void*)anchor->to())
|
||||
<< "; positionPercentage=" << anchor->positionPercentage();
|
||||
}
|
||||
|
||||
qDebug() << "Num Frame:" << Frame::dbg_numFrames();
|
||||
qDebug() << "Num FloatingWindow:" << FloatingWindow::dbg_numFrames();
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::positionStaticAnchors()
|
||||
{
|
||||
qCDebug(sizing) << Q_FUNC_INFO;
|
||||
m_leftAnchor->setPosition(0);
|
||||
m_topAnchor->setPosition(0);
|
||||
m_bottomAnchor->setPosition(height() - m_bottomAnchor->thickness());
|
||||
m_rightAnchor->setPosition(width() - m_rightAnchor->thickness());
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::redistributeSpace()
|
||||
{
|
||||
positionStaticAnchors();
|
||||
redistributeSpace_recursive(m_leftAnchor, 0);
|
||||
redistributeSpace_recursive(m_topAnchor, 0);
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::redistributeSpace(QSize oldSize, QSize newSize)
|
||||
{
|
||||
positionStaticAnchors();
|
||||
if (oldSize == newSize || !oldSize.isValid() || !newSize.isValid())
|
||||
return;
|
||||
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "old=" << oldSize << "; new=" << newSize;
|
||||
|
||||
const bool widthChanged = oldSize.width() != newSize.width();
|
||||
const bool heightChanged = oldSize.height() != newSize.height();
|
||||
|
||||
if (widthChanged)
|
||||
redistributeSpace_recursive(m_leftAnchor, 0);
|
||||
if (heightChanged)
|
||||
redistributeSpace_recursive(m_topAnchor, 0);
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::redistributeSpace_recursive(Anchor *fromAnchor, int minAnchorPos)
|
||||
{
|
||||
for (Item *item : fromAnchor->items(Anchor::Side2)) {
|
||||
Anchor *nextAnchor = item->anchorAtSide(Anchor::Side2, fromAnchor->orientation());
|
||||
if (nextAnchor->isStatic())
|
||||
continue;
|
||||
|
||||
// We use the minPos of the Anchor that had non-placeholder items on its side1.
|
||||
if (nextAnchor->hasNonPlaceholderItems(Anchor::Side1))
|
||||
minAnchorPos = nextAnchor->minPosition();
|
||||
|
||||
if (nextAnchor->hasNonPlaceholderItems(Anchor::Side2) && !nextAnchor->isFollowing()) {
|
||||
const int newPosition = int(nextAnchor->positionPercentage() * length(nextAnchor->orientation()));
|
||||
|
||||
// But don't let the anchor go out of bounds, it must respect its widgets min sizes
|
||||
auto bounds = boundPositionsForAnchor(nextAnchor);
|
||||
|
||||
// For the bounding, use Anchor::minPosition, as we're not making the anchors on the left/top shift, which boundsPositionsForAnchor() assumes.
|
||||
const int newPositionBounded = qMax(bounds.first, qBound(minAnchorPos, newPosition, bounds.second));
|
||||
|
||||
qCDebug(sizing) << Q_FUNC_INFO << nextAnchor << "bounds.first=" << bounds.first
|
||||
<< "; newPosition=" << newPosition
|
||||
<< "; bounds.first=" << bounds.first
|
||||
<< "; bounds.second=" << bounds.second
|
||||
<< "; newPositionBounded=" << newPositionBounded
|
||||
<< "; oldPosition=" << nextAnchor->position()
|
||||
<< "; size=" << m_size
|
||||
<< "; nextAnchor.minPosition=" << minAnchorPos;
|
||||
|
||||
nextAnchor->setPosition(newPositionBounded, Anchor::SetPositionOption_DontRecalculatePercentage);
|
||||
}
|
||||
|
||||
redistributeSpace_recursive(nextAnchor, minAnchorPos);
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::updateSizeConstraints()
|
||||
{
|
||||
const int minH = m_topAnchor->cumulativeMinLength(Anchor::Side2);
|
||||
const int minW = m_leftAnchor->cumulativeMinLength(Anchor::Side2);
|
||||
|
||||
const QSize newMinSize = QSize(minW, minH);
|
||||
const QSize newMinSize = m_rootItem->minSize();
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "Updating size constraints from" << m_minSize
|
||||
<< "to" << newMinSize;
|
||||
|
||||
setMinimumSize(newMinSize);
|
||||
}
|
||||
|
||||
int MultiSplitterLayout::wastedSpacing(Qt::Orientation orientation) const
|
||||
{
|
||||
// Wasted spacing due to using splitters:
|
||||
int numAnchors = 0;
|
||||
for (Anchor *anchor : m_anchors) {
|
||||
if (anchor->orientation() == orientation)
|
||||
numAnchors++;
|
||||
}
|
||||
|
||||
return (2 * Anchor::thickness(/*static=*/ true)) +
|
||||
((numAnchors - 2) * Anchor::thickness(/*static=*/ false)); // 2 of the anchors are always static
|
||||
}
|
||||
|
||||
AnchorGroup MultiSplitterLayout::staticAnchorGroup() const
|
||||
{
|
||||
return m_staticAnchorGroup;
|
||||
}
|
||||
|
||||
Anchor::List MultiSplitterLayout::anchors(Qt::Orientation orientation, bool includeStatic,
|
||||
bool includePlaceholders) const
|
||||
{
|
||||
Anchor::List result;
|
||||
for (Anchor *anchor : m_anchors) {
|
||||
if ((includeStatic || !anchor->isStatic()) && (includePlaceholders || !anchor->isFollowing()) && anchor->orientation() == orientation)
|
||||
result << anchor;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::blockItemPropagateGeo(bool block)
|
||||
{
|
||||
for (Item *item : m_items) {
|
||||
if (block)
|
||||
item->beginBlockPropagateGeo();
|
||||
else
|
||||
item->endBlockPropagateGeo();
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::emitVisibleWidgetCountChanged()
|
||||
{
|
||||
if (!m_inDestructor)
|
||||
@@ -1040,7 +599,7 @@ Frame::List MultiSplitterLayout::frames() const
|
||||
Frame::List result;
|
||||
|
||||
for (Item *item : m_items) {
|
||||
if (Frame *f = item->frame())
|
||||
if (auto f = static_cast<Frame*>(item->frame()))
|
||||
result.push_back(f);
|
||||
}
|
||||
|
||||
@@ -1063,22 +622,6 @@ bool MultiSplitterLayout::checkSanity() const
|
||||
return m_rootItem->checkSanity();
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::ensureHasAvailableSize(QSize needed)
|
||||
{
|
||||
const QSize availableSize = this->availableSize();
|
||||
|
||||
qCDebug(placeholder) << Q_FUNC_INFO << "; needed=" << needed << availableSize;
|
||||
|
||||
const int deltaWidth = needed.width() > availableSize.width() ? (needed.width() - availableSize.width())
|
||||
: 0;
|
||||
|
||||
const int deltaHeight = needed.height() > availableSize.height() ? (needed.height() - availableSize.height())
|
||||
: 0;
|
||||
|
||||
const QSize newSize = size() + QSize(deltaWidth, deltaHeight);
|
||||
setSize(newSize);
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::unrefOldPlaceholders(const Frame::List &framesBeingAdded) const
|
||||
{
|
||||
for (Frame *frame : framesBeingAdded) {
|
||||
@@ -1151,107 +694,6 @@ void MultiSplitterLayout::setMinimumSize(QSize sz)
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "minSize = " << m_minSize;
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::clearAnchorsFollowing()
|
||||
{
|
||||
for (Anchor *anchor : qAsConst(m_anchors))
|
||||
anchor->setFollowee(nullptr);
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::updateAnchorFollowing(const AnchorGroup &groupBeingRemoved)
|
||||
{
|
||||
clearAnchorsFollowing();
|
||||
|
||||
QHash<Anchor *, int> newPositionsWhenGroupRemoved;
|
||||
|
||||
for (Anchor *anchor : qAsConst(m_anchors)) {
|
||||
if (anchor->isStatic())
|
||||
continue;
|
||||
|
||||
if (anchor->onlyHasPlaceholderItems(Anchor::Side2)) {
|
||||
Anchor *toFollow = anchor->findNearestAnchorWithItems(Anchor::Side2);
|
||||
if (toFollow->followee() != anchor) {
|
||||
if (!toFollow->isStatic() && groupBeingRemoved.containsAnchor(anchor, Anchor::Side1)) {
|
||||
// A group is being removed, instead of simply shifting the left/top anchor all the way, let's make it use half the space
|
||||
if (toFollow->onlyHasPlaceholderItems(Anchor::Side1)) { // Means it can move!
|
||||
const int delta = toFollow->position() - anchor->position() - anchor->thickness();
|
||||
const int halfDelta = int(delta / 2.0);
|
||||
if (halfDelta > 0) {
|
||||
newPositionsWhenGroupRemoved.insert(toFollow, toFollow->position() - halfDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anchor->setFollowee(toFollow);
|
||||
}
|
||||
} else if (anchor->onlyHasPlaceholderItems(Anchor::Side1)) {
|
||||
Anchor *toFollow = anchor->findNearestAnchorWithItems(Anchor::Side1);
|
||||
if (toFollow->followee() != anchor) {
|
||||
|
||||
if (!toFollow->isStatic() && groupBeingRemoved.containsAnchor(anchor, Anchor::Side2)) {
|
||||
// A group is being removed, instead of simply shifting the right/bottom anchor all the way, let's make it use half the space
|
||||
if (toFollow->onlyHasPlaceholderItems(Anchor::Side2)) { // Means it can move!
|
||||
const int delta = anchor->position() - toFollow->position() - toFollow->thickness();
|
||||
const int halfDelta = int(delta / 2.0);
|
||||
if (halfDelta > 0) {
|
||||
newPositionsWhenGroupRemoved.insert(toFollow, toFollow->position() + halfDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anchor->setFollowee(toFollow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (auto it = newPositionsWhenGroupRemoved.begin(), end = newPositionsWhenGroupRemoved.end(); it != end; ++it) {
|
||||
Anchor *anchorToShift = it.key();
|
||||
const int newPosition = it.value();
|
||||
const Anchor::Side sideToShiftTo = newPosition < anchorToShift->position() ? Anchor::Side1
|
||||
: Anchor::Side2;
|
||||
bool doShift = true;
|
||||
for (Anchor *follower : anchorToShift->followers()) {
|
||||
if (follower->hasNonPlaceholderItems(sideToShiftTo) && !groupBeingRemoved.containsAnchor(follower, sideToShiftTo)) {
|
||||
doShift = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (doShift && !anchorToShift->isFollowing())
|
||||
anchorToShift->setPosition(newPosition);
|
||||
}
|
||||
|
||||
updateSizeConstraints();
|
||||
ensureAnchorsBounded();
|
||||
}
|
||||
|
||||
QHash<Anchor*, Anchor*> MultiSplitterLayout::anchorsShouldFollow() const
|
||||
{
|
||||
QHash<Anchor*, Anchor*> followers;
|
||||
|
||||
for (Anchor *anchor : m_anchors) {
|
||||
if (anchor->isStatic())
|
||||
continue;
|
||||
|
||||
if (anchor->onlyHasPlaceholderItems(Anchor::Side2)) {
|
||||
Anchor *toFollow = anchor->findNearestAnchorWithItems(Anchor::Side2);
|
||||
if (followers.value(toFollow) != anchor)
|
||||
followers.insert(anchor, toFollow);
|
||||
} else if (anchor->onlyHasPlaceholderItems(Anchor::Side1)) {
|
||||
Anchor *toFollow = anchor->findNearestAnchorWithItems(Anchor::Side1);
|
||||
if (followers.value(toFollow) != anchor)
|
||||
followers.insert(anchor, toFollow);
|
||||
}
|
||||
}
|
||||
|
||||
return followers;
|
||||
}
|
||||
|
||||
void MultiSplitterLayout::insertAnchor(Anchor *anchor)
|
||||
{
|
||||
m_anchors.append(anchor);
|
||||
}
|
||||
|
||||
const ItemList MultiSplitterLayout::items() const
|
||||
{
|
||||
return m_items;
|
||||
@@ -1314,10 +756,6 @@ bool MultiSplitterLayout::deserialize(const LayoutSaver::MultiSplitterLayout &ms
|
||||
}
|
||||
}
|
||||
|
||||
m_staticAnchorGroup.left = m_leftAnchor;
|
||||
m_staticAnchorGroup.top = m_topAnchor;
|
||||
m_staticAnchorGroup.right = m_rightAnchor;
|
||||
m_staticAnchorGroup.bottom = m_bottomAnchor;
|
||||
|
||||
m_items.clear(); // Now properly set the items, which installs needed event filters, etc.
|
||||
addItems_internal(items, false, false); // Add the items only after we have the static anchors set
|
||||
|
||||
Reference in New Issue
Block a user