diff --git a/CMakeLists.txt b/CMakeLists.txt index 32d4d8ee..66b515ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,7 @@ if(${PROJECT_NAME}_EXAMPLES) else() add_subdirectory(examples/dockwidgets) add_subdirectory(examples/minimal) + add_subdirectory(examples/minimal-mdi) set_compiler_flags(kddockwidgets_example) set_compiler_flags(kddockwidgets_minimal_example) endif() diff --git a/examples/dockwidgets/MyMainWindow.cpp b/examples/dockwidgets/MyMainWindow.cpp index 2c42f70e..acf8fdb4 100644 --- a/examples/dockwidgets/MyMainWindow.cpp +++ b/examples/dockwidgets/MyMainWindow.cpp @@ -29,11 +29,6 @@ #include #include -#if defined(DOCKS_DEVELOPER_MODE) -// Block just here for my own debugging -# include "../../src/private/MDILayoutWidget_p.h" -#endif - // clazy:excludeall=qstring-allocations,ctor-missing-parent-argument,detaching-member static MyWidget *newMyWidget() @@ -139,20 +134,6 @@ void MyMainWindow::createDockWidgets() for (int i = 0; i < numDockWidgets; i++) m_dockwidgets << newDockWidget(); -#if defined(DOCKS_DEVELOPER_MODE) - // This block is just for my testing - if (isMDI()) { - auto mdiArea = qobject_cast(layoutWidget()); - QPoint pt(10, 10); - for (KDDockWidgets::DockWidgetBase *dw : qAsConst(m_dockwidgets)) { - mdiArea->addDockWidget(dw, pt); - pt += QPoint(40, 40); - } - - return; - } -#endif - // MainWindow::addDockWidget() attaches a dock widget to the main window: addDockWidget(m_dockwidgets.at(0), KDDockWidgets::Location_OnTop); diff --git a/examples/dockwidgets/main.cpp b/examples/dockwidgets/main.cpp index ae74d7a5..43399899 100644 --- a/examples/dockwidgets/main.cpp +++ b/examples/dockwidgets/main.cpp @@ -126,13 +126,11 @@ int main(int argc, char **argv) QCommandLineOption noParentForFloating("no-parent-for-floating", QCoreApplication::translate("main", "(internal) FloatingWindows won't have a parent")); QCommandLineOption nativeTitleBar("native-title-bar", QCoreApplication::translate("main", "(internal) FloatingWindows a native title bar")); QCommandLineOption noDropIndicators("no-drop-indicators", QCoreApplication::translate("main", "(internal) Don't use any drop indicators")); - QCommandLineOption mdiLayout("mdi-layout", QCoreApplication::translate("main", "Main Window will use an MDI layout instead")); // TODO: Expose once stable parser.addOption(noQtTool); parser.addOption(noParentForFloating); parser.addOption(nativeTitleBar); parser.addOption(noDropIndicators); - parser.addOption(mdiLayout); # if defined(Q_OS_WIN) QCommandLineOption noAeroSnap("no-aero-snap", QCoreApplication::translate("main", "(internal) Disable AeroSnap")); @@ -162,9 +160,6 @@ int main(int argc, char **argv) options = parser.isSet(centralFrame) ? MainWindowOption_HasCentralFrame : MainWindowOption_None; - if (parser.isSet(mdiLayout)) - options |= MainWindowOption_MDI; // TODO: Move outside of developer mode once stable - if (parser.isSet(noQtTool)) internalFlags |= KDDockWidgets::Config::InternalFlag_DontUseQtToolWindowsForFloatingWindows; diff --git a/examples/minimal-mdi/CMakeLists.txt b/examples/minimal-mdi/CMakeLists.txt new file mode 100644 index 00000000..e0960ac2 --- /dev/null +++ b/examples/minimal-mdi/CMakeLists.txt @@ -0,0 +1,37 @@ +# +# This file is part of KDDockWidgets. +# +# SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company +# Author: Sergio Martins +# +# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only +# +# Contact KDAB at for commercial licensing options. +# + +cmake_minimum_required(VERSION 3.7) +project(kddockwidgets_minimal_mdi_example) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_INCLUDE_CURRENT_DIRS ON) + +if(NOT TARGET kddockwidgets) + # This will look for Qt, do find_package yourself manually before + # if you want to look for a specific Qt version for instance. + find_package(KDDockWidgets REQUIRED) +endif() + +set(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../dockwidgets/resources_example.qrc) + +add_executable(kddockwidgets_minimal_mdi_example + main.cpp + ../dockwidgets/MyWidget.cpp + ${RESOURCES_EXAMPLE_SRC} +) + +target_link_libraries(kddockwidgets_minimal_mdi_example + PRIVATE + KDAB::kddockwidgets +) + diff --git a/examples/minimal-mdi/MyWidget.cpp b/examples/minimal-mdi/MyWidget.cpp new file mode 100644 index 00000000..6bca080b --- /dev/null +++ b/examples/minimal-mdi/MyWidget.cpp @@ -0,0 +1,116 @@ +/* + This file is part of KDDockWidgets. + + SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company + Author: Sérgio Martins + + SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only + + Contact KDAB at for commercial licensing options. +*/ + +#include "MyWidget.h" + +#include +#include +#include +#include + +static QHash s_images; /// clazy:exclude=non-pod-global-static + +MyWidget::MyWidget(const QString &backgroundFile, const QString &logoFile, QWidget *parent) + : QWidget(parent) +{ + if (!backgroundFile.isEmpty()) { + auto it = s_images.find(backgroundFile); + if (it == s_images.end()) + it = s_images.insert(backgroundFile, QImage(backgroundFile)); + m_background = it.value(); + } + + if (!logoFile.isEmpty()) { + auto it = s_images.find(logoFile); + if (it == s_images.end()) + it = s_images.insert(logoFile, QImage(logoFile)); + m_logo = it.value(); + } + + setFocusPolicy(Qt::StrongFocus); +#if 0 + // Uncomment to show focus propagation working + new QLineEdit(this); + auto l2 = new QLineEdit(this); + l2->move(0, 100); + setFocusProxy(l2); +#endif +} + +MyWidget::~MyWidget() +{ +} + +void MyWidget::drawLogo(QPainter &p) +{ + if (m_logo.isNull()) + return; + + const qreal ratio = m_logo.height() / (m_logo.width() * 1.0); + + const int maxWidth = int(0.80 * size().width()); + const int maxHeight = int(0.80 * size().height()); + + const int proposedHeight = int(maxWidth * ratio); + + const int width = proposedHeight <= maxHeight ? maxWidth + : int(maxHeight / ratio); + + const int height = int(width * ratio); + QRect targetLogoRect(0,0, width, height); + targetLogoRect.moveCenter(rect().center() + QPoint(0, -int(size().height() * 0.00))); + p.drawImage(targetLogoRect, m_logo, m_logo.rect()); +} + +MyWidget1::MyWidget1(MyWidget::QWidget *parent) + : MyWidget(QStringLiteral(":/assets/triangles.png"), QStringLiteral(":/assets/KDAB_bubble_white.png"), parent) +{ +} + +void MyWidget1::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.fillRect(rect(), QColor(0xCC, 0xCC, 0xCC)); + p.drawImage(m_background.rect(), m_background, m_background.rect()); + + drawLogo(p); +} + +MyWidget2::MyWidget2(MyWidget::QWidget *parent) + : MyWidget(QString(), QStringLiteral(":/assets/KDAB_bubble_blue.png"), parent) +{ +} + +void MyWidget2::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.fillRect(rect(), Qt::white); + drawLogo(p); +} + +MyWidget3::MyWidget3(MyWidget::QWidget *parent) + : MyWidget(QStringLiteral(":/assets/base.png"), QStringLiteral(":/assets/KDAB_bubble_fulcolor.png"), parent) + , m_triangle(QImage(QStringLiteral(":/assets/tri.png"))) +{ +} + +void MyWidget3::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.fillRect(rect(), QColor(0xD5, 0xD5, 0xD5)); + + p.drawImage(m_background.rect(), m_background, m_background.rect()); + + const QRect targetRect = QRect({ width() - m_triangle.width(), height() - m_triangle.height() }, m_triangle.size()); + + p.drawImage(targetRect, m_triangle, m_triangle.rect()); + drawLogo(p); +} diff --git a/examples/minimal-mdi/MyWidget.h b/examples/minimal-mdi/MyWidget.h new file mode 100644 index 00000000..ad9ff91d --- /dev/null +++ b/examples/minimal-mdi/MyWidget.h @@ -0,0 +1,65 @@ +/* + This file is part of KDDockWidgets. + + SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company + Author: Sérgio Martins + + SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only + + Contact KDAB at for commercial licensing options. +*/ + +#ifndef EXAMPLEDOCKABLEWIDGET_H +#define EXAMPLEDOCKABLEWIDGET_H + +#pragma once + +#include + +QT_BEGIN_NAMESPACE +class QPainter; +QT_END_NAMESPACE + +class MyWidget : public QWidget +{ + Q_OBJECT +public: + MyWidget() = default; + explicit MyWidget(const QString &backgroundFile, const QString &logoFile, QWidget *parent = nullptr); + ~MyWidget(); +protected: + void drawLogo(QPainter &); + QImage m_background; + QImage m_logo; +}; + +class MyWidget1 : public MyWidget +{ + Q_OBJECT +public: + explicit MyWidget1(QWidget *parent = nullptr); +protected: + void paintEvent(QPaintEvent*) override; +}; + +class MyWidget2 : public MyWidget +{ + Q_OBJECT +public: + explicit MyWidget2(QWidget *parent = nullptr); +protected: + void paintEvent(QPaintEvent*) override; +}; + +class MyWidget3 : public MyWidget +{ + Q_OBJECT +public: + explicit MyWidget3(QWidget *parent = nullptr); +protected: + void paintEvent(QPaintEvent*) override; + QImage m_triangle; +}; + + +#endif diff --git a/examples/minimal-mdi/main.cpp b/examples/minimal-mdi/main.cpp new file mode 100644 index 00000000..cab1af8c --- /dev/null +++ b/examples/minimal-mdi/main.cpp @@ -0,0 +1,69 @@ +/* + This file is part of KDDockWidgets. + + SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company + Author: Sérgio Martins + + SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only + + Contact KDAB at for commercial licensing options. +*/ + +#include "MyWidget.h" + +#include +#include + +#include +#include + +// TODO: Get better API +#include "../../src/private/MDILayoutWidget_p.h" + +// clazy:excludeall=qstring-allocations + +int main(int argc, char **argv) +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif + QApplication app(argc, argv); + + app.setOrganizationName(QStringLiteral("KDAB")); + app.setApplicationName(QStringLiteral("Test app")); + + // Fusion looks better in general, but feel free to change + qApp->setStyle(QStyleFactory::create(QStringLiteral("Fusion"))); + + // # 1. Create our main window + + KDDockWidgets::MainWindow mainWindow(QStringLiteral("MyMainWindow"), + KDDockWidgets::MainWindowOption_MDI); + mainWindow.setWindowTitle("Main Window"); + mainWindow.resize(1200, 1200); + mainWindow.show(); + + // # 2. Create a dock widget, it needs a unique name + auto dock1 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock1")); + auto widget1 = new MyWidget(); + dock1->setWidget(widget1); + + auto dock2 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock2")); + auto widget2 = new MyWidget(QStringLiteral(":/assets/base.png"), + QStringLiteral(":/assets/KDAB_bubble_fulcolor.png")); + dock2->setWidget(widget2); + + auto dock3 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock3")); + auto widget3 = new MyWidget(QStringLiteral(":/assets/base.png"), + QStringLiteral(":/assets/KDAB_bubble_fulcolor.png")); + dock3->setWidget(widget3); + + // TODO: Get better API + auto layout = qobject_cast(mainWindow.layoutWidget()); + layout->addDockWidget(dock1, QPoint(10, 10)); + layout->addDockWidget(dock2, QPoint(50, 50)); + layout->addDockWidget(dock3, QPoint(90, 90)); + + return app.exec(); +} diff --git a/src/private/DragController.cpp b/src/private/DragController.cpp index 5a7339bd..db885306 100644 --- a/src/private/DragController.cpp +++ b/src/private/DragController.cpp @@ -373,6 +373,36 @@ bool StateDragging::handleMouseDoubleClick() return false; } +StateInternalMDIDragging::StateInternalMDIDragging(DragController *parent) + : StateBase(parent) +{ +} + +StateInternalMDIDragging::~StateInternalMDIDragging() +{ +} + +void StateInternalMDIDragging::onEntry() +{ +} + +bool StateInternalMDIDragging::handleMouseButtonRelease(QPoint globalPos) +{ + Q_UNUSED(globalPos); + return false; +} + +bool StateInternalMDIDragging::handleMouseMove(QPoint globalPos) +{ + Q_UNUSED(globalPos); + return false; +} + +bool StateInternalMDIDragging::handleMouseDoubleClick() +{ + return false; +} + StateDraggingWayland::StateDraggingWayland(DragController *parent) : StateDragging(parent) { diff --git a/src/private/DragController_p.h b/src/private/DragController_p.h index 2d81fc5d..0f882785 100644 --- a/src/private/DragController_p.h +++ b/src/private/DragController_p.h @@ -185,6 +185,21 @@ public: bool handleMouseDoubleClick() override; }; + +/// @brief State when we're moving an MDI dock widget around the main window +/// without it becoming floating +class StateInternalMDIDragging : public StateBase +{ + Q_OBJECT +public: + explicit StateInternalMDIDragging(DragController *parent); + ~StateInternalMDIDragging() override; + void onEntry() override; + bool handleMouseButtonRelease(QPoint globalPos) override; + bool handleMouseMove(QPoint globalPos) override; + bool handleMouseDoubleClick() override; +}; + // Used on wayland only to use QDrag instead of setting geometry on mouse-move. class StateDraggingWayland : public StateDragging {