Item: Add DefaultSizeMode enum

To control how we calculate the item's initial size when
we add it
This commit is contained in:
Sergio Martins
2020-05-10 21:20:31 +01:00
parent 11576c5455
commit 0dac5eed68
7 changed files with 117 additions and 31 deletions

View File

@@ -66,6 +66,15 @@ namespace KDDockWidgets
};
Q_DECLARE_FLAGS(RestoreOptions, RestoreOption)
///@brief When a widget is added we need to figure out what's a decent size for it
///This enum specifies the different ways to calculate it
enum class DefaultSizeMode {
ItemSize, ///< Simply uses the Item::size() of the item being added. Actual used size might be smaller if our window isn't big enough.
Fair, ///< Gives an equal relative size as the items that are already in the layout
FairButFloor, ///< Equal to fair, but if the item is smaller than the fair suggestion, then that small size is used.
SizePolicy, ///< Uses the item's sizeHint() and sizePolicy()
};
///@internal
inline QString locationStr(Location loc)
{

View File

@@ -120,9 +120,9 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location, DockWidgetBa
}
if (option & AddingOption_StartHidden) {
m_layout->addWidget(dw, location, relativeToFrame, option);
m_layout->addWidget(dw, location, relativeToFrame, DefaultSizeMode::Fair, option);
} else {
m_layout->addWidget(frame, location, relativeToFrame, option);
m_layout->addWidget(frame, location, relativeToFrame, DefaultSizeMode::Fair, option);
}
}
@@ -240,7 +240,7 @@ bool DropArea::drop(QWidgetOrQuick *droppedWindow, KDDockWidgets::Location locat
auto frame = Config::self().frameworkWidgetFactory()->createFrame();
frame->addWidget(dock);
m_layout->addWidget(frame, location, relativeTo);
m_layout->addWidget(frame, location, relativeTo, DefaultSizeMode::FairButFloor);
} else if (auto floatingWindow = qobject_cast<FloatingWindow *>(droppedWindow)) {
if (!validateAffinity(floatingWindow))
return false;

View File

@@ -356,7 +356,7 @@ int Item::pos(Qt::Orientation o) const
return o == Qt::Vertical ? y() : x();
}
void Item::insertItem(Item *item, Location loc, AddingOption option)
void Item::insertItem(Item *item, Location loc, DefaultSizeMode defaultSizeMode, AddingOption option)
{
Q_ASSERT(item != this);
@@ -377,10 +377,10 @@ void Item::insertItem(Item *item, Location loc, AddingOption option)
m_parent->setOrientation(orientation);
}
m_parent->insertItem(item, indexInParent);
m_parent->insertItem(item, indexInParent, defaultSizeMode);
} else {
ItemContainer *container = m_parent->convertChildToContainer(this);
container->insertItem(item, loc, option);
container->insertItem(item, loc, defaultSizeMode, option);
}
(void) root()->checkSanity();
@@ -715,8 +715,21 @@ int Item::visibleCount_recursive() const
return isVisible() ? 1 : 0;
}
struct ItemContainer::Private
{
Private(ItemContainer *q)
: q(q)
{
}
int defaultLengthFor(Item *item, DefaultSizeMode) const;
ItemContainer *const q;
};
ItemContainer::ItemContainer(QWidget *hostWidget, ItemContainer *parent)
: Item(true, hostWidget, parent)
, d(new Private(this))
{
Q_ASSERT(parent);
connectParent(parent);
@@ -736,11 +749,17 @@ ItemContainer::ItemContainer(QWidget *hostWidget, ItemContainer *parent)
ItemContainer::ItemContainer(QWidget *hostWidget)
: Item(true, hostWidget, /*parentContainer=*/ nullptr)
, d(new Private(this))
{
// CTOR for root item
Q_ASSERT(hostWidget);
}
ItemContainer::~ItemContainer()
{
delete d;
}
bool ItemContainer::checkSanity()
{
m_checkSanityScheduled = false;
@@ -1027,17 +1046,18 @@ ItemContainer *ItemContainer::convertChildToContainer(Item *leaf)
container->setParentContainer(nullptr);
container->setParentContainer(this);
insertItem(container, index);
insertItem(container, index, DefaultSizeMode::None);
m_children.removeOne(leaf);
container->setGeometry(leaf->geometry());
container->insertItem(leaf, Location_OnTop);
container->insertItem(leaf, Location_OnTop, DefaultSizeMode::None);
Q_EMIT itemsChanged();
updateSeparators_recursive();
return container;
}
void ItemContainer::insertItem(Item *item, Location loc, AddingOption option)
void ItemContainer::insertItem(Item *item, Location loc, DefaultSizeMode defaultSizeMode,
AddingOption addingOption)
{
Q_ASSERT(item != this);
if (contains(item)) {
@@ -1045,8 +1065,8 @@ void ItemContainer::insertItem(Item *item, Location loc, AddingOption option)
return;
}
item->setIsVisible(!(option & AddingOption_StartHidden));
Q_ASSERT(!((option & AddingOption_StartHidden) && item->isContainer()));
item->setIsVisible(!(addingOption & AddingOption_StartHidden));
Q_ASSERT(!((addingOption & AddingOption_StartHidden) && item->isContainer()));
const Qt::Orientation locOrientation = orientationForLocation(loc);
@@ -1057,7 +1077,7 @@ void ItemContainer::insertItem(Item *item, Location loc, AddingOption option)
}
const int index = locationIsSide1(loc) ? 0 : m_children.size();
insertItem(item, index);
insertItem(item, index, defaultSizeMode);
} else {
// Inserting directly in a container ? Only if it's root.
Q_ASSERT(isRoot());
@@ -1066,10 +1086,10 @@ void ItemContainer::insertItem(Item *item, Location loc, AddingOption option)
container->setChildren(m_children, m_orientation);
m_children.clear();
setOrientation(oppositeOrientation(m_orientation));
insertItem(container, 0);
insertItem(container, 0, DefaultSizeMode::None);
// Now we have the correct orientation, we can insert
insertItem(item, loc, option);
insertItem(item, loc, defaultSizeMode, addingOption);
if (!container->hasVisibleChildren())
container->setGeometry(QRect());
@@ -1450,10 +1470,17 @@ void ItemContainer::setLength_recursive(int length, Qt::Orientation o)
setSize_recursive(sz);
}
void ItemContainer::insertItem(Item *item, int index)
void ItemContainer::insertItem(Item *item, int index, DefaultSizeMode defaultSizeMode)
{
if (defaultSizeMode != DefaultSizeMode::None) {
/// Choose a nice size for the item we're adding
const int suggestedLength = d->defaultLengthFor(item, defaultSizeMode);
item->setLength_recursive(suggestedLength, m_orientation);
}
m_children.insert(index, item);
item->setParentContainer(this);
Q_EMIT itemsChanged();
if (!m_convertingItemToContainer && item->isVisible())
@@ -1869,10 +1896,9 @@ void ItemContainer::restoreChild(Item *item)
const int available = availableOnSide(item, Side1) + availableOnSide(item, Side2) - Item::separatorThickness;
const QSize proposedSize = item->size();
const int max = available;
const int min = item->minLength(m_orientation);
const int proposed = Layouting::length(proposedSize, m_orientation);
const int proposed = Layouting::length(item->size(), m_orientation);
const int newLength = qBound(min, proposed, max);
Q_ASSERT(item->isVisible());
@@ -2684,3 +2710,32 @@ void SizingInfo::fromVariantMap(const QVariantMap &map)
minSize = mapToSize(map[QStringLiteral("minSize")].toMap());
maxSize = mapToSize(map[QStringLiteral("maxSize")].toMap());
}
int ItemContainer::Private::defaultLengthFor(Item *item, DefaultSizeMode mode) const
{
int result = 0;
switch (mode) {
case DefaultSizeMode::None:
break;
case DefaultSizeMode::Fair: {
const int numVisibleChildren = q->numVisibleChildren() + 1; // +1 so it counts with @p item too, which we're adding
const int usableLength = q->length() - (Item::separatorThickness*(numVisibleChildren - 1));
result = usableLength / numVisibleChildren;
break;
}
case DefaultSizeMode::FairButFloor: {
int length = defaultLengthFor(item, DefaultSizeMode::Fair);
result = qMin(length, item->length(q->m_orientation));
break;
}
case DefaultSizeMode::ItemSize:
result = item->length(q->m_orientation);
break;
case DefaultSizeMode::SizePolicy:
qWarning() << Q_FUNC_INFO << "Now implemented yet";
break;
}
result = qMax(item->minLength(q->m_orientation), result); // bound with max-size too
return result;
}

