Item: Add DefaultSizeMode enum
To control how we calculate the item's initial size when we add it
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user