Add DockWidget::Option_NonDockable
A dock widget with this option will always be floating and not be able to dock into anything. Other widgets can't dock into it either.
This commit is contained in:
@@ -49,10 +49,11 @@ static MyWidget *newMyWidget()
|
||||
}
|
||||
|
||||
MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
bool dockWidget0IsNonClosable, bool restoreIsRelative,
|
||||
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
|
||||
const QString &affinityName, QWidget *parent)
|
||||
: MainWindow(uniqueName, options, parent)
|
||||
, m_dockWidget0IsNonClosable(dockWidget0IsNonClosable)
|
||||
, m_dockWidget9IsNonDockable(nonDockableDockWidget9)
|
||||
, m_restoreIsRelative(restoreIsRelative)
|
||||
{
|
||||
// qApp->installEventFilter(this);
|
||||
@@ -112,8 +113,11 @@ void MyMainWindow::createDockWidgets()
|
||||
{
|
||||
Q_ASSERT(m_dockwidgets.isEmpty());
|
||||
|
||||
const int numDockWidgets = m_dockWidget9IsNonDockable ? 10 : 9;
|
||||
|
||||
|
||||
// Create 9 KDDockWidget::DockWidget and the respective widgets they're hosting (MyWidget instances)
|
||||
for (int i = 0; i < 9; i++)
|
||||
for (int i = 0; i < numDockWidgets; i++)
|
||||
m_dockwidgets << newDockWidget();
|
||||
|
||||
|
||||
@@ -150,6 +154,9 @@ KDDockWidgets::DockWidgetBase *MyMainWindow::newDockWidget()
|
||||
if (count == 0 && m_dockWidget0IsNonClosable)
|
||||
options |= KDDockWidgets::DockWidget::Option_NotClosable;
|
||||
|
||||
if (count == 9 && m_dockWidget9IsNonDockable)
|
||||
options |= KDDockWidgets::DockWidget::Option_NotDockable;
|
||||
|
||||
auto dock = new KDDockWidgets::DockWidget(QStringLiteral("DockWidget #%1").arg(count), options);
|
||||
dock->setAffinityName(affinityName()); // optional, just to show the feature. Pass -mi to the example to see incompatible dock widgets
|
||||
|
||||
@@ -157,7 +164,14 @@ KDDockWidgets::DockWidgetBase *MyMainWindow::newDockWidget()
|
||||
dock->setIcon(QIcon::fromTheme(QStringLiteral("mail-message")));
|
||||
auto myWidget = newMyWidget();
|
||||
dock->setWidget(myWidget);
|
||||
dock->setTitle(QStringLiteral("DockWidget #%1").arg(count));
|
||||
|
||||
|
||||
if (dock->options() & KDDockWidgets::DockWidget::Option_NotDockable) {
|
||||
dock->setTitle(QStringLiteral("DockWidget #%1 (%2)").arg(count).arg("non dockable"));
|
||||
} else {
|
||||
dock->setTitle(QStringLiteral("DockWidget #%1").arg(count));
|
||||
}
|
||||
|
||||
dock->resize(600, 600);
|
||||
dock->show();
|
||||
m_toggleMenu->addAction(dock->toggleAction());
|
||||
|
||||
@@ -28,7 +28,7 @@ class MyMainWindow : public KDDockWidgets::MainWindow
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
bool dockWidget0IsNonClosable, bool restoreIsRelative,
|
||||
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
|
||||
const QString &affinityName = {}, // Usually not needed. Just here to show the feature.
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
@@ -37,6 +37,7 @@ private:
|
||||
KDDockWidgets::DockWidgetBase* newDockWidget();
|
||||
QMenu *m_toggleMenu = nullptr;
|
||||
const bool m_dockWidget0IsNonClosable;
|
||||
const bool m_dockWidget9IsNonDockable;
|
||||
const bool m_restoreIsRelative;
|
||||
KDDockWidgets::DockWidget::List m_dockwidgets;
|
||||
};
|
||||
|
||||
@@ -76,6 +76,9 @@ int main(int argc, char **argv)
|
||||
QCommandLineOption doubleClickMaximize("x", QCoreApplication::translate("main", "Double clicking a title bar will maximize a floating window"));
|
||||
parser.addOption(doubleClickMaximize);
|
||||
|
||||
QCommandLineOption nonDockable("d", QCoreApplication::translate("main", "DockWidget #9 will be non-dockable"));
|
||||
parser.addOption(nonDockable);
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
QCommandLineOption noCentralFrame("c", QCoreApplication::translate("main", "No central frame"));
|
||||
parser.addOption(noCentralFrame);
|
||||
@@ -122,8 +125,9 @@ int main(int argc, char **argv)
|
||||
|
||||
const bool nonClosableDockWidget0 = parser.isSet(nonClosableDockWidget);
|
||||
const bool restoreIsRelative = parser.isSet(relativeRestore);
|
||||
const bool nonDockableDockWidget9 = parser.isSet(nonDockable);
|
||||
|
||||
MyMainWindow mainWindow(QStringLiteral("MyMainWindow"), options, nonClosableDockWidget0, restoreIsRelative);
|
||||
MyMainWindow mainWindow(QStringLiteral("MyMainWindow"), options, nonClosableDockWidget0, nonDockableDockWidget9, restoreIsRelative);
|
||||
mainWindow.setWindowTitle("Main Window 1");
|
||||
mainWindow.resize(1200, 1200);
|
||||
mainWindow.show();
|
||||
@@ -135,7 +139,7 @@ int main(int argc, char **argv)
|
||||
: QString();
|
||||
|
||||
auto mainWindow2 = new MyMainWindow(QStringLiteral("MyMainWindow-2"), options,
|
||||
nonClosableDockWidget0, restoreIsRelative, affinity);
|
||||
nonClosableDockWidget0, nonDockableDockWidget9, restoreIsRelative, affinity);
|
||||
if (affinity.isEmpty())
|
||||
mainWindow2->setWindowTitle("Main Window 2");
|
||||
else
|
||||
|
||||
@@ -150,6 +150,12 @@ void DockWidgetBase::addDockWidgetAsTab(DockWidgetBase *other, AddingOption addi
|
||||
return;
|
||||
}
|
||||
|
||||
if ((other->options() & DockWidgetBase::Option_NotDockable) ||
|
||||
(options() & DockWidgetBase::Option_NotDockable)) {
|
||||
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << other;
|
||||
return;
|
||||
}
|
||||
|
||||
Frame *frame = this->frame();
|
||||
|
||||
if (frame) {
|
||||
@@ -184,6 +190,12 @@ void DockWidgetBase::addDockWidgetToContainingWindow(DockWidgetBase *other, Loca
|
||||
return;
|
||||
}
|
||||
|
||||
if ((other->options() & DockWidgetBase::Option_NotDockable) ||
|
||||
(options() & DockWidgetBase::Option_NotDockable)) {
|
||||
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << other;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isWindow())
|
||||
morphIntoFloatingWindow();
|
||||
|
||||
@@ -283,6 +295,11 @@ DockWidgetBase::Options DockWidgetBase::options() const
|
||||
|
||||
void DockWidgetBase::setOptions(Options options)
|
||||
{
|
||||
if ((d->options & Option_NotDockable) != (options & Option_NotDockable)) {
|
||||
qWarning() << Q_FUNC_INFO << "Option_NotDockable not allowed to change. Pass via ctor only.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (options != d->options) {
|
||||
d->options = options;
|
||||
Q_EMIT optionsChanged(options);
|
||||
|
||||
@@ -69,7 +69,8 @@ public:
|
||||
///@brief DockWidget options to pass at construction time
|
||||
enum Option {
|
||||
Option_None = 0, ///< No option, the default
|
||||
Option_NotClosable = 1 /// The DockWidget can't be closed on the [x], only programatically
|
||||
Option_NotClosable = 1, /// The DockWidget can't be closed on the [x], only programatically
|
||||
Option_NotDockable = 2 ///< The DockWidget can't be docked, it's always floating
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
|
||||
@@ -180,7 +181,10 @@ public:
|
||||
Options options() const;
|
||||
|
||||
/**
|
||||
* @brief Setter for the options
|
||||
* @brief Setter for the options.
|
||||
* Only Option_NotClosable is allowed to change after construction. For the other options use
|
||||
* the constructor only.
|
||||
*
|
||||
* @sa options(), optionsChanged()
|
||||
*/
|
||||
void setOptions(Options);
|
||||
|
||||
@@ -81,6 +81,11 @@ void MainWindowBase::addDockWidgetAsTab(DockWidgetBase *widget)
|
||||
return;
|
||||
}
|
||||
|
||||
if (widget->options() & DockWidgetBase::Option_NotDockable) {
|
||||
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << widget;
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->supportsCentralFrame()) {
|
||||
dropArea()->m_centralFrame->addWidget(widget);
|
||||
} else {
|
||||
@@ -90,6 +95,11 @@ void MainWindowBase::addDockWidgetAsTab(DockWidgetBase *widget)
|
||||
|
||||
void MainWindowBase::addDockWidget(DockWidgetBase *dw, Location location, DockWidgetBase *relativeTo, AddingOption option)
|
||||
{
|
||||
if (dw->options() & DockWidgetBase::Option_NotDockable) {
|
||||
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << dw;
|
||||
return;
|
||||
}
|
||||
|
||||
dropArea()->addDockWidget(dw, location, relativeTo, option);
|
||||
}
|
||||
|
||||
|
||||
@@ -197,6 +197,12 @@ bool StateDragging::handleMouseButtonRelease(QPoint globalPos)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (floatingWindow->anyNonDockable()) {
|
||||
qCDebug(state) << "StateDragging: Ignoring floating window with non dockable widgets";
|
||||
Q_EMIT q->dragCanceled();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (q->m_currentDropArea) {
|
||||
if (q->m_currentDropArea->drop(floatingWindow, globalPos)) {
|
||||
Q_EMIT q->dropped();
|
||||
@@ -213,21 +219,36 @@ bool StateDragging::handleMouseButtonRelease(QPoint globalPos)
|
||||
|
||||
bool StateDragging::handleMouseMove(QPoint globalPos)
|
||||
{
|
||||
if (!q->m_windowBeingDragged->floatingWindow()) {
|
||||
FloatingWindow *fw = q->m_windowBeingDragged->floatingWindow();
|
||||
if (!fw) {
|
||||
qCDebug(state) << "Canceling drag, window was deleted";
|
||||
Q_EMIT q->dragCanceled();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!q->m_nonClientDrag)
|
||||
q->m_windowBeingDragged->floatingWindow()->windowHandle()->setPosition(globalPos - q->m_offset);
|
||||
fw->windowHandle()->setPosition(globalPos - q->m_offset);
|
||||
|
||||
|
||||
if (fw->anyNonDockable()) {
|
||||
qCDebug(state) << "StateDragging: Ignoring non dockable floating window";
|
||||
return true;
|
||||
}
|
||||
|
||||
DropArea *dropArea = q->dropAreaUnderCursor();
|
||||
if (q->m_currentDropArea && dropArea != q->m_currentDropArea)
|
||||
q->m_currentDropArea->removeHover();
|
||||
|
||||
if (dropArea)
|
||||
dropArea->hover(q->m_windowBeingDragged->floatingWindow(), globalPos);
|
||||
if (dropArea) {
|
||||
if (FloatingWindow *targetFw = dropArea->floatingWindow()) {
|
||||
if (targetFw->anyNonDockable()) {
|
||||
qCDebug(state) << "StateDragging: Ignoring non dockable target floating window";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dropArea->hover(fw, globalPos);
|
||||
}
|
||||
|
||||
q->m_currentDropArea = dropArea;
|
||||
|
||||
|
||||
@@ -260,6 +260,15 @@ bool FloatingWindow::anyNonClosable() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FloatingWindow::anyNonDockable() const
|
||||
{
|
||||
for (Frame *frame : frames()) {
|
||||
if (frame->anyNonDockable())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FloatingWindow::hasSingleFrame() const
|
||||
{
|
||||
return frames().size() == 1;
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
TitleBar *titleBar() const { return m_titleBar; }
|
||||
|
||||
bool anyNonClosable() const;
|
||||
bool anyNonDockable() const;
|
||||
|
||||
/**
|
||||
* @brief checks if this FloatingWindow only has one frame.
|
||||
|
||||
@@ -333,6 +333,16 @@ bool Frame::anyNonClosable() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Frame::anyNonDockable() const
|
||||
{
|
||||
for (auto dw : dockWidgets()) {
|
||||
if (dw->options() & DockWidgetBase::Option_NotDockable)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Frame::onDockWidgetShown(DockWidgetBase *w)
|
||||
{
|
||||
if (hasSingleDockWidget() && contains(w)) { // We have to call contains because it might be being in process of being reparented
|
||||
|
||||
@@ -164,7 +164,7 @@ public:
|
||||
|
||||
FrameOptions options() const { return m_options; }
|
||||
bool anyNonClosable() const;
|
||||
|
||||
bool anyNonDockable() const;
|
||||
|
||||
///@brief returns whether there's 0 dock widgets. If not persistent then the Frame will delete itself.
|
||||
bool isEmpty() const { return dockWidgetCount() == 0; }
|
||||
|
||||
Reference in New Issue
Block a user