View File

@@ -86,6 +86,16 @@ enum class NeighbourSqueezeStrategy {
Side2NeighboursFirst ///< Same as Side1NeighboursFirst but does reverse order
};
///@brief When an item is added we need to figure out what's a decent size for it
///This enum specifies the different ways to calculate it
enum class DefaultSizeMode {
ItemSize, ///< Simply uses the Item::size() of the item being added. Actual used size might be smaller if our window isn't big enough.
Fair, ///< Gives an equal relative size as the items that are already in the layout
FairButFloor, ///< Equal to fair, but if the item is smaller than the fair suggestion, then that small size is used.
SizePolicy, ///< Uses the item's sizeHint() and sizePolicy()
None, ///< Don't do any sizing
};
inline Qt::Orientation oppositeOrientation(Qt::Orientation o) {
return o == Qt::Vertical ? Qt::Horizontal
: Qt::Vertical;
@@ -291,7 +301,9 @@ public:
bool isRoot() const;
virtual int visibleCount_recursive() const;
virtual void insertItem(Item *item, Location, AddingOption = AddingOption_None);
virtual void insertItem(Item *item, Location,
DefaultSizeMode defaultSizeMode = DefaultSizeMode::Fair,
AddingOption = AddingOption_None);
/**
* @brief No widget can have a minimum size smaller than this, regardless of their minimum size.
@@ -420,7 +432,8 @@ public:
explicit ItemContainer(QWidget *hostWidget, ItemContainer *parent);
explicit ItemContainer(QWidget *parent);
void insertItem(Item *item, int index);
~ItemContainer();
void insertItem(Item *item, int index, DefaultSizeMode);
[[nodiscard]] bool checkSanity() override;
bool hasOrientation() const;
int numChildren() const;
@@ -433,7 +446,8 @@ public:
void setGeometry_recursive(QRect rect) override;
ItemContainer *convertChildToContainer(Item *leaf);
void insertItem(Item *item, Location, AddingOption = AddingOption_None) override;
void insertItem(Item *item, Location, DefaultSizeMode defaultSizeMode = DefaultSizeMode::Fair,
AddingOption = AddingOption_None) override;
bool hasOrientationFor(Location) const;
Item::List visibleChildren(bool includeBeingInserted = false) const;
int usableLength() const;
@@ -551,6 +565,9 @@ private:
mutable bool m_checkSanityScheduled = false;
QVector<Layouting::Separator*> m_separators;
bool m_convertingItemToContainer = false;
struct Private;
Private *const d;
};
/**

View File

@@ -115,7 +115,9 @@ bool MultiSplitterLayout::validateInputs(QWidgetOrQuick *widget,
return true;
}
void MultiSplitterLayout::addWidget(QWidgetOrQuick *w, Location location, Frame *relativeToWidget, AddingOption option)
void MultiSplitterLayout::addWidget(QWidgetOrQuick *w, Location location,
Frame *relativeToWidget, DefaultSizeMode defaultSizeMode,
AddingOption option)
{
auto frame = qobject_cast<Frame*>(w);
qCDebug(addwidget) << Q_FUNC_INFO << w
@@ -164,7 +166,8 @@ void MultiSplitterLayout::addWidget(QWidgetOrQuick *w, Location location, Frame
}
Q_ASSERT(!newItem->geometry().isEmpty());
relativeTo->insertItem(newItem, Layouting::Location(location), Layouting::AddingOption(option));
relativeTo->insertItem(newItem, Layouting::Location(location),
Layouting::DefaultSizeMode(defaultSizeMode), Layouting::AddingOption(option));
if (dw && option && AddingOption_StartHidden)
delete frame;

View File

@@ -85,7 +85,7 @@ public:
* @brief Adds a widget to this MultiSplitter.
*/
void addWidget(QWidgetOrQuick *widget, KDDockWidgets::Location location,
Frame *relativeTo = nullptr, AddingOption option = {});
Frame *relativeTo = nullptr, DefaultSizeMode = DefaultSizeMode::Fair, AddingOption option = {});
/**
* Adds an entire MultiSplitter into this layout. The donor MultiSplitter will be deleted

View File

@@ -514,6 +514,7 @@ void TestMultiSplitter::tst_minSize()
item1->m_sizingInfo.minSize = {101, 150};
item2->m_sizingInfo.minSize = {200, 300};
item2->setSize(item2->m_sizingInfo.minSize);
item22->m_sizingInfo.minSize = {100, 100};
root->insertItem(item1, Location_OnLeft);
@@ -1023,7 +1024,7 @@ void TestMultiSplitter::tst_numSeparators()
root->insertItem(item5, Location_OnLeft);
QCOMPARE(root->separators_recursive().size(), 0);
root->insertItem(item6, Location_OnLeft, AddingOption_StartHidden);
root->insertItem(item6, Location_OnLeft, DefaultSizeMode::Fair, AddingOption_StartHidden);
QCOMPARE(root->separators_recursive().size(), 0);
QVERIFY(serializeDeserializeTest(root));
}
@@ -1095,7 +1096,7 @@ void TestMultiSplitter::tst_insertHiddenContainer()
auto root1 = createRoot();
auto root2 = createRoot();
Item *item2 = createItem();
root2->insertItem(item2, Location_OnLeft, AddingOption_StartHidden);
root2->insertItem(item2, Location_OnLeft, DefaultSizeMode::Fair, AddingOption_StartHidden);
QVERIFY(root1->checkSanity());
QVERIFY(root2->checkSanity());
@@ -1131,7 +1132,8 @@ void TestMultiSplitter::tst_availableOnSide()
Item *item3 = createItem(/*min=*/QSize(200, 200));
root->insertItem(item3, Location_OnRight);
QCOMPARE(root->availableOnSide(item3, Side1), (item1->width() - item1->minSize().width()) - (item2->width() - item2->minSize().width()));
QVERIFY(root->checkSanity());
QCOMPARE(root->availableOnSide(item3, Side1), (item1->width() - item1->minSize().width()) + (item2->width() - item2->minSize().width()));
QCOMPARE(root->availableOnSide(item3, Side2), 0);
auto separator2 = root->separators_recursive()[1];
@@ -1142,9 +1144,9 @@ void TestMultiSplitter::tst_availableOnSide()
item3->insertItem(item4, Location_OnBottom);
auto c = item3->parentContainer();
QCOMPARE(c->availableOnSide_recursive(item3, Side1, Qt::Horizontal), (item1->width() - item1->minSize().width()) - (item2->width() - item2->minSize().width()));
QCOMPARE(c->availableOnSide_recursive(item3, Side1, Qt::Horizontal), (item1->width() - item1->minSize().width()) + (item2->width() - item2->minSize().width()));
QCOMPARE(c->availableOnSide_recursive(item3, Side2, Qt::Horizontal), 0);
QCOMPARE(c->availableOnSide_recursive(item4, Side1, Qt::Horizontal), (item1->width() - item1->minSize().width()) - (item2->width() - item2->minSize().width()));
QCOMPARE(c->availableOnSide_recursive(item4, Side1, Qt::Horizontal), (item1->width() - item1->minSize().width()) + (item2->width() - item2->minSize().width()));
QCOMPARE(c->availableOnSide_recursive(item4, Side2, Qt::Horizontal), 0);
QCOMPARE(c->availableOnSide_recursive(item4, Side1, Qt::Vertical), (item3->height() - item3->minSize().height()));
@@ -1153,9 +1155,9 @@ void TestMultiSplitter::tst_availableOnSide()
Item *item31 = createItem(/*min=*/QSize(100, 100));
item3->insertItem(item31, Location_OnRight);
auto container31 = item31->parentContainer();
auto separato31 = container31->separators_recursive()[0];
QCOMPARE(container31->minPosForSeparator_global(separato31), item1->minSize().width() + item2->minSize().width() + item3->minSize().width() + 2*Item::separatorThickness);
QCOMPARE(container31->maxPosForSeparator_global(separato31), root->width() - item31->width() - Item::separatorThickness);
auto separator31 = container31->separators()[0];
QCOMPARE(container31->minPosForSeparator_global(separator31), item1->minSize().width() + item2->minSize().width() + item3->minSize().width() + 2*Item::separatorThickness);
QCOMPARE(container31->maxPosForSeparator_global(separator31), root->width() -item31->minSize().width() - Item::separatorThickness);
}
void TestMultiSplitter::tst_resizeViaSeparator()