Fix propagation of resize when dragging a separator
It was ok but was resizing children via the "percentage method", and we only want to resize the children next to the separator.
This commit is contained in:
@@ -222,7 +222,7 @@ void Item::setHostWidget(QWidget *host)
|
||||
}
|
||||
}
|
||||
|
||||
void Item::setSize_recursive(QSize newSize)
|
||||
void Item::setSize_recursive(QSize newSize, ChildrenResizeStrategy)
|
||||
{
|
||||
setSize(newSize);
|
||||
}
|
||||
@@ -1659,14 +1659,32 @@ void ItemContainer::resizeChildren(QSize oldSize, QSize newSize, SizingInfo::Lis
|
||||
itemSize.geometry.setSize({ newItemLength, height() });
|
||||
}
|
||||
}
|
||||
} else if (strategy == ChildrenResizeStrategy::Side1 || strategy == ChildrenResizeStrategy::Side2) {
|
||||
} else if (strategy == ChildrenResizeStrategy::Side1SeparatorMove ||
|
||||
strategy == ChildrenResizeStrategy::Side2SeparatorMove) {
|
||||
int remaining = Layouting::length(newSize - oldSize, m_orientation); // This is how much we need to give to children (when growing the container), or to take from them when shrinking the container
|
||||
const bool isGrowing = remaining > 0;
|
||||
remaining = qAbs(remaining); // Easier to deal in positive numbers
|
||||
const bool isSide1 = strategy == ChildrenResizeStrategy::Side1;
|
||||
|
||||
// We're resizing the container, and need to decide if we start resizing the 1st children or
|
||||
//, in reverse order.
|
||||
// If the separator is being dragged left or top, then isSide1SeparatorMove is true.
|
||||
// If isSide1SeparatorMove is true and we're growing, then it means this container is on the right/bottom top of the separator,
|
||||
// so should resize its first children first. Same logic for the other 3 cases
|
||||
|
||||
const bool isSide1SeparatorMove = strategy == ChildrenResizeStrategy::Side1SeparatorMove;
|
||||
bool resizeHeadFirst;
|
||||
if (isGrowing && isSide1SeparatorMove) {
|
||||
resizeHeadFirst = true;
|
||||
} else if (isGrowing && !isSide1SeparatorMove) {
|
||||
resizeHeadFirst = false;
|
||||
} else if (!isGrowing && isSide1SeparatorMove) {
|
||||
resizeHeadFirst = false;
|
||||
} else if (!isGrowing && !isSide1SeparatorMove) {
|
||||
resizeHeadFirst = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
const int index = isSide1 ? i : count - 1 - i;
|
||||
const int index = resizeHeadFirst ? i : count - 1 - i;
|
||||
|
||||
SizingInfo &size = childSizes[index];
|
||||
|
||||
@@ -1687,7 +1705,7 @@ void ItemContainer::resizeChildren(QSize oldSize, QSize newSize, SizingInfo::Lis
|
||||
}
|
||||
}
|
||||
|
||||
void ItemContainer::setSize_recursive(QSize newSize)
|
||||
void ItemContainer::setSize_recursive(QSize newSize, ChildrenResizeStrategy strategy)
|
||||
{
|
||||
QScopedValueRollback<bool> block(m_blockUpdatePercentages, true);
|
||||
|
||||
@@ -1717,7 +1735,7 @@ void ItemContainer::setSize_recursive(QSize newSize)
|
||||
// so doing it in 2 steps will reuse much logic.
|
||||
|
||||
// the sizes:
|
||||
resizeChildren(oldSize, newSize, /*by-ref*/ childSizes, ChildrenResizeStrategy::Percentage);
|
||||
resizeChildren(oldSize, newSize, /*by-ref*/ childSizes, strategy);
|
||||
|
||||
// the positions:
|
||||
positionItems(/*by-ref*/ childSizes);
|
||||
@@ -1731,7 +1749,7 @@ void ItemContainer::setSize_recursive(QSize newSize)
|
||||
}
|
||||
|
||||
// #3 Sizes are now correct and honour min/max sizes. So apply them to our Items
|
||||
applyGeometries(childSizes);
|
||||
applyGeometries(childSizes, strategy);
|
||||
}
|
||||
|
||||
int ItemContainer::length() const
|
||||
@@ -1927,7 +1945,8 @@ void ItemContainer::requestSeparatorMove(Separator *separator, int delta)
|
||||
tookLocally = qMin(available1, remainingToTake);
|
||||
|
||||
if (tookLocally != 0) {
|
||||
growItem(side2Neighbour, tookLocally, GrowthStrategy::Side1Only);
|
||||
growItem(side2Neighbour, tookLocally, GrowthStrategy::Side1Only, false,
|
||||
ChildrenResizeStrategy::Side1SeparatorMove);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1936,7 +1955,8 @@ void ItemContainer::requestSeparatorMove(Separator *separator, int delta)
|
||||
const int available2 = availableOnSide(side1Neighbour, Side2);
|
||||
tookLocally = qMin(available2, remainingToTake);
|
||||
if (tookLocally != 0) {
|
||||
growItem(side1Neighbour, tookLocally, GrowthStrategy::Side2Only);
|
||||
growItem(side1Neighbour, tookLocally, GrowthStrategy::Side2Only, false,
|
||||
ChildrenResizeStrategy::Side2SeparatorMove);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2252,17 +2272,19 @@ void ItemContainer::growItem(int index, SizingInfo::List &sizes, int missing,
|
||||
shrinkNeighbours(index, sizes, side1Growth, side2Growth, neighbourSqueezeStrategy);
|
||||
}
|
||||
|
||||
void ItemContainer::growItem(Item *item, int amount, GrowthStrategy growthStrategy, bool accountForNewSeparator)
|
||||
void ItemContainer::growItem(Item *item, int amount, GrowthStrategy growthStrategy,
|
||||
bool accountForNewSeparator, ChildrenResizeStrategy childResizeStrategy)
|
||||
{
|
||||
const Item::List items = visibleChildren();
|
||||
const int index = items.indexOf(item);
|
||||
SizingInfo::List sizes = this->sizes();
|
||||
|
||||
growItem(index, /*by-ref=*/sizes, amount, growthStrategy, accountForNewSeparator);
|
||||
applyGeometries(sizes);
|
||||
|
||||
applyGeometries(sizes, childResizeStrategy);
|
||||
}
|
||||
|
||||
void ItemContainer::applyGeometries(const SizingInfo::List &sizes)
|
||||
void ItemContainer::applyGeometries(const SizingInfo::List &sizes, ChildrenResizeStrategy strategy)
|
||||
{
|
||||
const Item::List items = visibleChildren();
|
||||
const int count = items.size();
|
||||
@@ -2270,7 +2292,7 @@ void ItemContainer::applyGeometries(const SizingInfo::List &sizes)
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Item *item = items.at(i);
|
||||
item->setSize_recursive(sizes[i].geometry.size());
|
||||
item->setSize_recursive(sizes[i].geometry.size(), strategy);
|
||||
}
|
||||
|
||||
positionItems();
|
||||
@@ -2592,6 +2614,11 @@ QVector<Separator *> ItemContainer::separators_recursive() const
|
||||
return separators;
|
||||
}
|
||||
|
||||
QVector<Separator *> ItemContainer::separators() const
|
||||
{
|
||||
return m_separators;
|
||||
}
|
||||
|
||||
Separator *ItemContainer::neighbourSeparator(const Item *item, Side side, Qt::Orientation orientation) const
|
||||
{
|
||||
Item::List children = visibleChildren();
|
||||
|
||||
@@ -76,8 +76,8 @@ Q_DECLARE_FLAGS(SeparatorOptions, SeparatorOption)
|
||||
|
||||
enum class ChildrenResizeStrategy {
|
||||
Percentage, ///< Resizes the container in a way that all children will keep occupying the same percentage
|
||||
Side1, ///< When resizing a container, it takes/adds space from Side1 children first
|
||||
Side2, ///< When resizing a container, it takes/adds space from Side2 children first
|
||||
Side1SeparatorMove, ///< When resizing a container, it takes/adds space from Side1 children first
|
||||
Side2SeparatorMove ///< When resizing a container, it takes/adds space from Side2 children first
|
||||
};
|
||||
|
||||
enum class NeighbourSqueezeStrategy {
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
|
||||
virtual QSize minSize() const;
|
||||
virtual QSize maxSize() const;
|
||||
virtual void setSize_recursive(QSize newSize);
|
||||
virtual void setSize_recursive(QSize newSize, ChildrenResizeStrategy strategy = ChildrenResizeStrategy::Percentage);
|
||||
virtual bool isVisible(bool excludeBeingInserted = false) const;
|
||||
virtual void setGeometry_recursive(QRect rect);
|
||||
virtual void dumpLayout(int level = 0);
|
||||
@@ -444,7 +444,7 @@ public:
|
||||
void setOrientation(Qt::Orientation);
|
||||
QSize minSize() const override;
|
||||
QSize maxSize() const override;
|
||||
void setSize_recursive(QSize newSize) override;
|
||||
void setSize_recursive(QSize newSize, ChildrenResizeStrategy strategy = ChildrenResizeStrategy::Percentage) override;
|
||||
int length() const;
|
||||
QRect rect() const;
|
||||
QVariantList items() const;
|
||||
@@ -467,7 +467,7 @@ public:
|
||||
///@brief grows an item by @p amount. It calculates how much to grow on side1 and on side2
|
||||
///Then calls growItem(item, side1Growth, side2Growth) which will effectively grow it,
|
||||
///and shrink the neighbours which are donating the size.
|
||||
void growItem(Item *, int amount, GrowthStrategy, bool accountForNewSeparator = false);
|
||||
void growItem(Item *, int amount, GrowthStrategy, bool accountForNewSeparator = false, ChildrenResizeStrategy = ChildrenResizeStrategy::Percentage);
|
||||
void growItem(int index, SizingInfo::List &sizes, int missing, GrowthStrategy, bool accountForNewSeparator = false);
|
||||
|
||||
///@brief Shrinks the neighbours of the item at @p index
|
||||
@@ -508,7 +508,7 @@ public:
|
||||
void setIsVisible(bool) override;
|
||||
bool isVisible(bool excludeBeingInserted = false) const override;
|
||||
void setLength_recursive(int length, Qt::Orientation) override;
|
||||
void applyGeometries(const SizingInfo::List &sizes);
|
||||
void applyGeometries(const SizingInfo::List &sizes, ChildrenResizeStrategy = ChildrenResizeStrategy::Percentage);
|
||||
void applyPositions(const SizingInfo::List &sizes);
|
||||
Qt::Orientation orientation() const;
|
||||
bool isVertical() const;
|
||||
@@ -535,6 +535,7 @@ public:
|
||||
bool m_isResizing = false;
|
||||
bool m_blockUpdatePercentages = false;
|
||||
QVector<Layouting::Separator*> separators_recursive() const;
|
||||
QVector<Layouting::Separator*> separators() const;
|
||||
Qt::Orientation m_orientation = Qt::Vertical;
|
||||
private:
|
||||
void resizeChildren(QSize oldSize, QSize newSize, SizingInfo::List &sizes, ChildrenResizeStrategy);
|
||||
|
||||
@@ -199,6 +199,7 @@ private Q_SLOTS:
|
||||
void tst_availableOnSide();
|
||||
void tst_resizeViaSeparator();
|
||||
void tst_resizeViaSeparator2();
|
||||
void tst_resizeViaSeparator3();
|
||||
void tst_mapToRoot();
|
||||
};
|
||||
|
||||
@@ -1227,6 +1228,61 @@ void TestMultiSplitter::tst_resizeViaSeparator2()
|
||||
QCOMPARE(item4->width(), originalChildWidth);
|
||||
}
|
||||
|
||||
void TestMultiSplitter::tst_resizeViaSeparator3()
|
||||
{
|
||||
// Like tst_resizeViaSeparator2 but we have nesting, when a container is shrunk, it too
|
||||
// should only shrink its children that are near the separator, instead of all of them equally
|
||||
|
||||
// Layout: |1 | 3|
|
||||
// |4 | |
|
||||
// -------
|
||||
// 2
|
||||
|
||||
auto root = createRoot();
|
||||
auto item1 = createItem();
|
||||
auto item2 = createItem();
|
||||
auto item3 = createItem();
|
||||
auto item4 = createItem();
|
||||
|
||||
root->insertItem(item1, Location_OnTop);
|
||||
root->insertItem(item2, Location_OnBottom);
|
||||
item1->insertItem(item3, Location_OnRight);
|
||||
item1->insertItem(item4, Location_OnBottom);
|
||||
|
||||
// Make some room, so each item has enough space to shrink without hitting constriants
|
||||
root->setSize_recursive(QSize(1000, 4000));
|
||||
|
||||
// Our horizontal separator
|
||||
const auto separators = root->separators();
|
||||
const auto horizontalSeparator = separators[0];
|
||||
QCOMPARE(separators.size(), 1);
|
||||
|
||||
const int delta = 10;
|
||||
const int oldH1 = item1->height();
|
||||
const int oldH2 = item2->height();
|
||||
const int oldH3 = item3->height();
|
||||
const int oldH4 = item4->height();
|
||||
|
||||
// If the following ever fails, then make sure item4 has space before we move the separator
|
||||
QVERIFY(item4->availableLength(Qt::Vertical) > delta);
|
||||
|
||||
// Move separator up:
|
||||
root->requestSeparatorMove(horizontalSeparator, -delta);
|
||||
|
||||
QCOMPARE(item2->height(), oldH2 + delta);
|
||||
QCOMPARE(item3->height(), oldH3 - delta);
|
||||
QCOMPARE(item4->height(), oldH4 - delta);
|
||||
QCOMPARE(item1->height(), oldH1);
|
||||
|
||||
// Move down again
|
||||
root->requestSeparatorMove(horizontalSeparator, delta);
|
||||
|
||||
QCOMPARE(item2->height(), oldH2);
|
||||
QCOMPARE(item3->height(), oldH3);
|
||||
QCOMPARE(item4->height(), oldH4);
|
||||
QCOMPARE(item1->height(), oldH1);
|
||||
}
|
||||
|
||||
void TestMultiSplitter::tst_mapToRoot()
|
||||
{
|
||||
auto root = createRoot();
|
||||
|
||||
Reference in New Issue
Block a user