Skip to content

Commit

Permalink
Introduce MainWindowOption_HasCentralWidget
Browse files Browse the repository at this point in the history
You can now set an arbitrary widget as "central widget".
It's similar to MainWindowOption_HasCentralFrame, however the widget
won't be detachable and won't show tabs.

Similar to what you'd get with QMainWindow central widget concept.

Example:
    QWidget *myWidget = new MyWidget();
    mainWindow->setPersistentCentralWidget(myWidget);

Fixes #225
  • Loading branch information
iamsergio committed Aug 30, 2021
1 parent 3fb8861 commit 1ccdf44
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 6 deletions.
1 change: 1 addition & 0 deletions Changelog
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- Install the Python bindings to "site-packages"
- The Python bindings for Qt6 use the "PyKDDockWidgetsQt6" namespace
- Co-installable with Qt6
- Adds support for non-detachable central widget, MainWindowOption_HasCentralWidget. (#225)

* v1.4.1 (unreleased)
-
Expand Down
4 changes: 4 additions & 0 deletions examples/dockwidgets/MyMainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowO

setAffinities({ affinityName });
createDockWidgets();

if (options & KDDockWidgets::MainWindowOption_HasCentralWidget) {
setPersistentCentralWidget(new MyWidget1());
}
}

MyMainWindow::~MyMainWindow()
Expand Down
7 changes: 7 additions & 0 deletions examples/dockwidgets/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ int main(int argc, char **argv)
QCoreApplication::translate("main", "If we're not using title bars we'll still show the close and float button in the tab bar"));
parser.addOption(showButtonsInTabBarIfTitleBarHidden);

QCommandLineOption centralWidget("central-widget",
QCoreApplication::translate("main", "The main window will have a non-detachable central widget"));
parser.addOption(centralWidget);

#if defined(DOCKS_DEVELOPER_MODE)
parser.addOption(centralFrame);

Expand Down Expand Up @@ -164,6 +168,9 @@ int main(int argc, char **argv)
options = parser.isSet(centralFrame) ? MainWindowOption_HasCentralFrame
: MainWindowOption_None;

if (parser.isSet(centralWidget))
options |= MainWindowOption_HasCentralWidget;

if (parser.isSet(noQtTool))
internalFlags |= KDDockWidgets::Config::InternalFlag_DontUseQtToolWindowsForFloatingWindows;

Expand Down
7 changes: 5 additions & 2 deletions src/KDDockWidgets.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ enum MainWindowOption
{
MainWindowOption_None = 0, ///> No option set
MainWindowOption_HasCentralFrame = 1, ///> Makes the MainWindow always have a central frame, for tabbing documents
MainWindowOption_MDI = 2 ///> The layout will be MDI. DockWidgets can have arbitrary positions, not restricted by any layout
MainWindowOption_MDI = 2, ///> The layout will be MDI. DockWidgets can have arbitrary positions, not restricted by any layout
MainWindowOption_HasCentralWidget = 4 | MainWindowOption_HasCentralFrame, ///> Similar to MainWindowOption_HasCentralFrame but
///> you'll have a central widget which can't be detached (Similar to regular QMainWindow).
};
Q_DECLARE_FLAGS(MainWindowOptions, MainWindowOption)
Q_ENUM_NS(MainWindowOptions)
Expand Down Expand Up @@ -258,7 +260,8 @@ enum FrameOption
FrameOption_None = 0,
FrameOption_AlwaysShowsTabs = 1,
FrameOption_IsCentralFrame = 2,
FrameOption_IsOverlayed = 4
FrameOption_IsOverlayed = 4,
FrameOption_NonDockable = 8 ///> You can't DND and tab things into this Frame
};
Q_DECLARE_FLAGS(FrameOptions, FrameOption)
Q_ENUM_NS(FrameOptions)
Expand Down
67 changes: 65 additions & 2 deletions src/MainWindowBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@
#include "private/LayoutSaver_p.h"
#include "private/DockWidgetBase_p.h"

// Or we can have a createDockWidget() in the factory
#ifdef KDDOCKWIDGETS_QTQUICK
# include "DockWidgetQuick.h"
#else
# include "DockWidget.h"
#endif

using namespace KDDockWidgets;

static LayoutWidget *createLayoutWidget(MainWindowBase *mainWindow, MainWindowOptions options)
Expand All @@ -44,10 +51,11 @@ static LayoutWidget *createLayoutWidget(MainWindowBase *mainWindow, MainWindowOp
class MainWindowBase::Private
{
public:
explicit Private(MainWindowBase *mainWindow, MainWindowOptions options)
explicit Private(MainWindowBase *mainWindow, const QString &uniqueName, MainWindowOptions options)
: m_options(options)
, q(mainWindow)
, m_layoutWidget(createLayoutWidget(mainWindow, options))
, m_persistentCentralDockWidget(createPersistentCentralDockWidget(uniqueName))
{
}

Expand All @@ -56,6 +64,37 @@ class MainWindowBase::Private
return m_options & MainWindowOption_HasCentralFrame;
}

bool supportsPersistentCentralWidget() const
{
if (!dropArea()) {
// This is the MDI case
return false;
}

return (m_options & MainWindowOption_HasCentralWidget) == MainWindowOption_HasCentralWidget;
}

DockWidgetBase* createPersistentCentralDockWidget(const QString &uniqueName) const
{
if (!supportsPersistentCentralWidget())
return nullptr;

auto dw = new DockWidgetType(QStringLiteral("%1-persistentCentralDockWidget").arg(uniqueName));
Frame *frame = dropArea()->m_centralFrame;
if (!frame) {
qWarning() << Q_FUNC_INFO << "Expected central frame";
return nullptr;
}

frame->addWidget(dw);
return dw;
}

DropAreaWithCentralFrame *dropArea() const
{
return qobject_cast<DropAreaWithCentralFrame *>(m_layoutWidget);
}

CursorPositions allowedResizeSides(SideBarLocation loc) const;

QRect rectForOverlay(Frame *, SideBarLocation) const;
Expand All @@ -69,12 +108,13 @@ class MainWindowBase::Private
MainWindowBase *const q;
QPointer<DockWidgetBase> m_overlayedDockWidget;
LayoutWidget *const m_layoutWidget;
DockWidgetBase *const m_persistentCentralDockWidget;
};

