diff --git a/src/private/LayoutWidget.cpp b/src/private/LayoutWidget.cpp index e998467a..7bfd3749 100644 --- a/src/private/LayoutWidget.cpp +++ b/src/private/LayoutWidget.cpp @@ -9,7 +9,13 @@ Contact KDAB at for commercial licensing options. */ +#include "Config.h" +#include "DockWidgetBase_p.h" +#include "FloatingWindow_p.h" +#include "FrameworkWidgetFactory.h" #include "LayoutWidget_p.h" +#include "MainWindowBase.h" +#include "Position_p.h" using namespace KDDockWidgets; @@ -22,3 +28,113 @@ LayoutWidget::LayoutWidget(QWidgetOrQuick *parent) LayoutWidget::~LayoutWidget() { } + +bool LayoutWidget::isInMainWindow() const +{ + return mainWindow() != nullptr; +} + +MainWindowBase *LayoutWidget::mainWindow() const +{ + if (auto pw = QWidgetAdapter::parentWidget()) { + // Note that if pw is a FloatingWindow then pw->parentWidget() can be a MainWindow too, as + // it's parented + if (pw->objectName() == QLatin1String("MyCentralWidget")) + return qobject_cast(pw->parentWidget()); + + if (auto mw = qobject_cast(pw)) + return mw; + } + + return nullptr; +} + +FloatingWindow *LayoutWidget::floatingWindow() const +{ + return qobject_cast(QWidgetAdapter::parentWidget()); +} + +void LayoutWidget::setRootItem(Layouting::ItemContainer *root) +{ + delete m_rootItem; + m_rootItem = root; + connect(m_rootItem, &Layouting::ItemContainer::numVisibleItemsChanged, this, + &MultiSplitter::visibleWidgetCountChanged); + connect(m_rootItem, &Layouting::ItemContainer::minSizeChanged, this, + [this] { setMinimumSize(layoutMinimumSize()); }); +} + +QSize LayoutWidget::layoutMinimumSize() const +{ + return m_rootItem->minSize(); +} + +QSize LayoutWidget::layoutMaximumSizeHint() const +{ + return m_rootItem->maxSizeHint(); +} + +void LayoutWidget::setLayoutMinimumSize(QSize sz) +{ + if (sz != m_rootItem->minSize()) { + setLayoutSize(size().expandedTo(m_rootItem->minSize())); // Increase size in case we need to + m_rootItem->setMinSize(sz); + } +} + +QSize LayoutWidget::size() const +{ + return m_rootItem->size(); +} + +void LayoutWidget::clearLayout() +{ + m_rootItem->clear(); +} + +bool LayoutWidget::checkSanity() const +{ + return m_rootItem->checkSanity(); +} + +void LayoutWidget::dumpLayout() const +{ + m_rootItem->dumpLayout(); +} + +void LayoutWidget::restorePlaceholder(DockWidgetBase *dw, Layouting::Item *item, int tabIndex) +{ + if (item->isPlaceholder()) { + Frame *newFrame = Config::self().frameworkWidgetFactory()->createFrame(this); + item->restore(newFrame); + } + + auto frame = qobject_cast(item->guestAsQObject()); + Q_ASSERT(frame); + + if (tabIndex != -1 && frame->dockWidgetCount() >= tabIndex) { + frame->insertWidget(dw, tabIndex); + } else { + frame->addWidget(dw); + } + + frame->QWidgetAdapter::setVisible(true); +} + +void LayoutWidget::unrefOldPlaceholders(const Frame::List &framesBeingAdded) const +{ + for (Frame *frame : framesBeingAdded) { + for (DockWidgetBase *dw : frame->dockWidgets()) { + dw->d->lastPositions().removePlaceholders(this); + } + } +} + +void LayoutWidget::setLayoutSize(QSize size) +{ + if (size != this->size()) { + m_rootItem->setSize_recursive(size); + if (!m_inResizeEvent && !LayoutSaver::restoreInProgress()) + resize(size); + } +} diff --git a/src/private/LayoutWidget_p.h b/src/private/LayoutWidget_p.h index 0e505f46..0f94b0d6 100644 --- a/src/private/LayoutWidget_p.h +++ b/src/private/LayoutWidget_p.h @@ -28,8 +28,21 @@ #include "kddockwidgets/KDDockWidgets.h" #include "kddockwidgets/QWidgetAdapter.h" +#include + +namespace Layouting { +class Item; +class Separator; +class Widget_qwidget; +} + namespace KDDockWidgets { +class MainWindowBase; +class FloatingWindow; +class Frame; +class DockWidgetBase; + /** * @brief The widget (QWidget or QQuickItem) which holds a layout of dock widgets. * @@ -47,6 +60,92 @@ class DOCKS_EXPORT LayoutWidget : public LayoutGuestWidget public: explicit LayoutWidget(QWidgetOrQuick *parent = nullptr); ~LayoutWidget() override; + + bool isInMainWindow() const; + MainWindowBase *mainWindow() const; + FloatingWindow *floatingWindow() const; + + /** + * @brief returns the layout's minimum size + * @ref setLayoutMinimumSize + */ + QSize layoutMinimumSize() const; + + /** + * @brief returns the layout's maximum size hint + */ + QSize layoutMaximumSizeHint() const; + + /** + * @brief returns the contents width. + * Usually it's the same width as the respective parent MultiSplitter. + */ + int width() const + { + return size().width(); + } + + /** + * @brief returns the contents height. + * Usually it's the same height as the respective parent MultiSplitter. + */ + int height() const + { + return size().height(); + } + + /** + * @brief getter for the size + */ + QSize size() const; + + /// @brief Runs some sanity checks. Returns true if everything is OK + bool checkSanity() const; + + /// @brief clears the layout + void clearLayout(); + + /// @brief dumps the layout to stderr + void dumpLayout() const; + + /** + * @brief setter for the contents size + * The "contents size" is just the size() of this layout. However, since resizing + * QWidgets is async and we need it to be sync. As sometimes adding widgets will increase + * the MultiSplitter size (due to widget's min-size constraints). + */ + void setLayoutSize(QSize); + + + /// @brief restores the dockwidget @p dw to its previous position + void restorePlaceholder(DockWidgetBase *dw, Layouting::Item *, int tabIndex); + +protected: + bool m_inResizeEvent = false; + + void setRootItem(Layouting::ItemContainer *root); + /** + * @brief setter for the minimum size + * @ref minimumSize + */ + void setLayoutMinimumSize(QSize); + + /** + * @brief Removes unneeded placeholder items when adding new frames. + * + * A floating frame A might have a placeholder in the main window (for example to remember its + * position on the Left), but then the user might attach it to the right, so the left + * placeholder is no longer need. Right before adding the frame to the right we remove the left + * placeholder, otherwise it's unrefed while we're adding causing a segfault. So what this does + * is making the unrefing happen a bit earlier. + */ + void unrefOldPlaceholders(const QList &framesBeingAdded) const; + +Q_SIGNALS: + void visibleWidgetCountChanged(int count); + +private: + Layouting::ItemContainer *m_rootItem = nullptr; }; } diff --git a/src/private/MultiSplitter.cpp b/src/private/MultiSplitter.cpp index 9886f2cb..e365e6cc 100644 --- a/src/private/MultiSplitter.cpp +++ b/src/private/MultiSplitter.cpp @@ -78,30 +78,6 @@ bool MultiSplitter::onResize(QSize newSize) return false; // So QWidget::resizeEvent is called } -bool MultiSplitter::isInMainWindow() const -{ - return mainWindow() != nullptr; -} - -MainWindowBase *MultiSplitter::mainWindow() const -{ - if (auto pw = QWidgetAdapter::parentWidget()) { - // Note that if pw is a FloatingWindow then pw->parentWidget() can be a MainWindow too, as it's parented - if (pw->objectName() == QLatin1String("MyCentralWidget")) - return qobject_cast(pw->parentWidget()); - - if (auto mw = qobject_cast(pw)) - return mw; - } - - return nullptr; -} - -FloatingWindow *MultiSplitter::floatingWindow() const -{ - return qobject_cast(QWidgetAdapter::parentWidget()); -} - bool MultiSplitter::validateInputs(QWidgetOrQuick *widget, Location location, const Frame *relativeToFrame, InitialOption option) const @@ -334,25 +310,6 @@ Frame::List MultiSplitter::frames() const return result; } -void MultiSplitter::restorePlaceholder(DockWidgetBase *dw, Layouting::Item *item, int tabIndex) -{ - if (item->isPlaceholder()) { - Frame *newFrame = Config::self().frameworkWidgetFactory()->createFrame(this); - item->restore(newFrame); - } - - auto frame = qobject_cast(item->guestAsQObject()); - Q_ASSERT(frame); - - if (tabIndex != -1 && frame->dockWidgetCount() >= tabIndex) { - frame->insertWidget(dw, tabIndex); - } else { - frame->addWidget(dw); - } - - frame->QWidgetAdapter::setVisible(true); -} - void MultiSplitter::layoutEqually() { layoutEqually(m_rootItem); @@ -367,70 +324,13 @@ void MultiSplitter::layoutEqually(Layouting::ItemBoxContainer *container) } } -void MultiSplitter::clearLayout() -{ - m_rootItem->clear(); -} - -bool MultiSplitter::checkSanity() const -{ - return m_rootItem->checkSanity(); -} - -void MultiSplitter::unrefOldPlaceholders(const Frame::List &framesBeingAdded) const -{ - for (Frame *frame : framesBeingAdded) { - for (DockWidgetBase *dw : frame->dockWidgets()) { - dw->d->lastPositions().removePlaceholders(this); - } - } -} - -void MultiSplitter::dumpLayout() const -{ - m_rootItem->dumpLayout(); -} - -void MultiSplitter::setLayoutSize(QSize size) -{ - if (size != this->size()) { - m_rootItem->setSize_recursive(size); - if (!m_inResizeEvent && !LayoutSaver::restoreInProgress()) - resize(size); - } -} - -QSize MultiSplitter::layoutMinimumSize() const -{ - return m_rootItem->minSize(); -} - -QSize MultiSplitter::layoutMaximumSizeHint() const -{ - return m_rootItem->maxSizeHint(); -} - -QSize MultiSplitter::size() const { return m_rootItem->size(); } - -void MultiSplitter::setLayoutMinimumSize(QSize sz) -{ - if (sz != m_rootItem->minSize()) { - setLayoutSize(size().expandedTo(m_rootItem->minSize())); // Increase size in case we need to - m_rootItem->setMinSize(sz); - } - - qCDebug(sizing) << Q_FUNC_INFO << "minSize = " << m_rootItem->minSize(); -} - void MultiSplitter::setRootItem(Layouting::ItemBoxContainer *root) { - delete m_rootItem; + LayoutWidget::setRootItem(root); + m_rootItem = root; - connect(m_rootItem, &Layouting::ItemBoxContainer::numVisibleItemsChanged, - this, &MultiSplitter::visibleWidgetCountChanged); - connect(m_rootItem, &Layouting::ItemBoxContainer::minSizeChanged, this, [this] { - setMinimumSize(layoutMinimumSize()); - }); + connect(m_rootItem, &Layouting::ItemContainer::minSizeChanged, this, + [this] { setMinimumSize(layoutMinimumSize()); }); } const Layouting::Item::List MultiSplitter::items() const diff --git a/src/private/MultiSplitter_p.h b/src/private/MultiSplitter_p.h index 6013e5f4..33439acc 100644 --- a/src/private/MultiSplitter_p.h +++ b/src/private/MultiSplitter_p.h @@ -28,19 +28,10 @@ #include "kddockwidgets/QWidgetAdapter.h" #include "kddockwidgets/docks_export.h" -namespace Layouting { -class Item; -class Separator; -class Widget_qwidget; -} - class TestDocks; namespace KDDockWidgets { -class MainWindowBase; -class FloatingWindow; -class Frame; struct WindowBeingDragged; /** @@ -60,9 +51,6 @@ class DOCKS_EXPORT MultiSplitter : public LayoutWidget public: explicit MultiSplitter(QWidgetOrQuick *parent = nullptr); ~MultiSplitter() override; - bool isInMainWindow() const; - MainWindowBase* mainWindow() const; - FloatingWindow* floatingWindow() const; /** * @brief Adds a widget to this MultiSplitter. @@ -120,7 +108,7 @@ public: /** * @brief The list of items in this layout. */ - const QVector items() const; + const QVector items() const; /** @@ -143,48 +131,6 @@ public: */ void updateSizeConstraints(); - /** - * @brief setter for the contents size - * The "contents size" is just the size() of this layout. However, since resizing - * QWidgets is async and we need it to be sync. As sometimes adding widgets will increase - * the MultiSplitter size (due to widget's min-size constraints). - */ - void setLayoutSize(QSize); - - /** - * @brief returns the contents width. - * Usually it's the same width as the respective parent MultiSplitter. - */ - int width() const { return size().width(); } - - /** - * @brief returns the contents height. - * Usually it's the same height as the respective parent MultiSplitter. - */ - int height() const { return size().height(); } - - /** - * @brief returns the layout's minimum size - * @ref setLayoutMinimumSize - */ - QSize layoutMinimumSize() const; - - /** - * @brief returns the layout's maximum size hint - */ - QSize layoutMaximumSizeHint() const; - - /** - * @brief getter for the size - */ - QSize size() const; - - /// @brief Runs some sanity checks. Returns true if everything is OK - bool checkSanity() const; - - /// @brief dumps the layout to stderr - void dumpLayout() const; - /** * @brief returns the Item that holds @p frame in this layout */ @@ -198,27 +144,16 @@ public: /// @brief Returns the list of dock widgets contained in this layout QVector dockWidgets() const; - /// @brief restores the dockwidget @p dw to its previous position - void restorePlaceholder(DockWidgetBase *dw, Layouting::Item *, int tabIndex); - /// @brief See docs for MainWindowBase::layoutEqually() void layoutEqually(); /// @brief overload that just resizes widgets within a sub-tree void layoutEqually(Layouting::ItemBoxContainer *); - /// @brief clears the layout - void clearLayout(); - -Q_SIGNALS: - void visibleWidgetCountChanged(int count); - protected: void onLayoutRequest() override; bool onResize(QSize newSize) override; private: - bool m_inResizeEvent = false; - friend class ::TestDocks; /** @@ -234,21 +169,6 @@ private: bool validateInputs(QWidgetOrQuick *widget, KDDockWidgets::Location location, const Frame *relativeToFrame, InitialOption option) const; - /** - * @brief Removes unneeded placeholder items when adding new frames. - * - * A floating frame A might have a placeholder in the main window (for example to remember its position on the Left), - * but then the user might attach it to the right, so the left placeholder is no longer need. - * Right before adding the frame to the right we remove the left placeholder, otherwise it's unrefed while we're adding - * causing a segfault. So what this does is making the unrefing happen a bit earlier. - */ - void unrefOldPlaceholders(const QList &framesBeingAdded) const; - - /** - * @brief setter for the minimum size - * @ref minimumSize - */ - void setLayoutMinimumSize(QSize); void setRootItem(Layouting::ItemBoxContainer *); diff --git a/src/private/multisplitter/Item_p.h b/src/private/multisplitter/Item_p.h index 0b2065c1..2c1b786e 100644 --- a/src/private/multisplitter/Item_p.h +++ b/src/private/multisplitter/Item_p.h @@ -294,6 +294,8 @@ public: QVector pathFromRoot() const; + Q_REQUIRED_RESULT virtual bool checkSanity(); + virtual QSize minSize() const; virtual QSize maxSizeHint() const; virtual void setSize_recursive(QSize newSize, ChildrenResizeStrategy strategy = ChildrenResizeStrategy::Percentage); @@ -321,7 +323,6 @@ protected: explicit Item(bool isContainer, Widget *hostWidget, ItemContainer *parent); void setParentContainer(ItemContainer *parent); void connectParent(ItemContainer *parent); - Q_REQUIRED_RESULT virtual bool checkSanity(); void setPos(QPoint); void setPos(int pos, Qt::Orientation); const ItemContainer *asContainer() const; @@ -384,10 +385,18 @@ public: bool contains_recursive(const Item *item) const; int visibleCount_recursive() const override; int count_recursive() const; + virtual void clear() = 0; + protected: bool hasSingleVisibleItem() const; Item::List m_children; + +Q_SIGNALS: + void itemsChanged(); + void numVisibleItemsChanged(int); + void numItemsChanged(); + private: struct Private; Private *const d; @@ -427,7 +436,7 @@ public: QRect suggestedDropRect(const Item *item, const Item *relativeTo, KDDockWidgets::Location) const; QVariantMap toVariantMap() const override; void fillFromVariantMap(const QVariantMap &map, const QHash &widgets) override; - void clear(); + void clear() override; Qt::Orientation orientation() const; bool isVertical() const; bool isHorizontal() const; @@ -516,10 +525,6 @@ private: bool test_suggestedRect(); #endif -Q_SIGNALS: - void itemsChanged(); - void numVisibleItemsChanged(int); - void numItemsChanged(); public: QVector separators_recursive() const; QVector separators() const;