├── .gitignore ├── DockWindow.qml ├── README.md ├── deployment.pri ├── draggingwindow.cpp ├── draggingwindow.h ├── main.cpp ├── main.qml ├── qdockablewindow.cpp ├── qdockablewindow.h ├── qdockgroup.cpp ├── qdockgroup.h ├── qml.qrc └── qquickdock.pro /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # C++ objects and libs 3 | 4 | *.slo 5 | *.lo 6 | *.o 7 | *.a 8 | *.la 9 | *.lai 10 | *.so 11 | *.dll 12 | *.dylib 13 | 14 | # Qt-es 15 | 16 | /.qmake.cache 17 | /.qmake.stash 18 | *.pro.user 19 | *.pro.user.* 20 | *.qbs.user 21 | *.qbs.user.* 22 | *.moc 23 | moc_*.cpp 24 | qrc_*.cpp 25 | ui_*.h 26 | Makefile* 27 | *build-* 28 | 29 | # QtCreator 30 | 31 | *.autosave 32 | 33 | # QtCtreator Qml 34 | *.qmlproject.user 35 | *.qmlproject.user.* 36 | 37 | # QtCtreator CMake 38 | CMakeLists.txt.user* 39 | -------------------------------------------------------------------------------- /DockWindow.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Window.Dock 1.0 3 | 4 | DockableWindow { 5 | id: dockWindow 6 | visible: true 7 | width: 640 8 | height: 480 9 | title: qsTr("Hello World") 10 | 11 | flags: Qt.FramelessWindowHint 12 | 13 | color: "transparent" 14 | property alias title: title.text 15 | 16 | Item { 17 | id: stateManager 18 | states: [ 19 | State { 20 | name: "" 21 | }, 22 | State { 23 | name: "freeDragging" 24 | PropertyChanges { 25 | target: dockWindow 26 | width: tabHeader.width 27 | height: tabHeader.height 28 | } 29 | PropertyChanges { 30 | target: closeButton 31 | visible: false 32 | } 33 | PropertyChanges { 34 | target: dockWindow 35 | } 36 | } 37 | ] 38 | } 39 | 40 | Rectangle { 41 | width: parent.width 42 | height: parent.height 43 | 44 | radius: 10 45 | 46 | color: "red" 47 | } 48 | 49 | Rectangle { 50 | id: titleBar 51 | width: parent.width 52 | height: 30 53 | 54 | color: "orange" 55 | 56 | MouseArea { 57 | anchors.fill: parent 58 | 59 | property point orgPos: "0, 0" 60 | 61 | onPressed: { 62 | console.log("onPressed"); 63 | orgPos.x = mouse.x; 64 | orgPos.y = mouse.y; 65 | 66 | 67 | } 68 | 69 | onPositionChanged: { 70 | dockWindow.x += mouse.x - orgPos.x; 71 | dockWindow.y += mouse.y - orgPos.y; 72 | } 73 | } 74 | } 75 | 76 | Rectangle { 77 | id: tabHeader 78 | 79 | width: 100 80 | height: 30 81 | 82 | color: "yellow" 83 | 84 | Text { 85 | id: title 86 | anchors.centerIn: parent 87 | } 88 | 89 | MouseArea { 90 | anchors.fill: parent 91 | 92 | hoverEnabled: true 93 | 94 | property point orgPos: "0, 0" 95 | property bool cancelDragging: false 96 | 97 | onPressed: { 98 | console.log("onPressed"); 99 | orgPos.x = mouse.x; 100 | orgPos.y = mouse.y; 101 | 102 | cancelDragging = false; 103 | } 104 | 105 | onEntered: { 106 | //console.log("onEntered"); 107 | startDrag(); 108 | } 109 | 110 | onReleased: { 111 | //stateManager.state = ""; 112 | } 113 | } 114 | } 115 | 116 | Rectangle { 117 | id: closeButton 118 | 119 | anchors.right: parent.right 120 | 121 | width: 30 122 | height: 30 123 | 124 | color: "black" 125 | 126 | MouseArea { 127 | anchors.fill: parent 128 | onClicked: { 129 | Qt.quit(); 130 | } 131 | } 132 | } 133 | 134 | Component.onCompleted: { 135 | console.log("on compledted ", title.text); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QQuickDock 2 | Docking window for Qt Quick 3 | -------------------------------------------------------------------------------- /deployment.pri: -------------------------------------------------------------------------------- 1 | unix:!android { 2 | isEmpty(target.path) { 3 | qnx { 4 | target.path = /tmp/$${TARGET}/bin 5 | } else { 6 | target.path = /opt/$${TARGET}/bin 7 | } 8 | export(target.path) 9 | } 10 | INSTALLS += target 11 | } 12 | 13 | export(INSTALLS) 14 | -------------------------------------------------------------------------------- /draggingwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "draggingwindow.h" 2 | #include 3 | 4 | DraggingWindow::DraggingWindow(QWindow* parent) 5 | : QQuickWindow(parent), 6 | mPressing(false) 7 | { 8 | setFlags(Qt::SplashScreen | Qt::WindowStaysOnTopHint); 9 | setWidth(100); 10 | setHeight(30); 11 | setMouseGrabEnabled(true); 12 | } 13 | 14 | void DraggingWindow::mousePressEvent(QMouseEvent *ev) 15 | { 16 | qDebug() << "mouse Press"; 17 | mOrigin = ev->pos(); 18 | mPressing = true; 19 | 20 | QQuickWindow::mousePressEvent(ev); 21 | } 22 | 23 | void DraggingWindow::mouseMoveEvent(QMouseEvent *ev) 24 | { 25 | static int counter = 0; 26 | 27 | if (!mPressing) { 28 | return; 29 | } 30 | 31 | counter ++; 32 | qDebug() << "mouse move event" << counter; 33 | //QQuickWindow::mouseMoveEvent(ev); 34 | 35 | QPoint dockPosition = position(); 36 | 37 | dockPosition += ev->pos() - mOrigin; 38 | 39 | setPosition(dockPosition); 40 | 41 | //ev->ignore(); 42 | } 43 | 44 | void DraggingWindow::mouseReleaseEvent(QMouseEvent *ev) 45 | { 46 | mPressing = false; 47 | } 48 | -------------------------------------------------------------------------------- /draggingwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef DRAGGINGWINDOW_H 2 | #define DRAGGINGWINDOW_H 3 | 4 | #include 5 | 6 | class DraggingWindow : public QQuickWindow 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit DraggingWindow(QWindow* parent = 0); 11 | 12 | 13 | protected: 14 | void mousePressEvent(QMouseEvent *ev); 15 | void mouseMoveEvent(QMouseEvent *ev); 16 | void mouseReleaseEvent(QMouseEvent *ev); 17 | 18 | 19 | private: 20 | QPoint mOrigin; 21 | bool mPressing; 22 | }; 23 | 24 | #endif // DRAGGINGWINDOW_H 25 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "qdockablewindow.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | QGuiApplication app(argc, argv); 10 | 11 | qmlRegisterType("QtQuick.Window.Dock", 1, 0, "DockableWindow"); 12 | 13 | 14 | QQmlApplicationEngine engine; 15 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 16 | 17 | 18 | 19 | return app.exec(); 20 | } 21 | -------------------------------------------------------------------------------- /main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Window 2.2 3 | import QtQuick.Window.Dock 1.0 4 | 5 | DockWindow { 6 | id: rootWindow 7 | 8 | visible: true 9 | width: 200 10 | height: 200 11 | 12 | property var visibleWindows 13 | 14 | onVisibleWindowsChanged: { 15 | console.log("visibleWindowsChanged: ", visibleWindows.length); 16 | 17 | for (var i = 0; i < visibleWindows.length; i++) { 18 | console.log(" ", visibleWindows[i].title); 19 | } 20 | } 21 | 22 | function focusTo(dockWindow) { 23 | console.log("onDockWindowFocused"); 24 | 25 | if (!visibleWindows) { 26 | visibleWindows = []; 27 | } 28 | 29 | var idx = visibleWindows.indexOf(dockWindow); 30 | if (idx >= 0) { 31 | visibleWindows.splice(idx, 1); 32 | } 33 | 34 | visibleWindows.unshift(dockWindow); 35 | console.log(" visibleWindows.length: ", visibleWindows.length); 36 | 37 | 38 | visibleWindowsChanged(); 39 | } 40 | 41 | //property list visibleWindows; 42 | 43 | DockWindow { 44 | id: dock01 45 | visible: true 46 | width: 400 47 | height: 300 48 | x: 0 49 | 50 | title: "dock01" 51 | } 52 | 53 | DockWindow { 54 | id: dock02 55 | visible: true 56 | x: 400 57 | width: 300 58 | height: 200 59 | 60 | title: "dock02" 61 | 62 | Rectangle { 63 | anchors.centerIn: parent 64 | width: 100 65 | height: 30 66 | 67 | color: "blue" 68 | 69 | MouseArea { 70 | anchors.fill: parent 71 | 72 | onClicked: { 73 | dock02.test01(); 74 | } 75 | } 76 | } 77 | } 78 | 79 | Window { 80 | id: draggingTab 81 | visible: false; 82 | 83 | width: tabHeader.width 84 | height: tabHeader.height 85 | 86 | flags: Qt.SplashScreen 87 | 88 | property alias title: title.text 89 | 90 | Rectangle { 91 | id: tabHeader 92 | 93 | width: 100 94 | height: 30 95 | 96 | color: "orange" 97 | 98 | Text { 99 | id: title 100 | anchors.centerIn: parent 101 | } 102 | } 103 | 104 | MouseArea { 105 | anchors.fill: parent 106 | 107 | property point orgPos: "0, 0" 108 | 109 | onPressed: { 110 | console.log("onPressed"); 111 | orgPos.x = mouse.x; 112 | orgPos.y = mouse.y; 113 | } 114 | 115 | onPositionChanged: { 116 | if (cancelDragging) { 117 | return; 118 | } 119 | 120 | //console.log(mouse.x, mouse.y); 121 | 122 | stateManager.state = "freeDragging"; 123 | 124 | draggingTab.x += mouse.x - orgPos.x; 125 | draggingTab.y += mouse.y - orgPos.y; 126 | 127 | } 128 | 129 | onReleased: { 130 | //stateManager.state = ""; 131 | } 132 | } 133 | } 134 | 135 | 136 | // DockableWindow { 137 | // id: dock02 138 | // visible: true 139 | 140 | // width: 200 141 | // height: 200 142 | 143 | // color: "yellow" 144 | 145 | 146 | // } 147 | 148 | Component.onCompleted: { 149 | console.log("on compledted rootWindow"); 150 | 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /qdockablewindow.cpp: -------------------------------------------------------------------------------- 1 | #include "qdockablewindow.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "qdockgroup.h" 7 | 8 | QDockableWindow::QDockableWindow(QWindow* parent) 9 | : QQuickWindow(parent) 10 | { 11 | } 12 | 13 | void QDockableWindow::setDockGroup(QDockGroup *group) 14 | { 15 | dockGroup = group; 16 | } 17 | 18 | void QDockableWindow::moveEvent(QMoveEvent *ev) 19 | { 20 | QQuickWindow::moveEvent(ev); 21 | 22 | //qDebug() << "moveEvent"; 23 | } 24 | 25 | bool QDockableWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) 26 | { 27 | bool rslt = QQuickWindow::nativeEvent(eventType, message, result); 28 | 29 | qDebug() << eventType; 30 | 31 | return rslt; 32 | } 33 | 34 | void QDockableWindow::focusInEvent(QFocusEvent *ev) 35 | { 36 | QQuickWindow::focusInEvent(ev); 37 | 38 | //qDebug() << "window" << id << "focused"; 39 | 40 | emit focusIn(); 41 | } 42 | 43 | void QDockableWindow::mouseMoveEvent(QMouseEvent *ev) 44 | { 45 | //qDebug() << "window " << id << " mouse move event"; 46 | QQuickWindow::mouseMoveEvent(ev); 47 | } 48 | 49 | void QDockableWindow::test01() 50 | { 51 | QWindowList list = QGuiApplication::topLevelWindows(); 52 | 53 | qDebug() << "number of window = " << list.count(); 54 | } 55 | 56 | void QDockableWindow::startDrag() 57 | { 58 | qDebug() << "QDockableWindow::startDrag"; 59 | 60 | DraggingWindow* dragWin = QDockGroup::draggingWindow(); 61 | 62 | dragWin->show(); 63 | dragWin->raise(); 64 | 65 | dragWin->setPosition(position()); 66 | } 67 | 68 | QDockableWindow* QDockableWindow::topLevelAt(const QPoint &pos) 69 | { 70 | 71 | QWindowList list = QGuiApplication::topLevelWindows(); 72 | for (int i = list.size()-1; i >= 0; --i) { 73 | QDockableWindow *w = qobject_cast(list[i]); 74 | 75 | qDebug() << w->geometry() << pos; 76 | 77 | if (w && w->isVisible() && w->geometry().contains(pos)) 78 | return w; 79 | } 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /qdockablewindow.h: -------------------------------------------------------------------------------- 1 | #ifndef QDOCKABLEWINDOW_H 2 | #define QDOCKABLEWINDOW_H 3 | 4 | #include 5 | 6 | class QDockGroup; 7 | 8 | class QDockableWindow : public QQuickWindow 9 | { 10 | Q_OBJECT 11 | public: 12 | explicit QDockableWindow(QWindow* parent = 0); 13 | 14 | int id; 15 | QDockGroup* dockGroup; 16 | 17 | void setDockGroup(QDockGroup* group); 18 | 19 | static QDockableWindow* topLevelAt(const QPoint &pos); 20 | 21 | signals: 22 | void focusIn(); 23 | 24 | protected: 25 | void moveEvent(QMoveEvent *ev); 26 | void mouseMoveEvent(QMouseEvent *ev); 27 | bool nativeEvent(const QByteArray &eventType, void *message, long *result); 28 | void focusInEvent(QFocusEvent *ev); 29 | 30 | public slots: 31 | void test01(); 32 | void startDrag(); 33 | }; 34 | 35 | #endif // QDOCKABLEWINDOW_H 36 | -------------------------------------------------------------------------------- /qdockgroup.cpp: -------------------------------------------------------------------------------- 1 | #include "qdockgroup.h" 2 | 3 | QDockGroup::QDockGroup(QObject *parent) : QObject(parent) 4 | { 5 | 6 | } 7 | 8 | QDockGroup* QDockGroup::instance() 9 | { 10 | static QDockGroup* sInstance = new QDockGroup(); 11 | 12 | return sInstance; 13 | } 14 | 15 | DraggingWindow* QDockGroup::draggingWindow() 16 | { 17 | static DraggingWindow* sDraggingWindow = new DraggingWindow(); 18 | 19 | return sDraggingWindow; 20 | } 21 | -------------------------------------------------------------------------------- /qdockgroup.h: -------------------------------------------------------------------------------- 1 | #ifndef QDOCKGROUP_H 2 | #define QDOCKGROUP_H 3 | 4 | #include 5 | #include 6 | 7 | #include "qdockablewindow.h" 8 | #include "draggingwindow.h" 9 | 10 | class QDockGroup : public QObject 11 | { 12 | Q_OBJECT 13 | private: 14 | explicit QDockGroup(QObject *parent = 0); 15 | 16 | public: 17 | static QDockGroup* instance(); 18 | static DraggingWindow* draggingWindow(); 19 | 20 | signals: 21 | 22 | public slots: 23 | 24 | 25 | 26 | }; 27 | 28 | #endif // QDOCKGROUP_H 29 | -------------------------------------------------------------------------------- /qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | DockWindow.qml 5 | 6 | 7 | -------------------------------------------------------------------------------- /qquickdock.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += qml quick 4 | CONFIG += c++11 5 | 6 | SOURCES += main.cpp \ 7 | qdockablewindow.cpp \ 8 | qdockgroup.cpp \ 9 | draggingwindow.cpp 10 | 11 | RESOURCES += qml.qrc 12 | 13 | # Additional import path used to resolve QML modules in Qt Creator's code model 14 | QML_IMPORT_PATH = 15 | 16 | # Default rules for deployment. 17 | include(deployment.pri) 18 | 19 | HEADERS += \ 20 | qdockablewindow.h \ 21 | qdockgroup.h \ 22 | draggingwindow.h 23 | 24 | DISTFILES += 25 | --------------------------------------------------------------------------------