MainWindowBase::MainWindowBase(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
WidgetType *parent, Qt::WindowFlags flags)
: QMainWindowOrQuick(parent, flags)
, d(new Private(this, options))
, d(new Private(this, uniqueName, options))
{
setUniqueName(uniqueName);

Expand Down Expand Up @@ -718,3 +758,26 @@ QRect MainWindowBase::windowGeometry() const

return window()->geometry();
}

void MainWindowBase::setPersistentCentralWidget(QWidgetOrQuick *widget)
{
if (!d->supportsPersistentCentralWidget()) {
qWarning() << "MainWindow::setPersistentCentralWidget() requires MainWindowOption_HasCentralWidget";
return;
}

auto dw = d->m_persistentCentralDockWidget;
if (dw) {
dw->setWidget(widget);
} else {
qWarning() << Q_FUNC_INFO << "Unexpected null central dock widget";
}
}

QWidgetOrQuick *MainWindowBase::persistentCentralWidget() const
{
if (auto dw = d->m_persistentCentralDockWidget)
return dw->widget();

return nullptr;
}
15 changes: 15 additions & 0 deletions src/MainWindowBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ class DOCKS_EXPORT MainWindowBase : public QMainWindow
KDDockWidgets::DockWidgetBase *relativeTo = nullptr,
KDDockWidgets::InitialOption initialOption = {});

/**
* @brief Sets a persistent central widget. It can't be detached.
*
* Requires passing MainWindowOption_HasCentralWidget in the CTOR.
* This is similar to the central frame concept of MainWindowOption_HasCentralFrame,
* with the difference that it won't show a tabs.
*
* @param widget The QWidget (or QQuickItem if built with QtQuick support) that you
* want to set.
*
* Example: kddockwidgets_example --central-widget
*/
Q_INVOKABLE void setPersistentCentralWidget(QWidgetOrQuick *widget);
QWidgetOrQuick *persistentCentralWidget() const;

/**
* @brief Returns the unique name that was passed via constructor.
* Used internally by the save/restore mechanism.
Expand Down
11 changes: 10 additions & 1 deletion src/private/DropAreaWithCentralFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,16 @@ Frame *DropAreaWithCentralFrame::createCentralFrame(MainWindowOptions options)
{
Frame *frame = nullptr;
if (options & MainWindowOption_HasCentralFrame) {
frame = Config::self().frameworkWidgetFactory()->createFrame(nullptr, FrameOptions() | FrameOption_IsCentralFrame | FrameOption_AlwaysShowsTabs);
FrameOptions frameOptions = FrameOption_IsCentralFrame;
const bool hasPersistentCentralWidget = (options & MainWindowOption_HasCentralWidget) == MainWindowOption_HasCentralWidget;
if (hasPersistentCentralWidget) {
frameOptions |= FrameOption_NonDockable;
} else {
// With a persistent central widget we don't allow detaching it
frameOptions |= FrameOption_AlwaysShowsTabs;
}

frame = Config::self().frameworkWidgetFactory()->createFrame(nullptr, frameOptions);
frame->setObjectName(QStringLiteral("central frame"));
}

Expand Down
6 changes: 6 additions & 0 deletions src/private/Frame_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ class DOCKS_EXPORT Frame
return m_options & FrameOption_IsCentralFrame;
}

/// @brief Returns whether you can DND dock widgets over this frame and tab into it
bool isDockable() const
{
return !(m_options & FrameOption_NonDockable);
}

/**
* @brief whether the tab widget will always show tabs, even if there's only 1 dock widget
*
Expand Down
2 changes: 1 addition & 1 deletion src/private/indicators/ClassicIndicators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void ClassicIndicators::updateIndicatorsVisibility(bool visible)

// Only allow to dock to center if the affinities match
auto tabbingAllowedFunc = Config::self().tabbingAllowedFunc();
m_tabIndicatorVisible = m_innerIndicatorsVisible && windowBeingDragged && DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities());
m_tabIndicatorVisible = m_innerIndicatorsVisible && windowBeingDragged && DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities()) && m_hoveredFrame->isDockable();
if (m_tabIndicatorVisible && tabbingAllowedFunc) {
const DockWidgetBase::List source = windowBeingDragged->dockWidgets();
const DockWidgetBase::List target = m_hoveredFrame->dockWidgets();
Expand Down

0 comments on commit 1ccdf44

Please sign in to comment.