Compare commits
117 Commits
LabMCT_KDD
...
advancedCu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61079be42d | ||
|
|
743dbc0718 | ||
|
|
fd4588de0f | ||
|
|
6ba10cfe12 | ||
|
|
096176dc72 | ||
|
|
25b04d7ed8 | ||
|
|
e345e89c35 | ||
|
|
a97663294c | ||
|
|
bb4cf802f5 | ||
|
|
701069617c | ||
|
|
a8c50f1876 | ||
|
|
61cca1e5ec | ||
|
|
7db9938b85 | ||
|
|
01cc915734 | ||
|
|
3454b67a45 | ||
|
|
21765efbac | ||
|
|
60a1e46453 | ||
|
|
8b8ef7f2b0 | ||
|
|
c0e8fe3869 | ||
|
|
524dff9105 | ||
|
|
0099a19a82 | ||
|
|
e6b8636e88 | ||
|
|
86419fd979 | ||
|
|
220471f746 | ||
|
|
412860abac | ||
|
|
2eeb4aac27 | ||
|
|
bfb2ec701e | ||
|
|
54bf24d5d4 | ||
|
|
76cbb760ed | ||
|
|
4824a398ab | ||
|
|
a502a8250b | ||
|
|
85fb4ff671 | ||
|
|
6db3ccc87f | ||
|
|
5811cab164 | ||
|
|
1387c2f573 | ||
|
|
79cc347cd8 | ||
|
|
e62bde3152 | ||
|
|
81abb3cea5 | ||
|
|
ecd3c20adf | ||
|
|
755d53432b | ||
|
|
e00a552bf8 | ||
|
|
faf93fe597 | ||
|
|
4f8aac7df3 | ||
|
|
719803ecfa | ||
|
|
f0ef24383b | ||
|
|
4f8b174a8d | ||
|
|
675b166956 | ||
|
|
b13ba1e42e | ||
|
|
481dae64c3 | ||
|
|
6b04e20a7e | ||
|
|
8a3ee35993 | ||
|
|
146c656e29 | ||
|
|
a190e2dfbf | ||
|
|
d0daff6771 | ||
|
|
721795b113 | ||
|
|
40231b7fae | ||
|
|
1d0300ecc8 | ||
|
|
ce20628555 | ||
|
|
d0dcac6b03 | ||
|
|
2b1aa44eff | ||
|
|
ae42dffcb1 | ||
|
|
21adfe06ad | ||
|
|
7de26139a2 | ||
|
|
894ff9fea0 | ||
|
|
942c462586 | ||
|
|
128645693c | ||
|
|
86bceb4c48 | ||
|
|
ea64aae861 | ||
|
|
d1645dff73 | ||
|
|
a72e018f3b | ||
|
|
66b0ba8902 | ||
|
|
18457d80aa | ||
|
|
95c12dbd4c | ||
|
|
c7682a3524 | ||
|
|
4922363e71 | ||
|
|
9f6ec0244f | ||
|
|
747e987f28 | ||
|
|
68e01c70ee | ||
|
|
296b2a3370 | ||
|
|
074bc26be9 | ||
|
|
f8e6ecf821 | ||
|
|
3e70a2cc71 | ||
|
|
65ced9604f | ||
|
|
45b0536c6a | ||
|
|
8c8f5a8fda | ||
|
|
22a9ce2596 | ||
|
|
f13f0129d4 | ||
|
|
22ffc6c7ea | ||
|
|
d1767b5534 | ||
|
|
2fbe4f872e | ||
|
|
9c17b44ad7 | ||
|
|
16c43b8c24 | ||
|
|
8391d85d48 | ||
|
|
e59e5d7a71 | ||
|
|
aa3c3272ee | ||
|
|
1d8fad245a | ||
|
|
789c531f3d | ||
|
|
5b87fb4435 | ||
|
|
402f0b9d90 | ||
|
|
37567d3980 | ||
|
|
6cef4cea2c | ||
|
|
aea2bf971b | ||
|
|
00a0e455e7 | ||
|
|
d5c7fbfedd | ||
|
|
bea6c09494 | ||
|
|
92d0d74641 | ||
|
|
4d4f2a0183 | ||
|
|
64b5564f99 | ||
|
|
66cc9ddc03 | ||
|
|
336f1146d3 | ||
|
|
29b1a434c4 | ||
|
|
b20ce0895b | ||
|
|
e67f55af51 | ||
|
|
f1410948f8 | ||
|
|
d832750eb7 | ||
|
|
77392709e2 | ||
|
|
6fd0b4ddee |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -64,3 +64,5 @@ kddockwidgets_minimal_example
|
||||
*.sln
|
||||
*.dir
|
||||
.vscode
|
||||
/.cache
|
||||
/compile_commands.json
|
||||
|
||||
@@ -90,10 +90,10 @@ endif()
|
||||
|
||||
set(${PROJECT_NAME}_VERSION_MAJOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 5)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 1)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 95)
|
||||
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
|
||||
set(PROJECT_VERSION ${${PROJECT_NAME}_VERSION}) #PROJECT_VERSION is needed by some ECM modules
|
||||
set(${PROJECT_NAME}_SOVERSION "1.5")
|
||||
set(${PROJECT_NAME}_SOVERSION "1.6")
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
@@ -132,22 +132,18 @@ endif()
|
||||
if(${PROJECT_NAME}_QT6)
|
||||
set(Qt_VERSION_MAJOR 6)
|
||||
set(QT_MIN_VERSION "6.0.0")
|
||||
find_package(Qt6Widgets ${QT_MIN_VERSION} REQUIRED)
|
||||
find_package(Qt6Test ${QT_MIN_VERSION} REQUIRED)
|
||||
set(${PROJECT_NAME}_LIBRARY_QTID "-qt6")
|
||||
else()
|
||||
set(Qt_VERSION_MAJOR 5)
|
||||
set(QT_MIN_VERSION "5.15")
|
||||
find_package(Qt5Widgets ${QT_MIN_VERSION} REQUIRED)
|
||||
find_package(Qt5Test ${QT_MIN_VERSION} REQUIRED)
|
||||
set(${PROJECT_NAME}_LIBRARY_QTID "")
|
||||
endif()
|
||||
find_package(Qt${Qt_VERSION_MAJOR} ${QT_MIN_VERSION} NO_MODULE REQUIRED COMPONENTS Widgets Test)
|
||||
include(KDQtInstallPaths) #to set QT_INSTALL_FOO variables
|
||||
|
||||
set(${PROJECT_NAME}_DEPS "widgets")
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
find_package(Qt${Qt_VERSION_MAJOR}Quick)
|
||||
find_package(Qt${Qt_VERSION_MAJOR}QuickControls2)
|
||||
find_package(Qt${Qt_VERSION_MAJOR} NO_MODULE REQUIRED COMPONENTS Quick QuickControls2)
|
||||
add_definitions(-DKDDOCKWIDGETS_QTQUICK)
|
||||
set(${PROJECT_NAME}_DEPS "${${PROJECT_NAME}_DEPS} quick quickcontrols2")
|
||||
else()
|
||||
@@ -217,11 +213,13 @@ if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE) OR
|
||||
set(sanitizers_enabled FALSE)
|
||||
endif()
|
||||
|
||||
# cannot enable this for clang + sanitizers
|
||||
if(NOT sanitizers_enabled OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Do not allow undefined symbols, even in non-symbolic shared libraries
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_MODULE_LINKER_FLAGS}")
|
||||
if(APPLE OR LINUX)
|
||||
# cannot enable this for clang + sanitizers
|
||||
if(NOT sanitizers_enabled OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Do not allow undefined symbols, even in non-symbolic shared libraries
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_MODULE_LINKER_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -298,8 +296,10 @@ if(${PROJECT_NAME}_EXAMPLES)
|
||||
add_subdirectory(examples/dockwidgets)
|
||||
add_subdirectory(examples/minimal)
|
||||
add_subdirectory(examples/minimal-mdi)
|
||||
add_subdirectory(examples/mdi_with_docking)
|
||||
set_compiler_flags(kddockwidgets_example)
|
||||
set_compiler_flags(kddockwidgets_minimal_example)
|
||||
set_compiler_flags(kddockwidgets_mdi_with_docking_example)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"KDDockWidgets_FUZZER" : "OFF"
|
||||
},
|
||||
@@ -18,16 +17,17 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-gammaray",
|
||||
"displayName": "dev-gammaray",
|
||||
"description": "A Gammaray friendly build. (No ASAN)",
|
||||
"name": "dev-asan",
|
||||
"displayName": "dev-asan",
|
||||
"description": "An ASAN/UBSAN build",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-dev-gammaray",
|
||||
"binaryDir": "${sourceDir}/build-dev-asan",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"KDDockWidgets_FUZZER" : "OFF"
|
||||
"KDDockWidgets_FUZZER" : "OFF",
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'"
|
||||
},
|
||||
"warnings" : {
|
||||
"uninitialized" : true
|
||||
@@ -164,6 +164,23 @@
|
||||
"displayName": "dev6",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-dev6",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_QT6": "ON",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"KDDockWidgets_FUZZER" : "OFF",
|
||||
"CMAKE_PREFIX_PATH" : "$env{QT6_DIR}"
|
||||
},
|
||||
"environment": {
|
||||
"PATH": "$env{QT6_DIR}/bin:$penv{PATH}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-asan6",
|
||||
"displayName": "dev-asan6",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-dev-asan6",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_QT6": "ON",
|
||||
@@ -295,6 +312,51 @@
|
||||
"QML2_IMPORT_PATH" : "$env{QT6_DIR}/imports:$env{QT6_DIR}/qml",
|
||||
"LD_LIBRARY_PATH" : "$env{QT6_DIR}/lib"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-time-trace",
|
||||
"displayName": "dev-time-trace",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-dev-time-trace",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"KDDockWidgets_FUZZER" : "OFF",
|
||||
"CMAKE_C_FLAGS_INIT" : "-ftime-trace",
|
||||
"CMAKE_CXX_FLAGS_INIT": "-ftime-trace"
|
||||
},
|
||||
"warnings" : {
|
||||
"uninitialized" : true
|
||||
},
|
||||
"environment": {
|
||||
"CC": "clang",
|
||||
"CXX": "clang++",
|
||||
"CCACHE_DISABLE" : "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev6-time-trace",
|
||||
"displayName": "dev6-time-trace",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-dev6-time-trace",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"KDDockWidgets_FUZZER" : "OFF",
|
||||
"KDDockWidgets_QT6" : "ON",
|
||||
"CMAKE_C_FLAGS_INIT" : "-ftime-trace",
|
||||
"CMAKE_CXX_FLAGS_INIT": "-ftime-trace"
|
||||
},
|
||||
"warnings" : {
|
||||
"uninitialized" : true
|
||||
},
|
||||
"environment": {
|
||||
"CC": "clang",
|
||||
"CXX": "clang++",
|
||||
"CCACHE_DISABLE" : "ON"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
|
||||
10
Changelog
10
Changelog
@@ -1,3 +1,13 @@
|
||||
* v1.6.0 (unreleased)
|
||||
- Fixed restoring of normal geometry when closing a maximized window (#259)
|
||||
- Experimental support for docking into dock widgets which are in a MDI area.
|
||||
- Fixed potential crash involving infinite loop between QWidget::create() and QWidget::createWinId()
|
||||
- Moved DropIndicatorOverlayInterface::DropLocation enum to KDDockWidgets namespace scope
|
||||
- Added Config::setDropIndicatorAllowedFunc() and corresponding example
|
||||
(kddockwidgets_example --hide-certain-docking-indicators)
|
||||
- Fixed case where unfloating wouldn't restore to the main window (#44 and #96)
|
||||
- Fixed MainWindow not propagating close events to docked widgets
|
||||
|
||||
* v1.5.1 (unreleased)
|
||||
- X11: Improved detecting which window is under the cursor, by using native X11 API
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
Supported Qt versions and toolchains
|
||||
=====================================
|
||||
|
||||
KDDockWidgets for QtQuick requires a C++17 capable compiler and either
|
||||
Qt >= 5.15.2 or Qt >= 6.2.1
|
||||
KDDockWidgets for QtQuick requires a C++17 capable compiler and Qt >= 6.2.1.
|
||||
|
||||
Qt 5.15.2 will probably also work, but it's not built and tested by KDAB CI, we
|
||||
advise users to move to Qt6 as soon as possible.
|
||||
|
||||
|
||||
|
||||
TROUBLESHOOTING
|
||||
|
||||
@@ -156,8 +156,9 @@ your application whenever updating KDDW.
|
||||
|
||||
|
||||
Supported Qt versions and toolchains
|
||||
=====================================
|
||||
KDDockWidgets requires Qt 5.15.x or Qt6 >= 6.2.
|
||||
====================================
|
||||
KDDockWidgets requires a C++17 capable compiler and Qt 5.15.x or Qt6 >= 6.2
|
||||
For QtQuick support see [README-QtQuick.md](README-QtQuick.md).
|
||||
|
||||
|
||||
Styling
|
||||
|
||||
17
appveyor.yml
17
appveyor.yml
@@ -19,7 +19,7 @@ skip_tags: false
|
||||
|
||||
# Build worker image
|
||||
image:
|
||||
- Ubuntu
|
||||
- Ubuntu2004
|
||||
- macos
|
||||
- Visual Studio 2019
|
||||
|
||||
@@ -40,19 +40,24 @@ configuration:
|
||||
- Release
|
||||
- Debug
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- useqt6: False
|
||||
- useqt6: True
|
||||
|
||||
install:
|
||||
- sh: if [ "`uname -s`" = "Darwin" ]; then brew install ninja; else sudo apt-get -y install mesa-common-dev libglu1-mesa-dev; fi
|
||||
- sh: if [ "`uname -s`" = "Darwin" ]; then brew install ninja; else sudo apt-get -y update; sudo apt-get -y install mesa-common-dev libglu1-mesa-dev libxkbcommon-dev libxkbcommon-x11-dev; fi
|
||||
|
||||
before_build:
|
||||
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
- cmd: set PATH=C:\Qt\5.15\msvc2019_64;%PATH%
|
||||
- sh: if [ "`uname -s`" = "Darwin" ]; then export PATH=$HOME/Qt/5.15/clang_64/bin:$PATH; else export PATH=$HOME/Qt/5.15/gcc_64/bin:$PATH; fi
|
||||
- cmd: set PATH=C:\Qt\6.2\msvc2019_64;C:\Qt\5.15\msvc2019_64;%PATH%
|
||||
- sh: if [ "`uname -s`" = "Darwin" ]; then export PATH=$HOME/Qt/6.1/macos/bin:$HOME/Qt/5.15/clang_64/bin:$PATH; else export PATH=$HOME/Qt/6.2/gcc_64/bin:$HOME/Qt/5.15/gcc_64/bin:$PATH; fi
|
||||
|
||||
build_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmd: cmake -G Ninja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DKDDockWidgets_TESTS=True -DKDDockWidgets_EXAMPLES=True -DKDDockWidgets_DEVELOPER_MODE=True ..
|
||||
- sh: cmake -G Ninja -DCMAKE_BUILD_TYPE=$CONFIGURATION -DKDDockWidgets_TESTS=True -DKDDockWidgets_EXAMPLES=True -DKDDockWidgets_DEVELOPER_MODE=True ..
|
||||
- cmd: cmake -G Ninja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DKDDockWidgets_QT6=%useqt6% -DKDDockWidgets_TESTS=True -DKDDockWidgets_EXAMPLES=True -DKDDockWidgets_DEVELOPER_MODE=True ..
|
||||
- sh: cmake -G Ninja -DCMAKE_BUILD_TYPE=$CONFIGURATION -DKDDockWidgets_QT6=$useqt6 -DKDDockWidgets_TESTS=True -DKDDockWidgets_EXAMPLES=True -DKDDockWidgets_DEVELOPER_MODE=True ..
|
||||
- cmake --build .
|
||||
- cmd: cmake --build . --target install
|
||||
- sh: sudo cmake --build . --target install
|
||||
|
||||
@@ -47,6 +47,17 @@
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": false
|
||||
},
|
||||
{
|
||||
"name": "gdb-kddockwidgets_mdi_with_docking_example",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build-dev/bin/kddockwidgets_mdi_with_docking_example",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"MIMode": "gdb",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": false
|
||||
},
|
||||
{
|
||||
"name": "gdb-tst_docks",
|
||||
"type": "cppdbg",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <kddockwidgets/FrameworkWidgetFactory.h>
|
||||
|
||||
#include <kddockwidgets/private/TabWidget_p.h>
|
||||
#include <kddockwidgets/private/FloatingWindow_p.h>
|
||||
#include <kddockwidgets/private/widgets/FrameWidget_p.h>
|
||||
#include <kddockwidgets/private/widgets/TabBarWidget_p.h>
|
||||
#include <kddockwidgets/private/widgets/TabWidgetWidget_p.h>
|
||||
@@ -28,6 +29,7 @@
|
||||
class MyTitleBar : public KDDockWidgets::TitleBarWidget
|
||||
{
|
||||
public:
|
||||
bool m_isSpecialType = false;
|
||||
explicit MyTitleBar(KDDockWidgets::Frame *frame)
|
||||
: KDDockWidgets::TitleBarWidget(frame)
|
||||
{
|
||||
@@ -45,24 +47,73 @@ public:
|
||||
void init()
|
||||
{
|
||||
setFixedHeight(60);
|
||||
|
||||
if (auto tb = tabBar()) {
|
||||
if (auto tbWidget = qobject_cast<KDDockWidgets::TabBarWidget *>(tb->asWidget())) {
|
||||
// 1. Be notified when dock widgets are added/removed from the tabbar and when current changes
|
||||
|
||||
connect(tbWidget, &KDDockWidgets::TabBarWidget::dockWidgetInserted, this, &MyTitleBar::updateType);
|
||||
connect(tbWidget, &KDDockWidgets::TabBarWidget::dockWidgetRemoved, this, &MyTitleBar::updateType);
|
||||
connect(tbWidget, &KDDockWidgets::TabBarWidget::currentChanged, this, &MyTitleBar::updateType);
|
||||
}
|
||||
}
|
||||
|
||||
if (KDDockWidgets::FloatingWindow *fw = floatingWindow()) {
|
||||
// 2. Floating Windows with more than 1 Frame (more than 1 tabbar) won't have a special titlebar.
|
||||
// during runtime a FloatingWindow can have frames removed/added, so update its title bar type.
|
||||
connect(fw, &KDDockWidgets::FloatingWindow::numFramesChanged, this, &MyTitleBar::updateType);
|
||||
}
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent *) override
|
||||
void updateType()
|
||||
{
|
||||
QPainter p(this);
|
||||
QPen pen(Qt::black);
|
||||
const QColor focusedBackgroundColor = Qt::yellow;
|
||||
const QColor backgroundColor = focusedBackgroundColor.darker(115);
|
||||
QBrush brush(isFocused() ? focusedBackgroundColor : backgroundColor);
|
||||
pen.setWidth(4);
|
||||
p.setPen(pen);
|
||||
p.setBrush(brush);
|
||||
p.drawRect(rect().adjusted(4, 4, -4, -4));
|
||||
QFont f = qApp->font();
|
||||
f.setPixelSize(30);
|
||||
f.setBold(true);
|
||||
p.setFont(f);
|
||||
p.drawText(QPoint(10,40), title());
|
||||
m_isSpecialType = false;
|
||||
|
||||
if (tabBar() != nullptr) { // Will be null for floating windows with several frames.
|
||||
const auto dws = dockWidgets();
|
||||
for (auto dw : dws) {
|
||||
// 3. If this TitleBar contains dock widget #1 or #2 it's special and will have custom painting
|
||||
if (dw->uniqueName() == QLatin1String("DockWidget #1") ||
|
||||
dw->uniqueName() == QLatin1String("DockWidget #2")) {
|
||||
m_isSpecialType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QWidget::update();
|
||||
}
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent *ev) override
|
||||
{
|
||||
KDDockWidgets::DockWidgetBase *currentDW = nullptr;
|
||||
if (auto tb = tabBar()) {
|
||||
if (auto tbWidget = qobject_cast<KDDockWidgets::TabBarWidget *>(tb->asWidget())) {
|
||||
// 4. Know the current tab, so it can influence the title bar
|
||||
currentDW = tbWidget->currentDockWidget();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_isSpecialType) {
|
||||
QPainter p(this);
|
||||
QPen pen(Qt::black);
|
||||
const bool isDw2 = currentDW && currentDW->uniqueName() == QLatin1String("DockWidget #2");
|
||||
const QColor focusedBackgroundColor = isDw2 ? Qt::cyan : Qt::yellow;
|
||||
|
||||
const QColor backgroundColor = focusedBackgroundColor.darker(115);
|
||||
QBrush brush(isFocused() ? focusedBackgroundColor : backgroundColor);
|
||||
pen.setWidth(4);
|
||||
p.setPen(pen);
|
||||
p.setBrush(brush);
|
||||
p.drawRect(rect().adjusted(4, 4, -4, -4));
|
||||
QFont f = qApp->font();
|
||||
f.setPixelSize(30);
|
||||
f.setBold(true);
|
||||
p.setFont(f);
|
||||
p.drawText(QPoint(10, 40), title());
|
||||
} else {
|
||||
KDDockWidgets::TitleBarWidget::paintEvent(ev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ static MyWidget *newMyWidget()
|
||||
MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
|
||||
bool maxSizeForDockWidget8, bool dockwidget5DoesntCloseBeforeRestore,
|
||||
bool dock0BlocksCloseEvent,
|
||||
const QString &affinityName, QWidget *parent)
|
||||
: MainWindow(uniqueName, options, parent)
|
||||
, m_dockWidget0IsNonClosable(dockWidget0IsNonClosable)
|
||||
@@ -54,6 +55,7 @@ MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowO
|
||||
, m_restoreIsRelative(restoreIsRelative)
|
||||
, m_maxSizeForDockWidget8(maxSizeForDockWidget8)
|
||||
, m_dockwidget5DoesntCloseBeforeRestore(dockwidget5DoesntCloseBeforeRestore)
|
||||
, m_dock0BlocksCloseEvent(dock0BlocksCloseEvent)
|
||||
{
|
||||
auto menubar = menuBar();
|
||||
auto fileMenu = new QMenu(QStringLiteral("File"), this);
|
||||
@@ -190,6 +192,9 @@ KDDockWidgets::DockWidgetBase *MyMainWindow::newDockWidget()
|
||||
myWidget->setMaximumSize(200, 200);
|
||||
}
|
||||
|
||||
if (count == 0 && m_dock0BlocksCloseEvent)
|
||||
myWidget->blockCloseEvent();
|
||||
|
||||
dock->setWidget(myWidget);
|
||||
|
||||
if (dock->options() & KDDockWidgets::DockWidget::Option_NotDockable) {
|
||||
|
||||
@@ -20,7 +20,7 @@ class MyMainWindow : public KDDockWidgets::MainWindow
|
||||
public:
|
||||
explicit MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
|
||||
bool maxSizeForDockWidget8, bool dockwidget5DoesntCloseBeforeRestore,
|
||||
bool maxSizeForDockWidget8, bool dockwidget5DoesntCloseBeforeRestore, bool dock0BlocksCloseEvent,
|
||||
const QString &affinityName = {}, // Usually not needed. Just here to show the feature.
|
||||
QWidget *parent = nullptr);
|
||||
~MyMainWindow() override;
|
||||
@@ -34,5 +34,6 @@ private:
|
||||
const bool m_restoreIsRelative;
|
||||
const bool m_maxSizeForDockWidget8;
|
||||
const bool m_dockwidget5DoesntCloseBeforeRestore;
|
||||
const bool m_dock0BlocksCloseEvent;
|
||||
KDDockWidgets::DockWidget::List m_dockwidgets;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QLineEdit>
|
||||
#include <QCloseEvent>
|
||||
|
||||
static QHash<QString, QImage> s_images; /// clazy:exclude=non-pod-global-static
|
||||
|
||||
@@ -70,6 +71,20 @@ void MyWidget::drawLogo(QPainter &p)
|
||||
p.drawImage(targetLogoRect, m_logo, m_logo.rect());
|
||||
}
|
||||
|
||||
void MyWidget::blockCloseEvent()
|
||||
{
|
||||
m_blocksCloseEvent = true;
|
||||
}
|
||||
|
||||
void MyWidget::closeEvent(QCloseEvent *ev)
|
||||
{
|
||||
if (m_blocksCloseEvent) {
|
||||
ev->ignore();
|
||||
} else {
|
||||
QWidget::closeEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
MyWidget1::MyWidget1(MyWidget::QWidget *parent)
|
||||
: MyWidget(QStringLiteral(":/assets/triangles.png"), QStringLiteral(":/assets/KDAB_bubble_white.png"), parent)
|
||||
{
|
||||
|
||||
@@ -26,10 +26,16 @@ class MyWidget : public QWidget
|
||||
public:
|
||||
explicit MyWidget(const QString &backgroundFile, const QString &logoFile, QWidget *parent = nullptr);
|
||||
~MyWidget();
|
||||
|
||||
// These two are just for demonstrating how to block the close event, if desired
|
||||
void blockCloseEvent();
|
||||
void closeEvent(QCloseEvent *) override;
|
||||
|
||||
protected:
|
||||
void drawLogo(QPainter &);
|
||||
QImage m_background;
|
||||
QImage m_logo;
|
||||
bool m_blocksCloseEvent = false;
|
||||
};
|
||||
|
||||
class MyWidget1 : public MyWidget
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "MyMainWindow.h"
|
||||
#include "MyFrameworkWidgetFactory.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <kddockwidgets/Config.h>
|
||||
|
||||
#include <QStyleFactory>
|
||||
@@ -119,6 +120,10 @@ int main(int argc, char **argv)
|
||||
QCoreApplication::translate("main", "DockWidget #5 won't be closed before a restore. Illustrates LayoutSaverOption::DontCloseBeforeRestore"));
|
||||
parser.addOption(dontCloseBeforeRestore);
|
||||
|
||||
QCommandLineOption blockCloseEvent("block-close-event",
|
||||
QCoreApplication::translate("main", "DockWidget #0 will block close events"));
|
||||
parser.addOption(blockCloseEvent);
|
||||
|
||||
QCommandLineOption showButtonsInTabBarIfTitleBarHidden("show-buttons-in-tabbar-if-titlebar-hidden",
|
||||
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);
|
||||
@@ -131,6 +136,10 @@ int main(int argc, char **argv)
|
||||
QCoreApplication::translate("main", "Allow switching tabs via context menu in tabs area"));
|
||||
parser.addOption(ctxtMenuOnTabs);
|
||||
|
||||
QCommandLineOption hideCertainDockingIndicators("hide-certain-docking-indicators",
|
||||
QCoreApplication::translate("main", "Illustrates usage of Config::setDropIndicatorAllowedFunc()"));
|
||||
parser.addOption(hideCertainDockingIndicators);
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
parser.addOption(centralFrame);
|
||||
|
||||
@@ -253,6 +262,24 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (parser.isSet(hideCertainDockingIndicators)) {
|
||||
// Here we exemplify adding a restriction to "Dock Widget 8"
|
||||
// Dock widget 8 will only be allowed to dock to the outter areasa
|
||||
auto func = [](KDDockWidgets::DropLocation location,
|
||||
const KDDockWidgets::DockWidgetBase::List &source,
|
||||
const KDDockWidgets::DockWidgetBase::List &target) {
|
||||
Q_UNUSED(target); // When dragging into a tab, 'target' would have the list of already tabbed dock widgets
|
||||
|
||||
const bool isDraggingDW8 = std::find_if(source.cbegin(), source.cend(), [] (KDDockWidgets::DockWidgetBase *dw) {
|
||||
return dw->uniqueName() == QLatin1String("DockWidget #8");
|
||||
}) != source.cend();
|
||||
|
||||
return (location & KDDockWidgets::DropLocation_Outter) || !isDraggingDW8;
|
||||
};
|
||||
|
||||
KDDockWidgets::Config::self().setDropIndicatorAllowedFunc(func);
|
||||
}
|
||||
|
||||
KDDockWidgets::Config::self().setFlags(flags);
|
||||
|
||||
const bool nonClosableDockWidget0 = parser.isSet(nonClosableDockWidget);
|
||||
@@ -261,6 +288,7 @@ int main(int argc, char **argv)
|
||||
const bool maxSizeForDockWidget8 = parser.isSet(maxSizeOption);
|
||||
const bool dontCloseDockWidget5BeforeRestore = parser.isSet(dontCloseBeforeRestore);
|
||||
const bool usesMainWindowsWithAffinity = parser.isSet(multipleMainWindows);
|
||||
const bool dock0BlocksCloseEvent = parser.isSet(blockCloseEvent);
|
||||
|
||||
#ifdef KDDOCKWIDGETS_SUPPORTS_NESTED_MAINWINDOWS
|
||||
const bool usesDockableMainWindows = parser.isSet(dockableMainWindows);
|
||||
@@ -270,7 +298,7 @@ int main(int argc, char **argv)
|
||||
|
||||
MyMainWindow mainWindow(QStringLiteral("MyMainWindow"), options, nonClosableDockWidget0,
|
||||
nonDockableDockWidget9, restoreIsRelative, maxSizeForDockWidget8,
|
||||
dontCloseDockWidget5BeforeRestore);
|
||||
dontCloseDockWidget5BeforeRestore, dock0BlocksCloseEvent);
|
||||
mainWindow.setWindowTitle("Main Window 1");
|
||||
mainWindow.resize(1200, 1200);
|
||||
mainWindow.show();
|
||||
@@ -289,7 +317,7 @@ int main(int argc, char **argv)
|
||||
auto mainWindow2 = new MyMainWindow(QStringLiteral("MyMainWindow-2"), options,
|
||||
nonClosableDockWidget0, nonDockableDockWidget9,
|
||||
restoreIsRelative, maxSizeForDockWidget8,
|
||||
dontCloseDockWidget5BeforeRestore, affinity);
|
||||
dontCloseDockWidget5BeforeRestore, dock0BlocksCloseEvent, affinity);
|
||||
if (affinity.isEmpty())
|
||||
mainWindow2->setWindowTitle("Main Window 2");
|
||||
else
|
||||
@@ -303,7 +331,7 @@ int main(int argc, char **argv)
|
||||
const QString affinity = QStringLiteral("Inner-DockWidgets-2");
|
||||
auto dockableMainWindow = new MyMainWindow(QStringLiteral("MyMainWindow-2"), options,
|
||||
false, false, restoreIsRelative, false,
|
||||
false, affinity);
|
||||
false, false, affinity);
|
||||
|
||||
dockableMainWindow->setAffinities({ affinity });
|
||||
|
||||
|
||||
40
examples/mdi_with_docking/CMakeLists.txt
Normal file
40
examples/mdi_with_docking/CMakeLists.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(kddockwidgets_mdi_with_docking_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)
|
||||
|
||||
# Just to reuse MyWidget.h
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../dockwidgets/)
|
||||
|
||||
add_executable(kddockwidgets_mdi_with_docking_example
|
||||
main.cpp
|
||||
../dockwidgets/MyWidget.cpp
|
||||
${RESOURCES_EXAMPLE_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(kddockwidgets_mdi_with_docking_example
|
||||
PRIVATE
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
|
||||
95
examples/mdi_with_docking/main.cpp
Normal file
95
examples/mdi_with_docking/main.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "MyWidget.h"
|
||||
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
#include <kddockwidgets/MainWindow.h>
|
||||
#include <kddockwidgets/MDIArea.h>
|
||||
|
||||
#include <QStyleFactory>
|
||||
#include <QApplication>
|
||||
#include <QCommandLineParser>
|
||||
|
||||
// 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("App supporting both docking and a MDI area"));
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("KDDockWidgets MDI mixed with normal docking");
|
||||
parser.addHelpOption();
|
||||
|
||||
QCommandLineOption nestedDocking("n", QCoreApplication::translate("main", "The MDI dock widgets will serve as drop areas, allowing for further nesting"));
|
||||
parser.addOption(nestedDocking);
|
||||
|
||||
parser.process(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_HasCentralWidget);
|
||||
mainWindow.setWindowTitle("Main Window");
|
||||
mainWindow.resize(1600, 1200);
|
||||
mainWindow.show();
|
||||
|
||||
// # 2. Create a dock widget, it needs a unique name
|
||||
auto dock1 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock1"));
|
||||
auto widget1 = new MyWidget1();
|
||||
dock1->setWidget(widget1);
|
||||
|
||||
auto dock2 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock2"));
|
||||
auto widget2 = new MyWidget2();
|
||||
dock2->setWidget(widget2);
|
||||
|
||||
// # 3. Dock them
|
||||
mainWindow.addDockWidget(dock1, KDDockWidgets::Location_OnLeft, nullptr, KDDockWidgets::InitialOption(QSize(300, 0)));
|
||||
mainWindow.addDockWidget(dock2, KDDockWidgets::Location_OnBottom, nullptr, KDDockWidgets::InitialOption(QSize(0, 300)));
|
||||
|
||||
KDDockWidgets::DockWidgetBase::Options options = {};
|
||||
if (parser.isSet(nestedDocking)) {
|
||||
options |= KDDockWidgets::DockWidgetBase::Option_MDINestable;
|
||||
}
|
||||
|
||||
// 4. Create our MDI widgets, which will go into the MDI area
|
||||
auto mdiWidget1 = new KDDockWidgets::DockWidget(QStringLiteral("MDI widget1"), options);
|
||||
mdiWidget1->setWidget(new MyWidget1());
|
||||
|
||||
auto mdiWidget2 = new KDDockWidgets::DockWidget(QStringLiteral("MDI widget2"), options);
|
||||
mdiWidget2->setWidget(new MyWidget2());
|
||||
|
||||
auto mdiWidget3 = new KDDockWidgets::DockWidget(QStringLiteral("MDI widget3"), options);
|
||||
auto widget3 = new MyWidget3();
|
||||
mdiWidget3->setWidget(widget3);
|
||||
|
||||
// Just for my personal testing: Overkill to add an option
|
||||
// widget3->blockCloseEvent();
|
||||
|
||||
auto mdiArea = new KDDockWidgets::MDIArea();
|
||||
mainWindow.setPersistentCentralWidget(mdiArea);
|
||||
|
||||
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
||||
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
||||
mdiArea->addDockWidget(mdiWidget3, QPoint(110, 110));
|
||||
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -24,6 +24,9 @@ endif()
|
||||
|
||||
set(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../dockwidgets/resources_example.qrc)
|
||||
|
||||
# Just to reuse MyWidget.h
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../dockwidgets/)
|
||||
|
||||
add_executable(kddockwidgets_minimal_mdi_example
|
||||
main.cpp
|
||||
../dockwidgets/MyWidget.cpp
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "MyWidget.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QLineEdit>
|
||||
|
||||
static QHash<QString, QImage> 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);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#ifndef EXAMPLEDOCKABLEWIDGET_H
|
||||
#define EXAMPLEDOCKABLEWIDGET_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
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
|
||||
@@ -53,6 +53,9 @@ int main(int argc, char **argv)
|
||||
auto widget3 = new MyWidget3();
|
||||
dock3->setWidget(widget3);
|
||||
|
||||
// Just for my personal testing: Overkill to add an option
|
||||
// widget3->blockCloseEvent();
|
||||
|
||||
// # 3. Dock them
|
||||
mainWindow.addDockWidget(dock1, QPoint(10, 10));
|
||||
mainWindow.addDockWidget(dock2, QPoint(50, 50));
|
||||
|
||||
@@ -35,6 +35,8 @@ set(DOCKSLIBS_SRCS
|
||||
MainWindowBase.h
|
||||
MainWindowMDI.cpp
|
||||
MainWindowMDI.h
|
||||
MDIArea.cpp
|
||||
MDIArea.h
|
||||
LayoutSaver.cpp
|
||||
LayoutSaver.h
|
||||
private/LayoutSaver_p.h
|
||||
@@ -126,6 +128,7 @@ set(DOCKS_INSTALLABLE_PRIVATE_INCLUDES
|
||||
private/WidgetResizeHandler_p.h
|
||||
private/DockRegistry_p.h
|
||||
private/TabWidget_p.h
|
||||
private/MDILayoutWidget_p.h
|
||||
)
|
||||
|
||||
set(DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES
|
||||
@@ -219,6 +222,7 @@ else()
|
||||
${DOCKS_INSTALLABLE_INCLUDES}
|
||||
MainWindow.h
|
||||
DockWidget.h
|
||||
MDIArea.h
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -295,7 +299,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR IS_CLANG_BUILD)
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${Qt_VERSION_MAJOR}::Widgets Qt${Qt_VERSION_MAJOR}::Quick Qt${Qt_VERSION_MAJOR}::QuickControls2)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${Qt_VERSION_MAJOR}::Widgets Qt${Qt_VERSION_MAJOR}::Quick Qt${Qt_VERSION_MAJOR}::QuickControls2 PRIVATE Qt${Qt_VERSION_MAJOR}::GuiPrivate)
|
||||
else()
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${Qt_VERSION_MAJOR}::Widgets PRIVATE Qt${Qt_VERSION_MAJOR}::WidgetsPrivate)
|
||||
endif()
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "Config.h"
|
||||
#include "private/multisplitter/MultiSplitterConfig.h"
|
||||
#include "private/multisplitter/Widget.h"
|
||||
#include "private/multisplitter/Item_p.h"
|
||||
#include "private/DockRegistry_p.h"
|
||||
#include "private/Utils_p.h"
|
||||
#include "private/DragController_p.h"
|
||||
@@ -54,6 +55,7 @@ public:
|
||||
DockWidgetFactoryFunc m_dockWidgetFactoryFunc = nullptr;
|
||||
MainWindowFactoryFunc m_mainWindowFactoryFunc = nullptr;
|
||||
TabbingAllowedFunc m_tabbingAllowedFunc = nullptr;
|
||||
DropIndicatorAllowedFunc m_dropIndicatorAllowedFunc = nullptr;
|
||||
FrameworkWidgetFactory *m_frameworkWidgetFactory = nullptr;
|
||||
Flags m_flags = Flag_Default;
|
||||
InternalFlags m_internalFlags = InternalFlag_None;
|
||||
@@ -180,6 +182,16 @@ TabbingAllowedFunc Config::tabbingAllowedFunc() const
|
||||
return d->m_tabbingAllowedFunc;
|
||||
}
|
||||
|
||||
void Config::setDropIndicatorAllowedFunc(DropIndicatorAllowedFunc func)
|
||||
{
|
||||
d->m_dropIndicatorAllowedFunc = func;
|
||||
}
|
||||
|
||||
DropIndicatorAllowedFunc Config::dropIndicatorAllowedFunc() const
|
||||
{
|
||||
return d->m_dropIndicatorAllowedFunc;
|
||||
}
|
||||
|
||||
void Config::setAbsoluteWidgetMinSize(QSize size)
|
||||
{
|
||||
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/false)) {
|
||||
|
||||
54
src/Config.h
54
src/Config.h
@@ -20,6 +20,7 @@
|
||||
#define KD_DOCKWIDGETS_CONFIG_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "KDDockWidgets.h"
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
@@ -37,6 +38,22 @@ class FrameworkWidgetFactory;
|
||||
typedef KDDockWidgets::DockWidgetBase *(*DockWidgetFactoryFunc)(const QString &name);
|
||||
typedef KDDockWidgets::MainWindowBase *(*MainWindowFactoryFunc)(const QString &name);
|
||||
|
||||
/// @brief Function to allow more granularity to disallow where widgets are dropped
|
||||
///
|
||||
/// By default, widgets can be dropped to the outter and inner left/right/top/bottom
|
||||
/// and center. The client app can however provide a lambda via setDropIndicatorAllowedFunc
|
||||
/// to block (by returning false) any specific locations they desire.
|
||||
///
|
||||
/// @param location The drop indicator location to allow or disallow
|
||||
/// @param source The dock widgets being dragged
|
||||
/// @param target The dock widgets within an existing docked tab group
|
||||
/// @return true if the docking is allowed.
|
||||
/// @sa setDropIndicatorAllowedFunc
|
||||
typedef bool (*DropIndicatorAllowedFunc)(DropLocation location,
|
||||
const QVector<DockWidgetBase *> &source,
|
||||
const QVector<DockWidgetBase *> &target);
|
||||
|
||||
/// @deprecated Use DropIndicatorAllowedFunc instead.
|
||||
/// @brief Function to allow the user more granularity to disallow dock widgets to tab together
|
||||
/// @param source The dock widgets being dragged
|
||||
/// @param target The dock widgets within an existing docked tab group
|
||||
@@ -203,6 +220,8 @@ public:
|
||||
bool dropIndicatorsInhibited() const;
|
||||
|
||||
/**
|
||||
* @deprecated Use setDropIndicatorAllowedFunc() instead, and catch the DropLocation_Center case.
|
||||
*
|
||||
* @brief Allows the user to intercept a docking attempt to center (tabbed) and disallow it.
|
||||
*
|
||||
* Whenever the user tries to tab two widgets together, the framework will call @p func. If
|
||||
@@ -219,8 +238,10 @@ public:
|
||||
* // disallows dockFoo to be tabbed with dockBar.
|
||||
* return !(source.contains(dockFoo) && target.contains(dockBar));
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* KDDockWidgets::Config::self()->setTabbingAllowedFunc(func);
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
void setTabbingAllowedFunc(TabbingAllowedFunc func);
|
||||
|
||||
@@ -229,6 +250,37 @@ public:
|
||||
///@sa setTabbingAllowedFunc().
|
||||
TabbingAllowedFunc tabbingAllowedFunc() const;
|
||||
|
||||
/**
|
||||
* @brief Allows the client app to disallow certain docking indicators.
|
||||
*
|
||||
* For example, let's assume the app doesn't want to show outter indicators for a certain
|
||||
* dock widget.
|
||||
*
|
||||
* @code
|
||||
* #include <kddockwidgets/Config.h>
|
||||
* (...)
|
||||
*
|
||||
* auto func = [] (KDDockWidgets::DropLocation loc,
|
||||
* const KDDockWidgets::DockWidgetBase::List &source,
|
||||
* const KDDockWidgets::DockWidgetBase::List &target)
|
||||
* {
|
||||
* // disallows dockFoo to be docked to outter areas
|
||||
* return !((loc & KDDockWidgets::DropLocation_Outter) && source.contains(dockFoo));
|
||||
* }
|
||||
*
|
||||
* KDDockWidgets::Config::self()->setDropIndicatorAllowedFunc(func);
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* Run "kddockwidgets_example --hide-certain-docking-indicators" to see this in action.
|
||||
*/
|
||||
void setDropIndicatorAllowedFunc(DropIndicatorAllowedFunc func);
|
||||
|
||||
///@brief Used internally by the framework. Returns the function which was passed to setDropIndicatorAllowedFunc()
|
||||
///By default it's nullptr.
|
||||
///@sa setDropIndicatorAllowedFunc().
|
||||
DropIndicatorAllowedFunc dropIndicatorAllowedFunc() const;
|
||||
|
||||
///@brief Sets the minimum size a dock widget can have.
|
||||
/// Widgets can still provide their own min-size and it will be respected, however it can never be
|
||||
/// smaller than this one.
|
||||
|
||||
@@ -180,7 +180,7 @@ bool DockWidgetBase::setFloating(bool floats)
|
||||
{
|
||||
const bool alreadyFloating = isFloating();
|
||||
|
||||
if ((floats && alreadyFloating) || (!floats && !alreadyFloating))
|
||||
if (floats == alreadyFloating)
|
||||
return true; // Nothing to do
|
||||
|
||||
if (!floats && (Config::self().internalFlags() & Config::InternalFlag_DontShowWhenUnfloatingHiddenWindow) && !isVisible()) {
|
||||
@@ -205,10 +205,10 @@ bool DockWidgetBase::setFloating(bool floats)
|
||||
|
||||
frame->detachTab(this);
|
||||
} else {
|
||||
d->frame()->titleBar()->makeWindow();
|
||||
titleBar()->makeWindow();
|
||||
}
|
||||
|
||||
auto lastGeo = d->lastPositions().lastFloatingGeometry();
|
||||
auto lastGeo = d->lastPosition()->lastFloatingGeometry();
|
||||
if (lastGeo.isValid()) {
|
||||
if (auto fw = floatingWindow())
|
||||
fw->setSuggestedGeometry(lastGeo, SuggestedGeometryHint_PreserveCenter);
|
||||
@@ -237,6 +237,17 @@ QString DockWidgetBase::uniqueName() const
|
||||
|
||||
QString DockWidgetBase::title() const
|
||||
{
|
||||
if (d->isMDIWrapper()) {
|
||||
// It's just a wrapper to help implementing Option_MDINestable. Return the title of the real dock widget we're hosting.
|
||||
auto dropAreaGuest = qobject_cast<DropArea*>(widget());
|
||||
Q_ASSERT(dropAreaGuest);
|
||||
if (dropAreaGuest->hasSingleFrame()) {
|
||||
return dropAreaGuest->frames().constFirst()->title();
|
||||
} else {
|
||||
return qApp->applicationName();
|
||||
}
|
||||
}
|
||||
|
||||
return d->title;
|
||||
}
|
||||
|
||||
@@ -370,7 +381,7 @@ QStringList DockWidgetBase::affinities() const
|
||||
|
||||
void DockWidgetBase::show()
|
||||
{
|
||||
if (isWindow() && (d->m_lastPositions.wasFloating() || !d->m_lastPositions.isValid())) {
|
||||
if (isWindow() && (d->m_lastPosition->wasFloating() || !d->m_lastPosition->isValid())) {
|
||||
// Create the FloatingWindow already, instead of waiting for the show event.
|
||||
// This reduces flickering on some platforms
|
||||
d->morphIntoFloatingWindow();
|
||||
@@ -465,7 +476,7 @@ bool DockWidgetBase::isInSideBar() const
|
||||
|
||||
bool DockWidgetBase::hasPreviousDockedLocation() const
|
||||
{
|
||||
return d->m_lastPositions.isValid();
|
||||
return d->m_lastPosition->isValid();
|
||||
}
|
||||
|
||||
QSize DockWidgetBase::lastOverlayedSize() const
|
||||
@@ -488,7 +499,7 @@ void DockWidgetBase::setFloatingGeometry(QRect geometry)
|
||||
if (isOpen() && isFloating()) {
|
||||
window()->setGeometry(geometry);
|
||||
} else {
|
||||
d->m_lastPositions.setLastFloatingGeometry(geometry);
|
||||
d->m_lastPosition->setLastFloatingGeometry(geometry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,7 +509,7 @@ FloatingWindow *DockWidgetBase::Private::morphIntoFloatingWindow()
|
||||
return fw; // Nothing to do
|
||||
|
||||
if (q->isWindow()) {
|
||||
QRect geo = m_lastPositions.lastFloatingGeometry();
|
||||
QRect geo = m_lastPosition->lastFloatingGeometry();
|
||||
if (geo.isNull()) {
|
||||
geo = q->geometry();
|
||||
|
||||
@@ -532,8 +543,75 @@ void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
|
||||
|
||||
MDILayoutWidget *DockWidgetBase::Private::mdiLayout() const
|
||||
{
|
||||
if (auto mw = mainWindow())
|
||||
return mw->mdiLayoutWidget();
|
||||
auto p = const_cast<QObject *>(q->parent());
|
||||
while (p) {
|
||||
if (qobject_cast<const QWindow*>(p)) {
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (qobject_cast<LayoutWidget*>(p)) {
|
||||
// We found a layout
|
||||
if (auto mdiLayout = qobject_cast<MDILayoutWidget*>(p)) {
|
||||
// And it's MDI
|
||||
return mdiLayout;
|
||||
} else if (auto dropArea = qobject_cast<DropArea*>(p)) {
|
||||
// It's a DropArea. But maybe it's a drop area that's just helping
|
||||
// making the MDI windows accept drops (Option_MDINestable)
|
||||
if (!dropArea->isMDIWrapper())
|
||||
return nullptr;
|
||||
|
||||
// It's a MDI wrapper, keep looking up.
|
||||
}
|
||||
}
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool DockWidgetBase::Private::isMDIWrapper() const
|
||||
{
|
||||
return mdiDropAreaWrapper() != nullptr;
|
||||
}
|
||||
|
||||
DropArea *DockWidgetBase::Private::mdiDropAreaWrapper() const
|
||||
{
|
||||
if (auto dropAreaGuest = qobject_cast<DropArea *>(q->widget())) {
|
||||
if (dropAreaGuest->isMDIWrapper())
|
||||
return dropAreaGuest;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DockWidgetBase *DockWidgetBase::Private::mdiDockWidgetWrapper() const
|
||||
{
|
||||
if (isMDIWrapper()) {
|
||||
// We are the wrapper
|
||||
return q;
|
||||
}
|
||||
|
||||
auto p = const_cast<QObject *>(q->parent());
|
||||
while (p) {
|
||||
if (qobject_cast<const QWindow*>(p)) {
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (qobject_cast<LayoutWidget*>(p)) {
|
||||
if (auto dropArea = qobject_cast<DropArea*>(p)) {
|
||||
if (dropArea->isMDIWrapper())
|
||||
return dropArea->mdiDockWidgetWrapper();
|
||||
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -603,7 +681,7 @@ void DockWidgetBase::Private::updateFloatAction()
|
||||
QScopedValueRollback<bool> recursionGuard(m_updatingFloatAction, true); // Guard against recursiveness
|
||||
|
||||
if (q->isFloating()) {
|
||||
floatAction->setEnabled(m_lastPositions.isValid());
|
||||
floatAction->setEnabled(m_lastPosition->isValid());
|
||||
floatAction->setChecked(true);
|
||||
floatAction->setToolTip(tr("Dock"));
|
||||
} else {
|
||||
@@ -646,7 +724,7 @@ void DockWidgetBase::Private::close()
|
||||
&& q->isVisible()) { // only user-closing is interesting to save the geometry
|
||||
// We check for isVisible so we don't save geometry if you call close() on an already closed
|
||||
// dock widget
|
||||
m_lastPositions.setLastFloatingGeometry(q->window()->geometry());
|
||||
m_lastPosition->setLastFloatingGeometry(q->window()->geometry());
|
||||
}
|
||||
|
||||
saveTabIndex();
|
||||
@@ -669,14 +747,14 @@ void DockWidgetBase::Private::close()
|
||||
|
||||
bool DockWidgetBase::Private::restoreToPreviousPosition()
|
||||
{
|
||||
if (!m_lastPositions.isValid())
|
||||
if (!m_lastPosition->isValid())
|
||||
return false;
|
||||
|
||||
Layouting::Item *item = m_lastPositions.lastItem();
|
||||
Layouting::Item *item = m_lastPosition->lastItem();
|
||||
|
||||
LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
|
||||
Q_ASSERT(layout);
|
||||
layout->restorePlaceholder(q, item, m_lastPositions.lastTabIndex());
|
||||
layout->restorePlaceholder(q, item, m_lastPosition->lastTabIndex());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -684,14 +762,14 @@ void DockWidgetBase::Private::maybeRestoreToPreviousPosition()
|
||||
{
|
||||
// This is called when we get a QEvent::Show. Let's see if we have to restore it to a previous position.
|
||||
|
||||
if (!m_lastPositions.isValid())
|
||||
if (!m_lastPosition->isValid())
|
||||
return;
|
||||
|
||||
Layouting::Item *layoutItem = m_lastPositions.lastItem();
|
||||
Layouting::Item *layoutItem = m_lastPosition->lastItem();
|
||||
if (!layoutItem)
|
||||
return; // nothing to do, no last position
|
||||
|
||||
if (m_lastPositions.wasFloating())
|
||||
if (m_lastPosition->wasFloating())
|
||||
return; // Nothing to do, it was floating before, now it'll just get visible
|
||||
|
||||
Frame *frame = this->frame();
|
||||
@@ -721,7 +799,7 @@ int DockWidgetBase::Private::currentTabIndex() const
|
||||
|
||||
void DockWidgetBase::Private::saveTabIndex()
|
||||
{
|
||||
m_lastPositions.saveTabIndex(currentTabIndex(), q->isFloating());
|
||||
m_lastPosition->saveTabIndex(currentTabIndex(), q->isFloating());
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::show()
|
||||
@@ -826,14 +904,26 @@ int DockWidgetBase::userType() const
|
||||
|
||||
void DockWidgetBase::setMDIPosition(QPoint pos)
|
||||
{
|
||||
if (MDILayoutWidget *layout = d->mdiLayout())
|
||||
layout->moveDockWidget(this, pos);
|
||||
if (MDILayoutWidget *layout = d->mdiLayout()) {
|
||||
if (auto wrapperDW = d->mdiDockWidgetWrapper()) {
|
||||
// Case of using Option_MDINestable. We need to layout the actual top level DW
|
||||
layout->moveDockWidget(wrapperDW, pos);
|
||||
} else {
|
||||
layout->moveDockWidget(this, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::setMDISize(QSize size)
|
||||
{
|
||||
if (MDILayoutWidget *layout = d->mdiLayout())
|
||||
layout->resizeDockWidget(this, size);
|
||||
if (MDILayoutWidget *layout = d->mdiLayout()) {
|
||||
if (auto wrapperDW = d->mdiDockWidgetWrapper()) {
|
||||
// Case of using Option_MDINestable. We need to layout the actual top level DW
|
||||
layout->resizeDockWidget(wrapperDW, size);
|
||||
} else {
|
||||
layout->resizeDockWidget(this, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::setMDIZ(int z)
|
||||
@@ -917,12 +1007,12 @@ DockWidgetBase::Private::Private(const QString &dockName, DockWidgetBase::Option
|
||||
void DockWidgetBase::Private::addPlaceholderItem(Layouting::Item *item)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
m_lastPositions.addPosition(item);
|
||||
m_lastPosition->addPlaceholderItem(item);
|
||||
}
|
||||
|
||||
LastPositions &DockWidgetBase::Private::lastPositions()
|
||||
Position::Ptr &DockWidgetBase::Private::lastPosition()
|
||||
{
|
||||
return m_lastPositions;
|
||||
return m_lastPosition;
|
||||
}
|
||||
|
||||
Frame *DockWidgetBase::Private::frame() const
|
||||
@@ -940,6 +1030,6 @@ void DockWidgetBase::Private::saveLastFloatingGeometry()
|
||||
{
|
||||
if (q->isFloating() && q->isVisible()) {
|
||||
// It's getting docked, save last floating position
|
||||
lastPositions().setLastFloatingGeometry(q->window()->geometry());
|
||||
lastPosition()->setLastFloatingGeometry(q->window()->geometry());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,10 @@ public:
|
||||
Option_None = 0, ///< No option, the default
|
||||
Option_NotClosable = 1, ///< The DockWidget can't be closed on the [x], only programmatically
|
||||
Option_NotDockable = 2, ///< The DockWidget can't be docked, it's always floating
|
||||
Option_DeleteOnClose = 4 ///< Deletes the DockWidget when closed
|
||||
Option_DeleteOnClose = 4, ///< Deletes the DockWidget when closed
|
||||
Option_MDINestable = 8 ///< EXPERIMENTAL. When this dock widget is being shown in a MDI area it will also allow other dock widgets to be dropped to its sides and tabbed
|
||||
/// Usually Each MDI "window" corresponds to one DockWidget, with this option each "window" will have a layout with 1 or more dock widgets
|
||||
/// Run "kddockwidgets_mdi_with_docking_example -n" to see it in action
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
Q_ENUM(Options);
|
||||
@@ -529,6 +532,7 @@ private:
|
||||
friend class MultiSplitter;
|
||||
friend class LayoutWidget;
|
||||
friend class MDILayoutWidget;
|
||||
friend class FloatingWindow;
|
||||
friend class Frame;
|
||||
friend class DropArea;
|
||||
friend class ::TestDocks;
|
||||
|
||||
@@ -75,9 +75,9 @@ TabBar *DefaultWidgetFactory::createTabBar(TabWidget *parent) const
|
||||
return new TabBarWidget(parent);
|
||||
}
|
||||
|
||||
TabWidget *DefaultWidgetFactory::createTabWidget(Frame *parent) const
|
||||
TabWidget *DefaultWidgetFactory::createTabWidget(Frame *parent, TabWidgetOptions options) const
|
||||
{
|
||||
return new TabWidgetWidget(parent);
|
||||
return new TabWidgetWidget(parent, options);
|
||||
}
|
||||
|
||||
Layouting::Separator *DefaultWidgetFactory::createSeparator(Layouting::Widget *parent) const
|
||||
@@ -189,7 +189,7 @@ TabBar *DefaultWidgetFactory::createTabBar(TabWidget *parent) const
|
||||
return new TabBarQuick(parent);
|
||||
}
|
||||
|
||||
TabWidget *DefaultWidgetFactory::createTabWidget(Frame *parent) const
|
||||
TabWidget *DefaultWidgetFactory::createTabWidget(Frame *parent, TabWidgetOptions) const
|
||||
{
|
||||
return new TabWidgetQuick(parent);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
///@brief Called internally by the framework to create a TabWidget
|
||||
/// Override to provide your own TabWidget sub-class.
|
||||
///@param parent Just forward to TabWidget's constructor.
|
||||
virtual TabWidget *createTabWidget(Frame *parent) const = 0;
|
||||
virtual TabWidget *createTabWidget(Frame *parent, TabWidgetOptions options = TabWidgetOption_None) const = 0;
|
||||
|
||||
///@brief Called internally by the framework to create a TabBar
|
||||
/// Override to provide your own TabBar sub-class.
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
Frame *createFrame(QWidgetOrQuick *parent, FrameOptions) const override;
|
||||
TitleBar *createTitleBar(Frame *) const override;
|
||||
TitleBar *createTitleBar(FloatingWindow *) const override;
|
||||
TabWidget *createTabWidget(Frame *parent) const override;
|
||||
TabWidget *createTabWidget(Frame *parent, TabWidgetOptions = TabWidgetOption_None) const override;
|
||||
TabBar *createTabBar(TabWidget *parent) const override;
|
||||
Layouting::Separator *createSeparator(Layouting::Widget *parent = nullptr) const override;
|
||||
FloatingWindow *createFloatingWindow(MainWindowBase *parent = nullptr) const override;
|
||||
|
||||
@@ -57,7 +57,7 @@ enum MainWindowOption
|
||||
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_HasCentralWidget = 4 | MainWindowOption_HasCentralFrame, ///> Similar to MainWindowOption_HasCentralFrame but
|
||||
///> you'll have a central widget which can't be detached (Similar to regular QMainWindow).
|
||||
///> you'll have a central widget which can't be detached (Similar to regular QMainWindow). @sa MainWindowBase::setPersistentCentralWidget()
|
||||
};
|
||||
Q_DECLARE_FLAGS(MainWindowOptions, MainWindowOption)
|
||||
Q_ENUM_NS(MainWindowOptions)
|
||||
@@ -229,6 +229,24 @@ enum class TitleBarButtonType
|
||||
};
|
||||
Q_ENUM_NS(TitleBarButtonType)
|
||||
|
||||
///@brief Enum describing the different drop indicator types
|
||||
enum DropLocation
|
||||
{
|
||||
DropLocation_None = 0,
|
||||
DropLocation_Left = 1,
|
||||
DropLocation_Top = 2,
|
||||
DropLocation_Right = 4,
|
||||
DropLocation_Bottom = 8,
|
||||
DropLocation_Center = 16,
|
||||
DropLocation_OutterLeft = 32,
|
||||
DropLocation_OutterTop = 64,
|
||||
DropLocation_OutterRight = 128,
|
||||
DropLocation_OutterBottom = 256,
|
||||
DropLocation_Inner = DropLocation_Left | DropLocation_Right | DropLocation_Top | DropLocation_Bottom,
|
||||
DropLocation_Outter = DropLocation_OutterLeft | DropLocation_OutterRight | DropLocation_OutterTop | DropLocation_OutterBottom
|
||||
};
|
||||
Q_ENUM_NS(DropLocation)
|
||||
|
||||
///@internal
|
||||
inline Qt5Qt6Compat::qhashtype qHash(SideBarLocation loc, Qt5Qt6Compat::qhashtype seed)
|
||||
{
|
||||
@@ -254,6 +272,7 @@ enum CursorPosition
|
||||
Q_DECLARE_FLAGS(CursorPositions, CursorPosition)
|
||||
Q_ENUM_NS(CursorPosition)
|
||||
|
||||
|
||||
///@internal
|
||||
enum FrameOption
|
||||
{
|
||||
@@ -266,6 +285,15 @@ enum FrameOption
|
||||
Q_DECLARE_FLAGS(FrameOptions, FrameOption)
|
||||
Q_ENUM_NS(FrameOptions)
|
||||
|
||||
///@internal
|
||||
enum TabWidgetOption
|
||||
{
|
||||
TabWidgetOption_None = 0,
|
||||
TabWidgetOption_DocumentMode = 1 ///> Enables QTabWidget::documentMode()
|
||||
};
|
||||
Q_DECLARE_FLAGS(TabWidgetOptions, TabWidgetOption)
|
||||
Q_ENUM_NS(TabWidgetOptions)
|
||||
|
||||
///@internal
|
||||
inline QString locationStr(Location loc)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ if (@KDDockWidgets_QTQUICK@)
|
||||
find_dependency(Qt@Qt_VERSION_MAJOR@Quick REQUIRED)
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT @KDDockWidgets_QT6@)
|
||||
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT @KDDockWidgets_QT6@ AND @KDDockWidgets_X11EXTRAS@)
|
||||
find_dependency(Qt5X11Extras REQUIRED)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "DockWidgetBase.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
|
||||
#include "private/multisplitter/Item_p.h"
|
||||
#include "private/LayoutSaver_p.h"
|
||||
#include "private/DockRegistry_p.h"
|
||||
#include "private/DockWidgetBase_p.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "private/LayoutWidget_p.h"
|
||||
#include "private/Logging_p.h"
|
||||
#include "private/Position_p.h"
|
||||
#include "private/Utils_p.h"
|
||||
|
||||
#include <qmath.h>
|
||||
#include <QDebug>
|
||||
@@ -176,7 +178,7 @@ QByteArray LayoutSaver::serializeLayout() const
|
||||
for (DockWidgetBase *dockWidget : dockWidgets) {
|
||||
if (d->matchesAffinity(dockWidget->affinities())) {
|
||||
auto dw = dockWidget->d->serialize();
|
||||
dw->lastPosition = dockWidget->d->lastPositions().serialize();
|
||||
dw->lastPosition = dockWidget->d->lastPosition()->serialize();
|
||||
layout.allDockWidgets.push_back(dw);
|
||||
}
|
||||
}
|
||||
@@ -289,7 +291,7 @@ bool LayoutSaver::restoreLayout(const QByteArray &data)
|
||||
|
||||
if (DockWidgetBase *dockWidget =
|
||||
d->m_dockRegistry->dockByName(dw->uniqueName, DockRegistry::DockByNameFlag::ConsultRemapping)) {
|
||||
dockWidget->d->lastPositions().deserialize(dw->lastPosition);
|
||||
dockWidget->d->lastPosition()->deserialize(dw->lastPosition);
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Couldn't find dock widget" << dw->uniqueName;
|
||||
}
|
||||
@@ -339,13 +341,19 @@ void LayoutSaver::Private::deserializeWindowGeometry(const T &saved, QWidgetOrQu
|
||||
// Not simply calling QWidget::setGeometry() here.
|
||||
// For QtQuick we need to modify the QWindow's geometry.
|
||||
|
||||
auto windowGeometry = saved.geometry;
|
||||
::FloatingWindow::ensureRectIsOnScreen(windowGeometry);
|
||||
QRect geometry = saved.geometry;
|
||||
if (!isNormalWindowState(saved.windowState)) {
|
||||
// The window will be maximized. We first set its geometry to normal
|
||||
// Later it's maximized and will remember this value
|
||||
geometry = saved.normalGeometry;
|
||||
}
|
||||
|
||||
::FloatingWindow::ensureRectIsOnScreen(geometry);
|
||||
|
||||
if (topLevel->isWindow()) {
|
||||
topLevel->setGeometry(windowGeometry);
|
||||
topLevel->setGeometry(geometry);
|
||||
} else {
|
||||
KDDockWidgets::Private::setTopLevelGeometry(windowGeometry, topLevel);
|
||||
KDDockWidgets::Private::setTopLevelGeometry(geometry, topLevel);
|
||||
}
|
||||
|
||||
topLevel->setVisible(saved.isVisible);
|
||||
@@ -851,6 +859,7 @@ QVariantMap LayoutSaver::MainWindow::toVariantMap() const
|
||||
map.insert(QStringLiteral("multiSplitterLayout"), multiSplitterLayout.toVariantMap());
|
||||
map.insert(QStringLiteral("uniqueName"), uniqueName);
|
||||
map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry));
|
||||
map.insert(QStringLiteral("normalGeometry"), Layouting::rectToMap(normalGeometry));
|
||||
map.insert(QStringLiteral("screenIndex"), screenIndex);
|
||||
map.insert(QStringLiteral("screenSize"), Layouting::sizeToMap(screenSize));
|
||||
map.insert(QStringLiteral("isVisible"), isVisible);
|
||||
@@ -872,6 +881,7 @@ void LayoutSaver::MainWindow::fromVariantMap(const QVariantMap &map)
|
||||
multiSplitterLayout.fromVariantMap(map.value(QStringLiteral("multiSplitterLayout")).toMap());
|
||||
uniqueName = map.value(QStringLiteral("uniqueName")).toString();
|
||||
geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap());
|
||||
normalGeometry = Layouting::mapToRect(map.value(QStringLiteral("normalGeometry")).toMap());
|
||||
screenIndex = map.value(QStringLiteral("screenIndex")).toInt();
|
||||
screenSize = Layouting::mapToSize(map.value(QStringLiteral("screenSize")).toMap());
|
||||
isVisible = map.value(QStringLiteral("isVisible")).toBool();
|
||||
@@ -1016,6 +1026,23 @@ void LayoutSaver::Placeholder::fromVariantMap(const QVariantMap &map)
|
||||
mainWindowUniqueName = map.value(QStringLiteral("mainWindowUniqueName")).toString();
|
||||
}
|
||||
|
||||
static QScreen *screenForMainWindow(MainWindowBase *mw)
|
||||
{
|
||||
// Workaround for 5.12 which doesn't have QWidget::screen().
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
return mw->screen();
|
||||
#endif
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
if (QWindow *window = mw->window()->windowHandle())
|
||||
return window->screen();
|
||||
return nullptr;
|
||||
#else
|
||||
return mw->screen();
|
||||
#endif
|
||||
}
|
||||
|
||||
LayoutSaver::ScalingInfo::ScalingInfo(const QString &mainWindowId, QRect savedMainWindowGeo, int screenIndex)
|
||||
{
|
||||
auto mainWindow = DockRegistry::self()->mainWindowByName(mainWindowId);
|
||||
@@ -1034,7 +1061,7 @@ LayoutSaver::ScalingInfo::ScalingInfo(const QString &mainWindowId, QRect savedMa
|
||||
return;
|
||||
}
|
||||
|
||||
const int currentScreenIndex = qApp->screens().indexOf(mainWindow->screen());
|
||||
const int currentScreenIndex = qApp->screens().indexOf(screenForMainWindow(mainWindow));
|
||||
|
||||
this->mainWindowName = mainWindowId;
|
||||
this->savedMainWindowGeometry = savedMainWindowGeo;
|
||||
|
||||
103
src/MDIArea.cpp
Normal file
103
src/MDIArea.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "MDIArea.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "private/MDILayoutWidget_p.h"
|
||||
#include "private/DropAreaWithCentralFrame_p.h"
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
# include "DockWidget.h"
|
||||
# include <QVBoxLayout>
|
||||
#else
|
||||
# include "DockWidgetQuick.h"
|
||||
#endif
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QCloseEvent>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
class MDIArea::Private
|
||||
{
|
||||
public:
|
||||
Private(QWidgetOrQuick *parent)
|
||||
: layoutWidget(new MDILayoutWidget(parent))
|
||||
{
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
delete layoutWidget;
|
||||
}
|
||||
|
||||
MDILayoutWidget *const layoutWidget;
|
||||
};
|
||||
|
||||
MDIArea::MDIArea(QWidgetOrQuick *parent)
|
||||
: QWidgetAdapter(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
auto vlay = new QVBoxLayout(this);
|
||||
vlay->setContentsMargins({});
|
||||
vlay->addWidget(d->layoutWidget);
|
||||
#else
|
||||
QWidgetAdapter::makeItemFillParent(d->layoutWidget);
|
||||
#endif
|
||||
}
|
||||
|
||||
MDIArea::~MDIArea()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void MDIArea::addDockWidget(DockWidgetBase *dw, QPoint localPt, InitialOption addingOption)
|
||||
{
|
||||
if (dw->options() & DockWidgetBase::Option_MDINestable) {
|
||||
// We' wrap it with a drop area, so we can drag other dock widgets over this one and dock
|
||||
auto wrapperDW = new DockWidgetType(QStringLiteral("%1-mdiWrapper").arg(dw->uniqueName()));
|
||||
auto dropAreaWrapper = new DropArea(wrapperDW, /*isMDIWrapper= */ true);
|
||||
dropAreaWrapper->addDockWidget(dw, Location_OnBottom, nullptr);
|
||||
wrapperDW->setWidget(dropAreaWrapper);
|
||||
|
||||
dw = wrapperDW;
|
||||
}
|
||||
|
||||
d->layoutWidget->addDockWidget(dw, localPt, addingOption);
|
||||
}
|
||||
|
||||
void MDIArea::moveDockWidget(DockWidgetBase *dw, QPoint pos)
|
||||
{
|
||||
d->layoutWidget->moveDockWidget(dw, pos);
|
||||
}
|
||||
|
||||
void MDIArea::resizeDockWidget(DockWidgetBase *dw, QSize size)
|
||||
{
|
||||
d->layoutWidget->resizeDockWidget(dw, size);
|
||||
}
|
||||
|
||||
QList<Frame *> MDIArea::frames() const
|
||||
{
|
||||
return d->layoutWidget->frames();
|
||||
}
|
||||
|
||||
void MDIArea::onCloseEvent(QCloseEvent *e)
|
||||
{
|
||||
e->accept(); // Accepted by default (will close unless ignored)
|
||||
|
||||
const Frame::List frames = this->frames();
|
||||
for (Frame *frame : frames) {
|
||||
qApp->sendEvent(frame, e);
|
||||
if (!e->isAccepted())
|
||||
break; // Stop when the first frame prevents closing
|
||||
}
|
||||
}
|
||||
67
src/MDIArea.h
Normal file
67
src/MDIArea.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#ifndef KDDOCKWIDGETS_MDI_AREA_H
|
||||
#define KDDOCKWIDGETS_MDI_AREA_H
|
||||
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "KDDockWidgets.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class MDILayoutWidget;
|
||||
class DockWidgetBase;
|
||||
class Frame;
|
||||
|
||||
/**
|
||||
* @brief MDIArea allows to host dock widget in MDI mode.
|
||||
* This is an alternative to using a full blown MainWindowMDI.
|
||||
* The use case is when you already have a MainWindow (doing normal docking) and you
|
||||
* want to add an area where you want to use MDI dock widgets. Instead of docking a MainWindowMDI,
|
||||
* you'd just use an MDIArea, and avoid having nested main windows.
|
||||
*
|
||||
* See examples/mdi_with_docking/.
|
||||
*/
|
||||
class DOCKS_EXPORT MDIArea : public QWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MDIArea(QWidgetOrQuick *parent = nullptr);
|
||||
~MDIArea();
|
||||
|
||||
/// @brief docks the dock widgets into this MDI area, at the specified position
|
||||
void addDockWidget(DockWidgetBase *dw, QPoint localPt, InitialOption addingOption = {});
|
||||
|
||||
/// @brief Moves a dock widget @p dw to point @p pos
|
||||
void moveDockWidget(DockWidgetBase *dw, QPoint pos);
|
||||
|
||||
/// @brief Sets the size of dock widget @p dw to @p size
|
||||
void resizeDockWidget(DockWidgetBase *dw, QSize size);
|
||||
|
||||
/// @brief Returns the list of frames in this MDI Area
|
||||
/// Each Frame object represents a 'window' emebedded in the MDI Area
|
||||
QList<Frame *> frames() const;
|
||||
|
||||
/// @brief Forwards the close event to the MDI dock widgets, aborts closing if at least one
|
||||
/// dock widget doesn't allow it
|
||||
void onCloseEvent(QCloseEvent *) override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *const d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -72,7 +72,8 @@ public:
|
||||
|
||||
void updateMargins()
|
||||
{
|
||||
m_layout->setContentsMargins(q->centerWidgetMargins());
|
||||
const qreal factor = logicalDpiFactor(q);
|
||||
m_layout->setContentsMargins(m_centerWidgetMargins * factor);
|
||||
}
|
||||
|
||||
MainWindow *const q;
|
||||
@@ -80,6 +81,7 @@ public:
|
||||
QHash<SideBarLocation, SideBar *> m_sideBars;
|
||||
MyCentralWidget *const m_centralWidget;
|
||||
QHBoxLayout *const m_layout;
|
||||
QMargins m_centerWidgetMargins = { 1, 5, 1, 1 };
|
||||
};
|
||||
|
||||
MyCentralWidget::~MyCentralWidget()
|
||||
@@ -139,11 +141,23 @@ void MainWindow::resizeEvent(QResizeEvent *ev)
|
||||
|
||||
QMargins MainWindow::centerWidgetMargins() const
|
||||
{
|
||||
const QMargins margins = { 1, 5, 1, 1 };
|
||||
return margins * logicalDpiFactor(this);
|
||||
return d->m_centerWidgetMargins;
|
||||
}
|
||||
|
||||
void MainWindow::setCenterWidgetMargins(const QMargins &margins)
|
||||
{
|
||||
if (d->m_centerWidgetMargins == margins)
|
||||
return;
|
||||
d->m_centerWidgetMargins = margins;
|
||||
d->updateMargins();
|
||||
}
|
||||
|
||||
QRect MainWindow::centralAreaGeometry() const
|
||||
{
|
||||
return centralWidget()->geometry();
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *ev)
|
||||
{
|
||||
onCloseEvent(ev);
|
||||
}
|
||||
|
||||
@@ -50,9 +50,15 @@ public:
|
||||
///@brief returns the sidebar for the specified location
|
||||
SideBar *sideBar(SideBarLocation) const override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
//@brief returns the margins for the contents widget
|
||||
QMargins centerWidgetMargins() const override;
|
||||
|
||||
//@brief sets the margins for the contents widgets
|
||||
void setCenterWidgetMargins(const QMargins &margins);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *) override;
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
QRect centralAreaGeometry() const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "private/DropAreaWithCentralFrame_p.h"
|
||||
#include "private/LayoutSaver_p.h"
|
||||
#include "private/DockWidgetBase_p.h"
|
||||
#include "private/multisplitter/Item_p.h"
|
||||
|
||||
// Or we can have a createDockWidget() in the factory
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
@@ -38,6 +39,8 @@
|
||||
# include "DockWidget.h"
|
||||
#endif
|
||||
|
||||
#include <QCloseEvent>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
static LayoutWidget *createLayoutWidget(MainWindowBase *mainWindow, MainWindowOptions options)
|
||||
@@ -547,7 +550,7 @@ void MainWindowBase::overlayOnSideBar(DockWidgetBase *dw)
|
||||
auto frame = Config::self().frameworkWidgetFactory()->createFrame(this, FrameOption_IsOverlayed);
|
||||
d->m_overlayedDockWidget = dw;
|
||||
frame->addWidget(dw);
|
||||
d->updateOverlayGeometry(dw->d->lastPositions().lastOverlayedGeometry(sb->location()).size());
|
||||
d->updateOverlayGeometry(dw->d->lastPosition()->lastOverlayedGeometry(sb->location()).size());
|
||||
|
||||
frame->setAllowedResizeSides(d->allowedResizeSides(sb->location()));
|
||||
frame->QWidgetAdapter::show();
|
||||
@@ -576,7 +579,7 @@ void MainWindowBase::clearSideBarOverlay(bool deleteFrame)
|
||||
}
|
||||
|
||||
const SideBarLocation loc = d->m_overlayedDockWidget->sideBarLocation();
|
||||
d->m_overlayedDockWidget->d->lastPositions().setLastOverlayedGeometry(
|
||||
d->m_overlayedDockWidget->d->lastPosition()->setLastOverlayedGeometry(
|
||||
loc, frame->QWidgetAdapter::geometry());
|
||||
|
||||
frame->unoverlay();
|
||||
@@ -739,6 +742,7 @@ LayoutSaver::MainWindow MainWindowBase::serialize() const
|
||||
|
||||
m.options = options();
|
||||
m.geometry = windowGeometry();
|
||||
m.normalGeometry = normalGeometry();
|
||||
m.isVisible = isVisible();
|
||||
m.uniqueName = uniqueName();
|
||||
m.screenIndex = screenNumberForWidget(this);
|
||||
@@ -789,3 +793,8 @@ QWidgetOrQuick *MainWindowBase::persistentCentralWidget() const
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MainWindowBase::onCloseEvent(QCloseEvent *e)
|
||||
{
|
||||
d->m_layoutWidget->onCloseEvent(e);
|
||||
}
|
||||
|
||||
@@ -223,6 +223,7 @@ public:
|
||||
QRect windowGeometry() const;
|
||||
|
||||
protected:
|
||||
void onCloseEvent(QCloseEvent *);
|
||||
void setUniqueName(const QString &uniqueName);
|
||||
void onResized(QResizeEvent *); // Because QtQuick doesn't have resizeEvent()
|
||||
virtual QMargins centerWidgetMargins() const = 0;
|
||||
|
||||
12
src/fwd_headers/kddockwidgets/MDIArea.h
Normal file
12
src/fwd_headers/kddockwidgets/MDIArea.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../../MDIArea.h"
|
||||
12
src/fwd_headers/kddockwidgets/private/MDILayoutWidget_p.h
Normal file
12
src/fwd_headers/kddockwidgets/private/MDILayoutWidget_p.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../../../private/MDILayoutWidget_p.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Utils_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QDebug>
|
||||
@@ -283,8 +284,9 @@ LayoutWidget *DockRegistry::layoutForItem(const Layouting::Item *item) const
|
||||
|
||||
bool DockRegistry::itemIsInMainWindow(const Layouting::Item *item) const
|
||||
{
|
||||
if (auto layout = layoutForItem(item))
|
||||
return layout->isInMainWindow();
|
||||
if (LayoutWidget *layout = layoutForItem(item)) {
|
||||
return layout->isInMainWindow(/*honoursNesting=*/ true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -675,7 +677,7 @@ void DockRegistry::clear(const DockWidgetBase::List &dockWidgets,
|
||||
for (auto dw : qAsConst(dockWidgets)) {
|
||||
if (affinities.isEmpty() || affinitiesMatch(affinities, dw->affinities())) {
|
||||
dw->forceClose();
|
||||
dw->d->lastPositions().removePlaceholders();
|
||||
dw->d->lastPosition()->removePlaceholders();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,7 +713,7 @@ bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
// When clicking on a MDI Frame we raise the window
|
||||
if (Frame *f = parentFrame(watched)) {
|
||||
if (Frame *f = firstParentOfType<Frame>(watched)) {
|
||||
if (f->isMDI())
|
||||
f->raise();
|
||||
}
|
||||
|
||||
@@ -191,13 +191,13 @@ public:
|
||||
*/
|
||||
MainWindowBase::List mainWindowsWithAffinity(const QStringList &affinities) const;
|
||||
|
||||
// TODO: docs
|
||||
/// @brief Returns the LayoutWidget where the specified item is in
|
||||
LayoutWidget *layoutForItem(const Layouting::Item *) const;
|
||||
|
||||
// TODO: docs
|
||||
/// @brief Returns whether the item is in a main window.
|
||||
/// Nesting is honoured. (MDIArea inside DropArea inside MainWindow, for example)
|
||||
bool itemIsInMainWindow(const Layouting::Item *) const;
|
||||
|
||||
|
||||
bool affinitiesMatch(const QStringList &affinities1, const QStringList &affinities2) const;
|
||||
|
||||
/// @brief Returns a list of all known main window unique names
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
void addPlaceholderItem(Layouting::Item *);
|
||||
|
||||
///@brief returns the last position, just for tests.
|
||||
LastPositions &lastPositions();
|
||||
Position::Ptr &lastPosition();
|
||||
|
||||
void forceClose();
|
||||
QPoint defaultCenterPosForFloating();
|
||||
@@ -136,6 +136,17 @@ public:
|
||||
/// @brief Returns the mdi layout this dock widget is in, if any.
|
||||
MDILayoutWidget *mdiLayout() const;
|
||||
|
||||
/// @brief Returns if this is an helper DockWidget created automatically to host a drop area inside MDI
|
||||
/// This is only used by the DockWidget::Option_MDINestable feature
|
||||
bool isMDIWrapper() const;
|
||||
|
||||
/// @brief If this dock widget is an MDI wrapper (isMDIWrapper()), then returns the wrapper drop area
|
||||
DropArea *mdiDropAreaWrapper() const;
|
||||
|
||||
/// @brief If this dock widget is inside a drop area nested in MDI then returns the wrapper dock widget
|
||||
/// This goes up the hierarchy, while mdiDropAreaWrapper goes down.
|
||||
DockWidgetBase *mdiDockWidgetWrapper() const;
|
||||
|
||||
const QString name;
|
||||
QStringList affinities;
|
||||
QString title;
|
||||
@@ -147,7 +158,7 @@ public:
|
||||
const LayoutSaverOptions layoutSaverOptions;
|
||||
QAction *const toggleAction;
|
||||
QAction *const floatAction;
|
||||
LastPositions m_lastPositions;
|
||||
Position::Ptr m_lastPosition = std::make_shared<Position>();
|
||||
bool m_isPersistentCentralDockWidget = false;
|
||||
bool m_processingToggleAction = false;
|
||||
bool m_updatingToggleAction = false;
|
||||
|
||||
@@ -143,6 +143,8 @@ void MinimalStateMachine::setCurrentState(State *state)
|
||||
|
||||
if (state)
|
||||
state->onEntry();
|
||||
|
||||
Q_EMIT currentStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,26 +594,26 @@ DragController::DragController(QObject *parent)
|
||||
{
|
||||
qCDebug(creation) << "DragController()";
|
||||
|
||||
auto stateNone = new StateNone(this);
|
||||
m_stateNone = new StateNone(this);
|
||||
auto statepreDrag = new StatePreDrag(this);
|
||||
auto stateDragging = isWayland() ? new StateDraggingWayland(this)
|
||||
: new StateDragging(this);
|
||||
m_stateDraggingMDI = new StateInternalMDIDragging(this);
|
||||
|
||||
stateNone->addTransition(this, &DragController::mousePressed, statepreDrag);
|
||||
statepreDrag->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
m_stateNone->addTransition(this, &DragController::mousePressed, statepreDrag);
|
||||
statepreDrag->addTransition(this, &DragController::dragCanceled, m_stateNone);
|
||||
statepreDrag->addTransition(this, &DragController::manhattanLengthMove, stateDragging);
|
||||
statepreDrag->addTransition(this, &DragController::manhattanLengthMoveMDI, m_stateDraggingMDI);
|
||||
stateDragging->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
stateDragging->addTransition(this, &DragController::dropped, stateNone);
|
||||
stateDragging->addTransition(this, &DragController::dragCanceled, m_stateNone);
|
||||
stateDragging->addTransition(this, &DragController::dropped, m_stateNone);
|
||||
|
||||
m_stateDraggingMDI->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
m_stateDraggingMDI->addTransition(this, &DragController::dragCanceled, m_stateNone);
|
||||
m_stateDraggingMDI->addTransition(this, &DragController::mdiPopOut, stateDragging);
|
||||
|
||||
if (usesFallbackMouseGrabber())
|
||||
enableFallbackMouseGrabber();
|
||||
|
||||
setCurrentState(stateNone);
|
||||
setCurrentState(m_stateNone);
|
||||
}
|
||||
|
||||
DragController *DragController::instance()
|
||||
@@ -647,6 +649,11 @@ bool DragController::isInClientDrag() const
|
||||
return isDragging() && !m_nonClientDrag;
|
||||
}
|
||||
|
||||
bool DragController::isIdle() const
|
||||
{
|
||||
return activeState() == m_stateNone;
|
||||
}
|
||||
|
||||
void DragController::grabMouseFor(QWidgetOrQuick *target)
|
||||
{
|
||||
if (isWayland())
|
||||
@@ -788,6 +795,12 @@ static QWidgetOrQuick *qtTopLevelForHWND(HWND hwnd)
|
||||
// Case not supported for QtQuick.
|
||||
const QWidgetList widgets = qApp->topLevelWidgets();
|
||||
for (QWidget *widget : widgets) {
|
||||
if (!widget->windowHandle()) {
|
||||
// Don't call winId on windows that don't have it, as that will force all its childrens to have it,
|
||||
// and that's not very stable. a top level might not have one because it's being destroyed, or because
|
||||
// it's a top-level just because it has't been reparented I guess.
|
||||
continue;
|
||||
}
|
||||
if (hwnd == ( HWND )widget->winId()) {
|
||||
return widget;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class StateBase;
|
||||
class StateNone;
|
||||
class StateInternalMDIDragging;
|
||||
class DropArea;
|
||||
class Draggable;
|
||||
@@ -59,6 +60,9 @@ public:
|
||||
State *currentState() const;
|
||||
void setCurrentState(State *);
|
||||
|
||||
Q_SIGNALS:
|
||||
void currentStateChanged();
|
||||
|
||||
private:
|
||||
State *m_currentState = nullptr;
|
||||
};
|
||||
@@ -85,6 +89,7 @@ public:
|
||||
bool isDragging() const;
|
||||
bool isInNonClientDrag() const;
|
||||
bool isInClientDrag() const;
|
||||
bool isIdle() const;
|
||||
|
||||
void grabMouseFor(QWidgetOrQuick *);
|
||||
void releaseMouse(QWidgetOrQuick *);
|
||||
@@ -133,6 +138,7 @@ private:
|
||||
DropArea *m_currentDropArea = nullptr;
|
||||
bool m_nonClientDrag = false;
|
||||
FallbackMouseGrabber *m_fallbackMouseGrabber = nullptr;
|
||||
StateNone *m_stateNone = nullptr;
|
||||
StateInternalMDIDragging *m_stateDraggingMDI = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
#include "Logging_p.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
// #include "indicators/AnimatedIndicators_p.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
@@ -34,8 +33,9 @@ using namespace KDDockWidgets;
|
||||
*
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
DropArea::DropArea(QWidgetOrQuick *parent)
|
||||
DropArea::DropArea(QWidgetOrQuick *parent, bool isMDIWrapper)
|
||||
: MultiSplitter(parent)
|
||||
, m_isMDIWrapper(isMDIWrapper)
|
||||
, m_dropIndicatorOverlay(Config::self().frameworkWidgetFactory()->createDropIndicatorOverlay(this))
|
||||
{
|
||||
qCDebug(creation) << "DropArea";
|
||||
@@ -46,6 +46,24 @@ DropArea::DropArea(QWidgetOrQuick *parent)
|
||||
qWarning() << "Dropping not implement for QtQuick on Wayland yet!";
|
||||
#endif
|
||||
}
|
||||
|
||||
if (m_isMDIWrapper) {
|
||||
connect(this, &MultiSplitter::visibleWidgetCountChanged, this, [this] {
|
||||
auto dw = mdiDockWidgetWrapper();
|
||||
if (!dw) {
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected null wrapper dock widget";
|
||||
return;
|
||||
}
|
||||
|
||||
if (visibleCount() > 0) {
|
||||
// The title of our MDI frame will need to change to the app name if we have more than 1 dock widget nested
|
||||
Q_EMIT dw->titleChanged(dw->title());
|
||||
} else {
|
||||
// Our wrapeper isn't needed anymore
|
||||
dw->deleteLater();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
DropArea::~DropArea()
|
||||
@@ -156,6 +174,11 @@ bool DropArea::hasSingleFloatingFrame() const
|
||||
return frames.size() == 1 && frames.first()->isFloating();
|
||||
}
|
||||
|
||||
bool DropArea::hasSingleFrame() const
|
||||
{
|
||||
return visibleCount() == 1;
|
||||
}
|
||||
|
||||
QStringList DropArea::affinities() const
|
||||
{
|
||||
if (auto mw = mainWindow()) {
|
||||
@@ -178,14 +201,14 @@ void DropArea::layoutParentContainerEqually(DockWidgetBase *dw)
|
||||
layoutEqually(item->parentBoxContainer());
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation DropArea::hover(WindowBeingDragged *draggedWindow, QPoint globalPos)
|
||||
DropLocation DropArea::hover(WindowBeingDragged *draggedWindow, QPoint globalPos)
|
||||
{
|
||||
if (Config::self().dropIndicatorsInhibited() || !validateAffinity(draggedWindow))
|
||||
return DropIndicatorOverlayInterface::DropLocation_None;
|
||||
return DropLocation_None;
|
||||
|
||||
if (!m_dropIndicatorOverlay) {
|
||||
qWarning() << Q_FUNC_INFO << "The frontend is missing a drop indicator overlay";
|
||||
return DropIndicatorOverlayInterface::DropLocation_None;
|
||||
return DropLocation_None;
|
||||
}
|
||||
|
||||
Frame *frame = frameContainingPos(globalPos); // Frame is nullptr if MainWindowOption_HasCentralFrame isn't set
|
||||
@@ -194,13 +217,13 @@ DropIndicatorOverlayInterface::DropLocation DropArea::hover(WindowBeingDragged *
|
||||
return m_dropIndicatorOverlay->hover(globalPos);
|
||||
}
|
||||
|
||||
static bool isOutterLocation(DropIndicatorOverlayInterface::DropLocation location)
|
||||
static bool isOutterLocation(DropLocation location)
|
||||
{
|
||||
switch (location) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
case DropLocation_OutterLeft:
|
||||
case DropLocation_OutterTop:
|
||||
case DropLocation_OutterRight:
|
||||
case DropLocation_OutterBottom:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -216,7 +239,7 @@ bool DropArea::drop(WindowBeingDragged *droppedWindow, QPoint globalPos)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_dropIndicatorOverlay->currentDropLocation() == DropIndicatorOverlayInterface::DropLocation_None) {
|
||||
if (m_dropIndicatorOverlay->currentDropLocation() == DropLocation_None) {
|
||||
qCDebug(hovering) << "DropArea::drop: bailing out, drop location = none";
|
||||
return false;
|
||||
}
|
||||
@@ -236,7 +259,7 @@ bool DropArea::drop(WindowBeingDragged *droppedWindow, QPoint globalPos)
|
||||
}
|
||||
|
||||
bool DropArea::drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame,
|
||||
DropIndicatorOverlayInterface::DropLocation droploc)
|
||||
DropLocation droploc)
|
||||
{
|
||||
FloatingWindow *droppedWindow = draggedWindow ? draggedWindow->floatingWindow()
|
||||
: nullptr;
|
||||
@@ -247,7 +270,8 @@ bool DropArea::drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame,
|
||||
// With Wayland we delay the floating window until we drop it.
|
||||
// Ofc, we could just dock the dockwidget without the temporary FloatingWindow, but this way we reuse
|
||||
// 99% of the rest of the code, without adding more wayland special cases
|
||||
droppedWindow = draggedWindow->draggable()->makeWindow()->floatingWindow();
|
||||
droppedWindow = draggedWindow ? draggedWindow->draggable()->makeWindow()->floatingWindow()
|
||||
: nullptr;
|
||||
if (!droppedWindow) {
|
||||
// Doesn't happen
|
||||
qWarning() << Q_FUNC_INFO << "Wayland: Expected window" << draggedWindow;
|
||||
@@ -263,19 +287,19 @@ bool DropArea::drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame,
|
||||
// variable isn't used
|
||||
|
||||
switch (droploc) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
case DropLocation_Left:
|
||||
case DropLocation_Top:
|
||||
case DropLocation_Bottom:
|
||||
case DropLocation_Right:
|
||||
result = drop(droppedWindow, DropIndicatorOverlayInterface::multisplitterLocationFor(droploc), acceptingFrame);
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
case DropLocation_OutterLeft:
|
||||
case DropLocation_OutterTop:
|
||||
case DropLocation_OutterRight:
|
||||
case DropLocation_OutterBottom:
|
||||
result = drop(droppedWindow, DropIndicatorOverlayInterface::multisplitterLocationFor(droploc), nullptr);
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
case DropLocation_Center:
|
||||
qCDebug(hovering) << "Tabbing" << droppedWindow << "into" << acceptingFrame;
|
||||
if (!validateAffinity(droppedWindow, acceptingFrame))
|
||||
return false;
|
||||
@@ -361,3 +385,16 @@ bool DropArea::validateAffinity(T *window, Frame *acceptingFrame) const
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DropArea::isMDIWrapper() const
|
||||
{
|
||||
return m_isMDIWrapper;
|
||||
}
|
||||
|
||||
DockWidgetBase *DropArea::mdiDockWidgetWrapper() const
|
||||
{
|
||||
if (m_isMDIWrapper)
|
||||
return qobject_cast<DockWidgetBase *>(QWidgetAdapter::parent());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ class DOCKS_EXPORT DropArea : public MultiSplitter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DropArea(QWidgetOrQuick *parent);
|
||||
explicit DropArea(QWidgetOrQuick *parent, bool isMDIWrapper = false);
|
||||
~DropArea();
|
||||
|
||||
void removeHover();
|
||||
DropIndicatorOverlayInterface::DropLocation hover(WindowBeingDragged *draggedWindow, QPoint globalPos);
|
||||
DropLocation hover(WindowBeingDragged *draggedWindow, QPoint globalPos);
|
||||
///@brief Called when a user drops a widget via DND
|
||||
bool drop(WindowBeingDragged *droppedWindow, QPoint globalPos);
|
||||
Frame::List frames() const;
|
||||
@@ -64,9 +64,19 @@ public:
|
||||
/// Implies it's in a FloatingWindow and that it has only one dock widget
|
||||
bool hasSingleFloatingFrame() const;
|
||||
|
||||
/// Returns whether this drop area has only 1 frame.
|
||||
/// See further explanation in FloatingWindow::hasSingleFrame()
|
||||
bool hasSingleFrame() const;
|
||||
|
||||
QStringList affinities() const;
|
||||
void layoutParentContainerEqually(DockWidgetBase *);
|
||||
|
||||
/// When DockWidget::Option_MDINestable is used, docked MDI dock widgets will be wrapped inside a DropArea, so they accept drops
|
||||
/// This DropArea is created implicitly while docking, and this function will return true
|
||||
bool isMDIWrapper() const;
|
||||
|
||||
/// Returns the helper dock widget for implementing DockWidget::Option_MDINestable.
|
||||
DockWidgetBase *mdiDockWidgetWrapper() const;
|
||||
private:
|
||||
Q_DISABLE_COPY(DropArea)
|
||||
friend class Frame;
|
||||
@@ -77,12 +87,13 @@ private:
|
||||
|
||||
template<typename T>
|
||||
bool validateAffinity(T *, Frame *acceptingFrame = nullptr) const;
|
||||
bool drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame, DropIndicatorOverlayInterface::DropLocation);
|
||||
bool drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame, DropLocation);
|
||||
bool drop(QWidgetOrQuick *droppedwindow, KDDockWidgets::Location location, Frame *relativeTo);
|
||||
Frame *frameContainingPos(QPoint globalPos) const;
|
||||
void updateFloatingActions();
|
||||
|
||||
bool m_inDestructor = false;
|
||||
const bool m_isMDIWrapper;
|
||||
QString m_affinityName;
|
||||
DropIndicatorOverlayInterface *m_dropIndicatorOverlay = nullptr;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "Frame_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DragController_p.h"
|
||||
#include "Config.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
@@ -24,6 +26,9 @@ DropIndicatorOverlayInterface::DropIndicatorOverlayInterface(DropArea *dropArea)
|
||||
setVisible(false);
|
||||
setObjectName(QStringLiteral("DropIndicatorOverlayInterface"));
|
||||
|
||||
// Set transparent for mouse events so that topLevel->childAt() never returns the drop indicator overlay
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
connect(DockRegistry::self(), &DockRegistry::dropIndicatorsInhibitedChanged, this,
|
||||
[this](bool inhibited) {
|
||||
if (inhibited)
|
||||
@@ -81,35 +86,88 @@ bool DropIndicatorOverlayInterface::isHovered() const
|
||||
return m_draggedWindowIsHovering;
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation DropIndicatorOverlayInterface::currentDropLocation() const
|
||||
DropLocation DropIndicatorOverlayInterface::currentDropLocation() const
|
||||
{
|
||||
return m_currentDropLocation;
|
||||
}
|
||||
|
||||
KDDockWidgets::Location DropIndicatorOverlayInterface::multisplitterLocationFor(DropIndicatorOverlayInterface::DropLocation dropLoc)
|
||||
KDDockWidgets::Location DropIndicatorOverlayInterface::multisplitterLocationFor(DropLocation dropLoc)
|
||||
{
|
||||
switch (dropLoc) {
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_None:
|
||||
case DropLocation_None:
|
||||
return KDDockWidgets::Location_None;
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
case DropLocation_Left:
|
||||
case DropLocation_OutterLeft:
|
||||
return KDDockWidgets::Location_OnLeft;
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
case DropLocation_OutterTop:
|
||||
case DropLocation_Top:
|
||||
return KDDockWidgets::Location_OnTop;
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
case DropLocation_OutterRight:
|
||||
case DropLocation_Right:
|
||||
return KDDockWidgets::Location_OnRight;
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
case DropLocation_OutterBottom:
|
||||
case DropLocation_Bottom:
|
||||
return KDDockWidgets::Location_OnBottom;
|
||||
case KDDockWidgets::DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
case DropLocation_Center:
|
||||
return KDDockWidgets::Location_None;
|
||||
case DropLocation_Inner:
|
||||
case DropLocation_Outter:
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected drop location" << dropLoc;
|
||||
break;
|
||||
}
|
||||
|
||||
return KDDockWidgets::Location_None;
|
||||
}
|
||||
|
||||
bool DropIndicatorOverlayInterface::dropIndicatorVisible(DropLocation dropLoc) const
|
||||
{
|
||||
if (dropLoc == DropLocation_None)
|
||||
return false;
|
||||
|
||||
WindowBeingDragged *windowBeingDragged = DragController::instance()->windowBeingDragged();
|
||||
if (!windowBeingDragged)
|
||||
return false;
|
||||
|
||||
const DockWidgetBase::List source = windowBeingDragged->dockWidgets();
|
||||
const DockWidgetBase::List target = m_hoveredFrame ? m_hoveredFrame->dockWidgets()
|
||||
: DockWidgetBase::List();
|
||||
|
||||
const bool isInner = dropLoc & DropLocation_Inner;
|
||||
const bool isOutter = dropLoc & DropLocation_Outter;
|
||||
if (isInner) {
|
||||
if (!m_hoveredFrame)
|
||||
return false;
|
||||
} else if (isOutter) {
|
||||
// If there's only 1 frame in the layout, the outer indicators are redundant, as they do the same thing as the internal ones.
|
||||
// But there might be another window obscuring our target, so it's useful to show the outer indicators in this case
|
||||
const bool isTheOnlyFrame = m_hoveredFrame && m_hoveredFrame->isTheOnlyFrame();
|
||||
if (isTheOnlyFrame && !DockRegistry::self()->isProbablyObscured(m_hoveredFrame->window()->windowHandle(), windowBeingDragged))
|
||||
return false;
|
||||
} else if (dropLoc == DropLocation_Center) {
|
||||
if (!m_hoveredFrame)
|
||||
return false;
|
||||
|
||||
if (auto tabbingAllowedFunc = Config::self().tabbingAllowedFunc()) {
|
||||
if (!tabbingAllowedFunc(source, target))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow to dock to center if the affinities match
|
||||
if (!DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities()) && m_hoveredFrame->isDockable())
|
||||
return false;
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Unknown drop indicator location" << dropLoc;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto dropIndicatorAllowedFunc = Config::self().dropIndicatorAllowedFunc()) {
|
||||
if (!dropIndicatorAllowedFunc(dropLoc, source, target))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::onFrameDestroyed()
|
||||
{
|
||||
setHoveredFrame(nullptr);
|
||||
@@ -119,7 +177,7 @@ void DropIndicatorOverlayInterface::onHoveredFrameChanged(Frame *)
|
||||
{
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation location)
|
||||
void DropIndicatorOverlayInterface::setCurrentDropLocation(DropLocation location)
|
||||
{
|
||||
if (m_currentDropLocation != location) {
|
||||
m_currentDropLocation = location;
|
||||
@@ -127,7 +185,7 @@ void DropIndicatorOverlayInterface::setCurrentDropLocation(DropIndicatorOverlayI
|
||||
}
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation DropIndicatorOverlayInterface::hover(QPoint globalPos)
|
||||
DropLocation DropIndicatorOverlayInterface::hover(QPoint globalPos)
|
||||
{
|
||||
return hover_impl(globalPos);
|
||||
}
|
||||
@@ -143,5 +201,5 @@ void DropIndicatorOverlayInterface::setHoveredFrameRect(QRect rect)
|
||||
void DropIndicatorOverlayInterface::removeHover()
|
||||
{
|
||||
setWindowBeingDragged(false);
|
||||
setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
|
||||
setCurrentDropLocation(DropLocation_None);
|
||||
}
|
||||
|
||||
@@ -25,25 +25,8 @@ class DOCKS_EXPORT DropIndicatorOverlayInterface : public QWidgetAdapter
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QRect hoveredFrameRect READ hoveredFrameRect NOTIFY hoveredFrameRectChanged)
|
||||
Q_PROPERTY(KDDockWidgets::DropIndicatorOverlayInterface::DropLocation currentDropLocation READ currentDropLocation NOTIFY currentDropLocationChanged)
|
||||
Q_PROPERTY(KDDockWidgets::DropLocation currentDropLocation READ currentDropLocation NOTIFY currentDropLocationChanged)
|
||||
public:
|
||||
enum DropLocation
|
||||
{
|
||||
DropLocation_None = 0,
|
||||
DropLocation_Left,
|
||||
DropLocation_Top,
|
||||
DropLocation_Right,
|
||||
DropLocation_Bottom,
|
||||
DropLocation_Center,
|
||||
DropLocation_OutterLeft,
|
||||
DropLocation_OutterTop,
|
||||
DropLocation_OutterRight,
|
||||
DropLocation_OutterBottom,
|
||||
|
||||
DropLocation_First = DropLocation_Left,
|
||||
DropLocation_Last = DropLocation_OutterBottom,
|
||||
};
|
||||
Q_ENUM(DropLocation)
|
||||
|
||||
explicit DropIndicatorOverlayInterface(DropArea *dropArea);
|
||||
void setHoveredFrame(Frame *);
|
||||
@@ -55,9 +38,9 @@ public:
|
||||
{
|
||||
return m_hoveredFrame;
|
||||
}
|
||||
void setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation location);
|
||||
void setCurrentDropLocation(DropLocation location);
|
||||
|
||||
KDDockWidgets::DropIndicatorOverlayInterface::DropLocation hover(QPoint globalPos);
|
||||
KDDockWidgets::DropLocation hover(QPoint globalPos);
|
||||
|
||||
/// Clears and hides drop indicators
|
||||
void removeHover();
|
||||
@@ -66,6 +49,9 @@ public:
|
||||
/// The return is in global coordinates
|
||||
virtual QPoint posForIndicator(DropLocation) const = 0;
|
||||
|
||||
/// @brief Returns whether the specified drop indicator should be visible
|
||||
virtual bool dropIndicatorVisible(DropLocation) const;
|
||||
|
||||
static KDDockWidgets::Location multisplitterLocationFor(DropLocation);
|
||||
|
||||
Q_SIGNALS:
|
||||
@@ -80,7 +66,7 @@ private:
|
||||
DropLocation m_currentDropLocation = DropLocation_None;
|
||||
|
||||
protected:
|
||||
virtual DropIndicatorOverlayInterface::DropLocation hover_impl(QPoint globalPos) = 0;
|
||||
virtual DropLocation hover_impl(QPoint globalPos) = 0;
|
||||
virtual void onHoveredFrameChanged(Frame *);
|
||||
virtual void updateVisibility() {};
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "DragController_p.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
|
||||
#include "multisplitter/Item_p.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QScopedValueRollback>
|
||||
@@ -144,12 +147,52 @@ FloatingWindow::FloatingWindow(QRect suggestedGeometry, MainWindowBase *parent)
|
||||
FloatingWindow::FloatingWindow(Frame *frame, QRect suggestedGeometry, MainWindowBase *parent)
|
||||
: FloatingWindow(suggestedGeometry, hackFindParentHarder(frame, parent))
|
||||
{
|
||||
m_disableSetVisible = true;
|
||||
// Adding a widget will trigger onFrameCountChanged, which triggers a setVisible(true).
|
||||
// The problem with setVisible(true) will forget about or requested geometry and place the window at 0,0
|
||||
// So disable the setVisible(true) call while in the ctor.
|
||||
m_dropArea->addWidget(frame, KDDockWidgets::Location_OnTop, {});
|
||||
m_disableSetVisible = false;
|
||||
QScopedValueRollback<bool> guard(m_disableSetVisible, true);
|
||||
|
||||
if (frame->hasNestedMDIDockWidgets()) {
|
||||
// When using DockWidget::MDINestable, the docked MDI widget is wrapped by a drop area so we can drop things into it.
|
||||
// When floating it, we can delete that helper drop area, as FloatingWindow already has one
|
||||
|
||||
if (frame->dockWidgetCount() == 0) {
|
||||
// doesn't happen
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected empty frame";
|
||||
return;
|
||||
}
|
||||
|
||||
DockWidgetBase *dwMDIWrapper = frame->dockWidgetAt(0);
|
||||
DropArea *dropAreaMDIWrapper = dwMDIWrapper->d->mdiDropAreaWrapper();
|
||||
|
||||
if (dropAreaMDIWrapper->hasSingleFrame()) {
|
||||
Frame *innerFrame = dropAreaMDIWrapper->frames().constFirst();
|
||||
if (innerFrame->hasSingleDockWidget()) {
|
||||
// When pressing the unfloat button, the dock widgets gets docked to the previous
|
||||
// position it was at. DockWidgetBase::Private::m_lastPosition stores that location,
|
||||
// however, when having nested MDI, we have an extra Dock Widget, the wrapper, and it
|
||||
// contains the last position. So, when floating, we need to transfer that and not lose it.
|
||||
DockWidgetBase *dw = innerFrame->dockWidgetAt(0);
|
||||
dw->d->lastPosition() = dwMDIWrapper->d->lastPosition();
|
||||
}
|
||||
}
|
||||
|
||||
m_dropArea->addMultiSplitter(dropAreaMDIWrapper, Location_OnTop);
|
||||
dwMDIWrapper->setVisible(false);
|
||||
if (!DragController::instance()->isIdle()) {
|
||||
// We're dragging a MDI window and we reached the border, detaching it, and making it float. We can't delete the wrapper frame just yet,
|
||||
// as that would delete the title bar which is currently being dragged. Delete it once the drag finishes
|
||||
connect(DragController::instance(), &DragController::currentStateChanged, dwMDIWrapper, [dwMDIWrapper] {
|
||||
if (DragController::instance()->isIdle())
|
||||
delete dwMDIWrapper;
|
||||
});
|
||||
} else {
|
||||
dwMDIWrapper->deleteLater();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Adding a widget will trigger onFrameCountChanged, which triggers a setVisible(true).
|
||||
// The problem with setVisible(true) will forget about or requested geometry and place the window at 0,0
|
||||
// So disable the setVisible(true) call while in the ctor.
|
||||
m_dropArea->addWidget(frame, KDDockWidgets::Location_OnTop, {});
|
||||
}
|
||||
}
|
||||
|
||||
FloatingWindow::~FloatingWindow()
|
||||
@@ -321,7 +364,7 @@ bool FloatingWindow::anyNonDockable() const
|
||||
|
||||
bool FloatingWindow::hasSingleFrame() const
|
||||
{
|
||||
return m_dropArea->visibleCount() == 1;
|
||||
return m_dropArea->hasSingleFrame();
|
||||
}
|
||||
|
||||
bool FloatingWindow::hasSingleDockWidget() const
|
||||
@@ -451,14 +494,7 @@ void FloatingWindow::onCloseEvent(QCloseEvent *e)
|
||||
return;
|
||||
}
|
||||
|
||||
e->accept(); // Accepted by default (will close unless ignored)
|
||||
|
||||
const Frame::List frames = this->frames();
|
||||
for (Frame *frame : frames) {
|
||||
qApp->sendEvent(frame, e);
|
||||
if (!e->isAccepted())
|
||||
break; // Stop when the first frame prevents closing
|
||||
}
|
||||
m_dropArea->onCloseEvent(e);
|
||||
}
|
||||
|
||||
bool FloatingWindow::deserialize(const LayoutSaver::FloatingWindow &fw)
|
||||
@@ -466,12 +502,6 @@ bool FloatingWindow::deserialize(const LayoutSaver::FloatingWindow &fw)
|
||||
if (dropArea()->deserialize(fw.multiSplitterLayout)) {
|
||||
updateTitleBarVisibility();
|
||||
|
||||
if (fw.normalGeometry.isValid() && !isNormalWindowState(fw.windowState)) {
|
||||
// Restore QWidgetPrivate's normalGeometry (no public API in QWidget)
|
||||
setNormalGeometry(fw.normalGeometry);
|
||||
}
|
||||
|
||||
// And show it:
|
||||
if (fw.windowState & Qt::WindowMaximized) {
|
||||
showMaximized();
|
||||
} else if (fw.windowState & Qt::WindowMinimized) {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
@@ -50,12 +51,22 @@ static FrameOptions actualOptions(FrameOptions options)
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
static TabWidgetOptions tabWidgetOptions(FrameOptions options)
|
||||
{
|
||||
if (options & FrameOption_NonDockable) {
|
||||
/// If we can't tab things into this Frame then let's not draw the QTabWidget frame either
|
||||
return TabWidgetOption_DocumentMode;
|
||||
}
|
||||
|
||||
return TabWidgetOption_None;
|
||||
}
|
||||
}
|
||||
|
||||
Frame::Frame(QWidgetOrQuick *parent, FrameOptions options, int userType)
|
||||
: LayoutGuestWidget(parent)
|
||||
, FocusScope(this)
|
||||
, m_tabWidget(Config::self().frameworkWidgetFactory()->createTabWidget(this))
|
||||
, m_tabWidget(Config::self().frameworkWidgetFactory()->createTabWidget(this, tabWidgetOptions(options)))
|
||||
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
|
||||
, m_options(actualOptions(options))
|
||||
, m_userType(userType)
|
||||
@@ -330,6 +341,9 @@ void Frame::updateTitleBarVisibility()
|
||||
} else if (FloatingWindow *fw = floatingWindow()) {
|
||||
// If there's nested frames then show each Frame's title bar
|
||||
visible = !fw->hasSingleFrame();
|
||||
} else if (isMDIWrapper()) {
|
||||
auto dropArea = this->mdiDropAreaWrapper();
|
||||
visible = !dropArea->hasSingleFrame();
|
||||
} else {
|
||||
visible = true;
|
||||
}
|
||||
@@ -373,6 +387,10 @@ TitleBar *Frame::actualTitleBar() const
|
||||
// If there's nested frames then show each Frame's title bar
|
||||
if (fw->hasSingleFrame())
|
||||
return fw->titleBar();
|
||||
} else if (auto mdiDropArea = mdiDropAreaWrapper()) {
|
||||
if (mdiDropArea->hasSingleFrame()) {
|
||||
return mdiFrame()->titleBar();
|
||||
}
|
||||
}
|
||||
|
||||
return titleBar();
|
||||
@@ -536,7 +554,7 @@ void Frame::setLayoutItem(Layouting::Item *item)
|
||||
dw->d->addPlaceholderItem(item);
|
||||
} else {
|
||||
for (DockWidgetBase *dw : dockWidgets())
|
||||
dw->d->lastPositions().removePlaceholders();
|
||||
dw->d->lastPosition()->removePlaceholders();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,7 +638,7 @@ void Frame::unoverlay()
|
||||
|
||||
bool Frame::isFloating() const
|
||||
{
|
||||
if (isInMainWindow())
|
||||
if (isInMainWindow() || isMDI())
|
||||
return false;
|
||||
|
||||
return isTheOnlyFrame();
|
||||
@@ -836,11 +854,55 @@ bool Frame::isMDI() const
|
||||
return mdiLayoutWidget() != nullptr;
|
||||
}
|
||||
|
||||
bool Frame::isMDIWrapper() const
|
||||
{
|
||||
return mdiDropAreaWrapper() != nullptr;
|
||||
}
|
||||
|
||||
Frame *Frame::mdiFrame() const
|
||||
{
|
||||
if (auto dwWrapper = mdiDockWidgetWrapper()) {
|
||||
return dwWrapper->d->frame();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DockWidgetBase *Frame::mdiDockWidgetWrapper() const
|
||||
{
|
||||
if (auto dropArea = mdiDropAreaWrapper()) {
|
||||
return qobject_cast<DockWidgetBase *>(dropArea->QWidgetAdapter::parent());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DropArea *Frame::mdiDropAreaWrapper() const
|
||||
{
|
||||
auto dropArea = qobject_cast<DropArea *>(QWidgetAdapter::parent());
|
||||
if (dropArea && dropArea->isMDIWrapper())
|
||||
return dropArea;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MDILayoutWidget *Frame::mdiLayoutWidget() const
|
||||
{
|
||||
return qobject_cast<MDILayoutWidget *>(m_layoutWidget);
|
||||
}
|
||||
|
||||
bool Frame::hasNestedMDIDockWidgets() const
|
||||
{
|
||||
if (!isMDI() || dockWidgetCount() == 0)
|
||||
return false;
|
||||
|
||||
if (dockWidgetCount() != 1) {
|
||||
qWarning() << Q_FUNC_INFO << "Expected a single dock widget wrapper as frame child";
|
||||
return false;
|
||||
}
|
||||
|
||||
return dockWidgetAt(0)->d->isMDIWrapper();
|
||||
}
|
||||
|
||||
int Frame::userType() const
|
||||
{
|
||||
return m_userType;
|
||||
|
||||
@@ -285,9 +285,27 @@ public:
|
||||
/// Usually no, unless you're using an MDI main window
|
||||
bool isMDI() const;
|
||||
|
||||
/// @brief Returns whether this frame was created automatically just for the purpose of supporting DockWidget::Option_MDINestable
|
||||
bool isMDIWrapper() const;
|
||||
|
||||
/// @brief If this is an MDI wrapper frame, return the DockWidget MDI wrapper
|
||||
/// @sa isMDIWrapper
|
||||
DockWidgetBase *mdiDockWidgetWrapper() const;
|
||||
|
||||
/// @brief If this is an MDI wrapper frame, return the DropArea MDI wrapper
|
||||
/// @sa isMDIWrapper
|
||||
DropArea *mdiDropAreaWrapper() const;
|
||||
|
||||
/// @brief If this frame is an MDI wrapper, returns the MDI frame. That is the frame you actually drag inside the MDI area
|
||||
Frame *mdiFrame() const;
|
||||
|
||||
/// @brief Returns the MDI layout. Or nullptr if this frame isn't in a MDI layout
|
||||
MDILayoutWidget *mdiLayoutWidget() const;
|
||||
|
||||
/// @brief If this frame is a MDI frame (isMDI() == true), returns whether it contains nested dock widgets (DockWidget::Option_MDINestable)
|
||||
/// @sa isMDI()
|
||||
bool hasNestedMDIDockWidgets() const;
|
||||
|
||||
/// @brief See DockWidgetBase::userType()
|
||||
int userType() const;
|
||||
|
||||
|
||||
@@ -284,6 +284,7 @@ public:
|
||||
QString uniqueName;
|
||||
QStringList affinities;
|
||||
QRect geometry;
|
||||
QRect normalGeometry;
|
||||
int screenIndex;
|
||||
QSize screenSize; // for relative-size restoring
|
||||
bool isVisible;
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "Position_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
#include "multisplitter/Item_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
@@ -33,21 +36,30 @@ LayoutWidget::~LayoutWidget()
|
||||
DockRegistry::self()->unregisterLayout(this);
|
||||
}
|
||||
|
||||
bool LayoutWidget::isInMainWindow() const
|
||||
bool LayoutWidget::isInMainWindow(bool honourNesting) const
|
||||
{
|
||||
return mainWindow() != nullptr;
|
||||
return mainWindow(honourNesting) != nullptr;
|
||||
}
|
||||
|
||||
MainWindowBase *LayoutWidget::mainWindow() const
|
||||
MainWindowBase *LayoutWidget::mainWindow(bool honourNesting) 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<MainWindowBase *>(pw->parentWidget());
|
||||
// QtQuick doesn't support nesting yet
|
||||
honourNesting = honourNesting && kddwUsesQtWidgets();
|
||||
|
||||
if (auto mw = qobject_cast<MainWindowBase *>(pw))
|
||||
return mw;
|
||||
if (honourNesting) {
|
||||
// This layout might be a MDIArea, nested in DropArea, which is main window.
|
||||
return firstParentOfType<MainWindowBase>(this);
|
||||
} else {
|
||||
|
||||
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<MainWindowBase *>(pw->parentWidget());
|
||||
|
||||
if (auto mw = qobject_cast<MainWindowBase *>(pw))
|
||||
return mw;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -129,7 +141,7 @@ void LayoutWidget::unrefOldPlaceholders(const Frame::List &framesBeingAdded) con
|
||||
{
|
||||
for (Frame *frame : framesBeingAdded) {
|
||||
for (DockWidgetBase *dw : frame->dockWidgets()) {
|
||||
dw->d->lastPositions().removePlaceholders(this);
|
||||
dw->d->lastPosition()->removePlaceholders(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,3 +302,15 @@ LayoutSaver::MultiSplitter LayoutWidget::serialize() const
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void LayoutWidget::onCloseEvent(QCloseEvent *e)
|
||||
{
|
||||
e->accept(); // Accepted by default (will close unless ignored)
|
||||
|
||||
const Frame::List frames = this->frames();
|
||||
for (Frame *frame : frames) {
|
||||
qApp->sendEvent(frame, e);
|
||||
if (!e->isAccepted())
|
||||
break; // Stop when the first frame prevents closing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
namespace Layouting {
|
||||
class Item;
|
||||
class ItemContainer;
|
||||
class Separator;
|
||||
class Widget_qwidget;
|
||||
}
|
||||
@@ -62,8 +63,13 @@ public:
|
||||
explicit LayoutWidget(QWidgetOrQuick *parent = nullptr);
|
||||
~LayoutWidget() override;
|
||||
|
||||
bool isInMainWindow() const;
|
||||
MainWindowBase *mainWindow() const;
|
||||
/// @brief Returns whether this layout is in a MainWindow
|
||||
/// @param honourNesting If true, then we'll count DropAreas/MDIAreas which are nested into DropAreas/MDIAreas as inside the main window.
|
||||
/// otherwise, only direct parenting is considered
|
||||
bool isInMainWindow(bool honourNesting = false) const;
|
||||
|
||||
MainWindowBase *mainWindow(bool honourNesting = false) const;
|
||||
|
||||
FloatingWindow *floatingWindow() const;
|
||||
|
||||
/**
|
||||
@@ -183,6 +189,8 @@ public:
|
||||
virtual bool deserialize(const LayoutSaver::MultiSplitter &);
|
||||
LayoutSaver::MultiSplitter serialize() const;
|
||||
|
||||
void onCloseEvent(QCloseEvent *) override;
|
||||
|
||||
protected:
|
||||
void setRootItem(Layouting::ItemContainer *root);
|
||||
/**
|
||||
|
||||
@@ -107,7 +107,8 @@ void MDILayoutWidget::resizeDockWidget(Frame *frame, QSize size)
|
||||
|
||||
Layouting::Item *item = itemForFrame(frame);
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "Frame not found in the layout" << frame;
|
||||
qWarning() << Q_FUNC_INFO << "Frame not found in the layout" << frame << frame->isMDI()
|
||||
<< frame->isMDIWrapper();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
~MDILayoutWidget() override;
|
||||
|
||||
/// @brief docks the dock widgets into this MDI area, at the specified position
|
||||
void addDockWidget(DockWidgetBase *dw, QPoint localPt, InitialOption addingOption);
|
||||
void addDockWidget(DockWidgetBase *dw, QPoint localPt, InitialOption addingOption = {});
|
||||
|
||||
/// @brief Moves a dock widget @p dw to point @p pos
|
||||
void moveDockWidget(DockWidgetBase *dw, QPoint pos);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "Position_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -47,7 +48,7 @@ void Position::addPlaceholderItem(Layouting::Item *placeholder)
|
||||
removeNonMainWindowPlaceholders();
|
||||
}
|
||||
|
||||
// Make sure our list only contains valid placeholders. We save the result so we can disconnect from the lambda, since the Item might outlive LastPosition
|
||||
// Make sure our list only contains valid placeholders. We save the result so we can disconnect from the lambda, since the Item might outlive Position
|
||||
QMetaObject::Connection connection = QObject::connect(placeholder, &QObject::destroyed, placeholder, [this, placeholder] {
|
||||
removePlaceholder(placeholder);
|
||||
});
|
||||
@@ -66,7 +67,7 @@ Layouting::Item *Position::layoutItem() const
|
||||
// In the future we might want to restore it to FloatingWindows.
|
||||
|
||||
for (const auto &itemref : m_placeholders) {
|
||||
if (DockRegistry::self()->itemIsInMainWindow(itemref->item))
|
||||
if (itemref->isInMainWindow())
|
||||
return itemref->item;
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ void Position::removeNonMainWindowPlaceholders()
|
||||
auto it = m_placeholders.begin();
|
||||
while (it != m_placeholders.end()) {
|
||||
ItemRef *itemref = it->get();
|
||||
if (!DockRegistry::self()->itemIsInMainWindow(itemref->item))
|
||||
if (!itemref->isInMainWindow())
|
||||
it = m_placeholders.erase(it);
|
||||
else
|
||||
++it;
|
||||
@@ -121,6 +122,9 @@ void Position::removePlaceholder(Layouting::Item *placeholder)
|
||||
|
||||
void Position::deserialize(const LayoutSaver::Position &lp)
|
||||
{
|
||||
m_lastFloatingGeometry = lp.lastFloatingGeometry;
|
||||
m_lastOverlayedGeometries = lp.lastOverlayedGeometries;
|
||||
|
||||
for (const auto &placeholder : qAsConst(lp.placeholders)) {
|
||||
LayoutWidget *layout;
|
||||
int itemIndex = placeholder.itemIndex;
|
||||
@@ -190,6 +194,9 @@ LayoutSaver::Position Position::serialize() const
|
||||
l.tabIndex = m_tabIndex;
|
||||
l.wasFloating = m_wasFloating;
|
||||
|
||||
l.lastFloatingGeometry = lastFloatingGeometry();
|
||||
l.lastOverlayedGeometries = m_lastOverlayedGeometries;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
@@ -209,17 +216,7 @@ ItemRef::~ItemRef()
|
||||
}
|
||||
}
|
||||
|
||||
LayoutSaver::Position LastPositions::serialize()
|
||||
bool ItemRef::isInMainWindow() const
|
||||
{
|
||||
LayoutSaver::Position result = lastPosition->serialize();
|
||||
result.lastFloatingGeometry = lastFloatingGeometry();
|
||||
result.lastOverlayedGeometries = m_lastOverlayedGeometries;
|
||||
return result;
|
||||
}
|
||||
|
||||
void LastPositions::deserialize(const LayoutSaver::Position &p)
|
||||
{
|
||||
m_lastFloatingGeometry = p.lastFloatingGeometry;
|
||||
m_lastOverlayedGeometries = p.lastOverlayedGeometries;
|
||||
lastPosition->deserialize(p);
|
||||
return DockRegistry::self()->itemIsInMainWindow(item);
|
||||
}
|
||||
|
||||
@@ -41,9 +41,11 @@ class LayoutWidget;
|
||||
// Just a RAII class so we don't forget to unref
|
||||
struct ItemRef
|
||||
{
|
||||
ItemRef(const QMetaObject::Connection &conn, Layouting::Item *it);
|
||||
explicit ItemRef(const QMetaObject::Connection &, Layouting::Item *);
|
||||
~ItemRef();
|
||||
|
||||
bool isInMainWindow() const;
|
||||
|
||||
Layouting::Item *const item;
|
||||
const QPointer<Layouting::Item> guard;
|
||||
const QMetaObject::Connection connection;
|
||||
@@ -106,6 +108,7 @@ public:
|
||||
bool containsPlaceholder(Layouting::Item *) const;
|
||||
void removePlaceholders();
|
||||
|
||||
/// @brief Returns the last places where the dock widget was or is
|
||||
const std::vector<std::unique_ptr<ItemRef>> &placeholders() const
|
||||
{
|
||||
return m_placeholders;
|
||||
@@ -120,26 +123,10 @@ public:
|
||||
///@brief removes the Item @p placeholder
|
||||
void removePlaceholder(Layouting::Item *placeholder);
|
||||
|
||||
private:
|
||||
friend inline QDebug operator<<(QDebug, const KDDockWidgets::Position::Ptr &);
|
||||
|
||||
// The last places where this dock widget was (or is), so it can be restored when setFloating(false) or show() is called.
|
||||
std::vector<std::unique_ptr<ItemRef>> m_placeholders;
|
||||
bool m_clearing = false; // to prevent re-entrancy
|
||||
};
|
||||
|
||||
struct LastPositions
|
||||
{
|
||||
// TODO: Support multiple old positions, one per main window
|
||||
|
||||
bool isValid() const
|
||||
void saveTabIndex(int tabIndex, bool isFloating)
|
||||
{
|
||||
return lastPosition->isValid();
|
||||
}
|
||||
|
||||
void addPosition(Layouting::Item *item)
|
||||
{
|
||||
lastPosition->addPlaceholderItem(item);
|
||||
m_tabIndex = tabIndex;
|
||||
m_wasFloating = isFloating;
|
||||
}
|
||||
|
||||
void setLastFloatingGeometry(QRect geo)
|
||||
@@ -149,7 +136,7 @@ struct LastPositions
|
||||
|
||||
bool wasFloating() const
|
||||
{
|
||||
return lastPosition->m_wasFloating;
|
||||
return m_wasFloating;
|
||||
}
|
||||
|
||||
QRect lastFloatingGeometry() const
|
||||
@@ -157,6 +144,16 @@ struct LastPositions
|
||||
return m_lastFloatingGeometry;
|
||||
}
|
||||
|
||||
Layouting::Item *lastItem() const
|
||||
{
|
||||
return layoutItem();
|
||||
}
|
||||
|
||||
int lastTabIndex() const
|
||||
{
|
||||
return m_tabIndex;
|
||||
}
|
||||
|
||||
QRect lastOverlayedGeometry(SideBarLocation loc) const
|
||||
{
|
||||
return m_lastOverlayedGeometries.value(loc);
|
||||
@@ -167,47 +164,14 @@ struct LastPositions
|
||||
m_lastOverlayedGeometries[loc] = rect;
|
||||
}
|
||||
|
||||
LayoutSaver::Position serialize();
|
||||
void deserialize(const LayoutSaver::Position &p);
|
||||
|
||||
Layouting::Item *lastItem() const
|
||||
{
|
||||
return lastPosition->layoutItem();
|
||||
}
|
||||
|
||||
Layouting::Item::List layoutItems() const
|
||||
{
|
||||
Layouting::Item::List items;
|
||||
return items;
|
||||
}
|
||||
|
||||
void saveTabIndex(int tabIndex, bool isFloating)
|
||||
{
|
||||
lastPosition->m_tabIndex = tabIndex;
|
||||
lastPosition->m_wasFloating = isFloating;
|
||||
}
|
||||
|
||||
void removePlaceholders() const
|
||||
{
|
||||
lastPosition->removePlaceholders();
|
||||
}
|
||||
|
||||
void removePlaceholders(const LayoutWidget *hostWidget) const
|
||||
{
|
||||
lastPosition->removePlaceholders(hostWidget);
|
||||
}
|
||||
|
||||
int lastTabIndex() const
|
||||
{
|
||||
return lastPosition->m_tabIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
friend inline QDebug operator<<(QDebug, const KDDockWidgets::Position::Ptr &);
|
||||
|
||||
// The last places where this dock widget was (or is), so it can be restored when setFloating(false) or show() is called.
|
||||
std::vector<std::unique_ptr<ItemRef>> m_placeholders;
|
||||
QRect m_lastFloatingGeometry;
|
||||
QHash<SideBarLocation, QRect> m_lastOverlayedGeometries;
|
||||
|
||||
friend inline QDebug operator<<(QDebug d, const KDDockWidgets::LastPositions &);
|
||||
Position::Ptr lastPosition = std::make_shared<Position>();
|
||||
bool m_clearing = false; // to prevent re-entrancy
|
||||
};
|
||||
|
||||
inline QDebug operator<<(QDebug d, const KDDockWidgets::Position::Ptr &p)
|
||||
@@ -219,12 +183,6 @@ inline QDebug operator<<(QDebug d, const KDDockWidgets::Position::Ptr &p)
|
||||
return d;
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug d, const KDDockWidgets::LastPositions &p)
|
||||
{
|
||||
d << p.lastPosition << "; lastFloatingGeometry=" << p.m_lastFloatingGeometry;
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "Config.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
#include "TabWidget_p.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWindowStateChangeEvent>
|
||||
@@ -100,8 +102,24 @@ MainWindowBase *TitleBar::mainWindow() const
|
||||
|
||||
bool TitleBar::isMDI() const
|
||||
{
|
||||
if (auto mw = mainWindow())
|
||||
return mw->isMDI();
|
||||
QObject *p = const_cast<TitleBar *>(this);
|
||||
while (p) {
|
||||
if (qobject_cast<const QWindow*>(p)) {
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qobject_cast<MDILayoutWidget *>(p))
|
||||
return true;
|
||||
|
||||
if (qobject_cast<DropArea *>(p)) {
|
||||
// Note that the TitleBar can be inside a DropArea that's inside a MDIArea
|
||||
// so we need this additional check
|
||||
return false;
|
||||
}
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -321,7 +339,7 @@ void TitleBar::onCloseClicked()
|
||||
qWarning() << Q_FUNC_INFO << "Frame with no dock widgets";
|
||||
}
|
||||
} else {
|
||||
if (m_frame->isTheOnlyFrame() && !m_frame->isInMainWindow()) {
|
||||
if (m_frame->isTheOnlyFrame() && m_frame->isInFloatingWindow()) {
|
||||
m_frame->window()->close();
|
||||
} else {
|
||||
m_frame->close();
|
||||
@@ -349,7 +367,7 @@ void TitleBar::onCloseClicked()
|
||||
bool TitleBar::isFloating() const
|
||||
{
|
||||
if (m_floatingWindow)
|
||||
return m_floatingWindow->hasSingleDockWidget(); // Debatable! Maybe it's always floating.
|
||||
return true;
|
||||
|
||||
if (m_frame)
|
||||
return m_frame->isFloating();
|
||||
@@ -393,9 +411,16 @@ void TitleBar::onFloatClicked()
|
||||
// Case 2: Multiple dockwidgets are tabbed together and floating
|
||||
// TODO: Just reuse the whole frame and put it back. The frame currently doesn't remember the position in the main window
|
||||
// so use an hack for now
|
||||
for (auto dock : qAsConst(dockWidgets)) {
|
||||
dock->setFloating(true);
|
||||
dock->setFloating(false);
|
||||
if (!dockWidgets.isEmpty()) { // could be empty during destruction, maybe
|
||||
if (!dockWidgets.constFirst()->hasPreviousDockedLocation()) {
|
||||
// Don't attempt, there's no previous docked location
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto dock : qAsConst(dockWidgets)) {
|
||||
dock->setFloating(true);
|
||||
dock->setFloating(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -474,3 +499,20 @@ bool TitleBar::isWindow() const
|
||||
{
|
||||
return m_floatingWindow != nullptr;
|
||||
}
|
||||
|
||||
TabBar *TitleBar::tabBar() const
|
||||
{
|
||||
if (m_floatingWindow && m_floatingWindow->hasSingleFrame()) {
|
||||
if (Frame *frame = m_floatingWindow->singleFrame()) {
|
||||
return frame->tabWidget()->tabBar();
|
||||
} else {
|
||||
// Shouldn't happen
|
||||
qWarning() << Q_FUNC_INFO << "Expected a frame";
|
||||
}
|
||||
|
||||
} else if (m_frame) {
|
||||
return m_frame->tabWidget()->tabBar();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace KDDockWidgets {
|
||||
class DockWidgetBase;
|
||||
class Frame;
|
||||
class Button;
|
||||
class TabBar;
|
||||
|
||||
class DOCKS_EXPORT TitleBar : public QWidgetAdapter, public Draggable
|
||||
{
|
||||
@@ -63,7 +64,7 @@ public:
|
||||
|
||||
DockWidgetBase *singleDockWidget() const override;
|
||||
|
||||
///@brief Returns true if the dock widget which has this title bar is floating
|
||||
///@brief Returns true if this title-bar is the title bar of a floating window
|
||||
bool isFloating() const;
|
||||
|
||||
///@brief the list of dockwidgets under this TitleBar.
|
||||
@@ -96,6 +97,11 @@ public:
|
||||
///@brief toggle floating
|
||||
Q_INVOKABLE bool onDoubleClicked();
|
||||
|
||||
|
||||
///@brief Returns the tab bar which is under this title bar.
|
||||
///It's only nullptr for the case of having a Floating Window with more than one nested Frame
|
||||
TabBar* tabBar() const;
|
||||
|
||||
///@brief getter for m_frame
|
||||
Frame *frame() const
|
||||
{
|
||||
@@ -112,9 +118,8 @@ public:
|
||||
///Returns nullptr otherwise
|
||||
MainWindowBase *mainWindow() const;
|
||||
|
||||
/// @brief Returns if this title bar is in a main window in MDI mode
|
||||
/// By default false. Only relevant if your main window was constructed with the
|
||||
/// MainWindowOption_MDI option
|
||||
/// @brief Returns if this title bar belongs to a dock widget which is in MDI mode (inside a MDI area)
|
||||
/// For example in a main window created with MainWindowOption_MDI option
|
||||
bool isMDI() const override;
|
||||
|
||||
/// @brief updates the close button enabled state
|
||||
|
||||
@@ -362,13 +362,25 @@ inline bool scalingFactorIsSupported(qreal factor)
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Returns the parent frame which the specified object is in, if any
|
||||
inline Frame *parentFrame(QObject *from)
|
||||
template <typename T>
|
||||
inline T* firstParentOfType(const QObject *child)
|
||||
{
|
||||
auto p = from;
|
||||
auto p = const_cast<QObject *>(child);
|
||||
while (p) {
|
||||
if (auto frame = qobject_cast<Frame *>(p))
|
||||
return frame;
|
||||
if (auto candidate = qobject_cast<T *>(p))
|
||||
return candidate;
|
||||
|
||||
if (qobject_cast<const QWindow*>(p)) {
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
if (auto w = qobject_cast<QWidget *>(p))
|
||||
if (w->isWindow())
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
@@ -376,6 +388,33 @@ inline Frame *parentFrame(QObject *from)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* lastParentOfType(const QObject *child)
|
||||
{
|
||||
auto p = const_cast<QObject *>(child);
|
||||
T* result = nullptr;
|
||||
while (p) {
|
||||
if (auto candidate = qobject_cast<T *>(p))
|
||||
result = candidate;
|
||||
|
||||
if (qobject_cast<const QWindow*>(p)) {
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
// Ignore QObject hierarchies spanning though multiple windows
|
||||
if (auto w = qobject_cast<QWidget *>(p))
|
||||
if (w->isWindow())
|
||||
return result;
|
||||
#endif
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -87,8 +87,31 @@ bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *e)
|
||||
if (!widget)
|
||||
return false;
|
||||
|
||||
if (m_isTopLevelWindowResizer && (!widget->isTopLevel() || o != mTarget))
|
||||
return false;
|
||||
if (m_isTopLevelWindowResizer) {
|
||||
if (!widget->isTopLevel() || o != mTarget)
|
||||
return false;
|
||||
} else if (isMDI()) {
|
||||
// Each Frame has a WidgetResizeHandler instance.
|
||||
// mTarget is the Frame we want to resize.
|
||||
// but 'o' might not be mTarget, because we're using a global event filter.
|
||||
// The global event filter is required because we allow the cursor to be outside the frame, a few pixels
|
||||
// so we have a nice resize margin.
|
||||
// Here we deal with the case where our mTarget, let's say "Frame 1" is on top of "Frame 2" but cursor
|
||||
// is near "Frame 2"'s margins, and would show resize cursor.
|
||||
// We only want to continue if the cursor is near the margins of our own frame (mTarget)
|
||||
|
||||
auto frame = firstParentOfType<Frame>(widget);
|
||||
if (frame && frame->isMDIWrapper()) {
|
||||
// We don't care about the inner Option_MDINestable helper frame
|
||||
frame = frame->mdiFrame();
|
||||
}
|
||||
|
||||
if (frame && frame != mTarget) {
|
||||
const bool areSiblings = frame->QWidgetAdapter::parentWidget() == mTarget->parentWidget();
|
||||
if (areSiblings)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (e->type()) {
|
||||
case QEvent::MouseButtonPress: {
|
||||
@@ -497,15 +520,20 @@ CursorPosition WidgetResizeHandler::cursorPosition(QPoint globalPos) const
|
||||
const int margin = widgetResizeHandlerMargin();
|
||||
|
||||
QFlags<CursorPosition>::Int result = CursorPosition_Undefined;
|
||||
if (qAbs(x) <= margin)
|
||||
result |= CursorPosition_Left;
|
||||
else if (qAbs(x - (mTarget->width() - margin)) <= margin)
|
||||
result |= CursorPosition_Right;
|
||||
|
||||
if (qAbs(y) <= margin)
|
||||
result |= CursorPosition_Top;
|
||||
else if (qAbs(y - (mTarget->height() - margin)) <= margin)
|
||||
result |= CursorPosition_Bottom;
|
||||
if (y >= -margin && y <= mTarget->height() + margin) {
|
||||
if (qAbs(x) <= margin)
|
||||
result |= CursorPosition_Left;
|
||||
else if (qAbs(x - (mTarget->width() - margin)) <= margin)
|
||||
result |= CursorPosition_Right;
|
||||
}
|
||||
|
||||
if (x >= -margin && x <= mTarget->width() + margin) {
|
||||
if (qAbs(y) <= margin)
|
||||
result |= CursorPosition_Top;
|
||||
else if (qAbs(y - (mTarget->height() - margin)) <= margin)
|
||||
result |= CursorPosition_Bottom;
|
||||
}
|
||||
|
||||
// Filter out sides we don't allow
|
||||
result = result & mAllowedResizeSides;
|
||||
|
||||
@@ -45,29 +45,59 @@ ClassicIndicators::~ClassicIndicators()
|
||||
delete m_indicatorWindow;
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation ClassicIndicators::hover_impl(QPoint globalPos)
|
||||
DropLocation ClassicIndicators::hover_impl(QPoint globalPos)
|
||||
{
|
||||
return m_indicatorWindow->hover(globalPos);
|
||||
}
|
||||
|
||||
QPoint ClassicIndicators::posForIndicator(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
QPoint ClassicIndicators::posForIndicator(DropLocation loc) const
|
||||
{
|
||||
return m_indicatorWindow->posForIndicator(loc);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::innerIndicatorsVisible() const
|
||||
bool ClassicIndicators::innerLeftIndicatorVisible() const
|
||||
{
|
||||
return m_innerIndicatorsVisible;
|
||||
return dropIndicatorVisible(DropLocation_Left);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::outterIndicatorsVisible() const
|
||||
bool ClassicIndicators::innerRightIndicatorVisible() const
|
||||
{
|
||||
return m_outterIndicatorsVisible;
|
||||
return dropIndicatorVisible(DropLocation_Right);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::innerTopIndicatorVisible() const
|
||||
{
|
||||
return dropIndicatorVisible(DropLocation_Top);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::innerBottomIndicatorVisible() const
|
||||
{
|
||||
return dropIndicatorVisible(DropLocation_Bottom);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::outterLeftIndicatorVisible() const
|
||||
{
|
||||
return dropIndicatorVisible(DropLocation_OutterLeft);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::outterRightIndicatorVisible() const
|
||||
{
|
||||
return dropIndicatorVisible(DropLocation_OutterRight);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::outterTopIndicatorVisible() const
|
||||
{
|
||||
return dropIndicatorVisible(DropLocation_OutterTop);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::outterBottomIndicatorVisible() const
|
||||
{
|
||||
return dropIndicatorVisible(DropLocation_OutterBottom);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::tabIndicatorVisible() const
|
||||
{
|
||||
return m_tabIndicatorVisible;
|
||||
return dropIndicatorVisible(DropLocation_Center);
|
||||
}
|
||||
|
||||
bool ClassicIndicators::onResize(QSize)
|
||||
@@ -82,40 +112,13 @@ void ClassicIndicators::updateVisibility()
|
||||
m_indicatorWindow->updatePositions();
|
||||
m_indicatorWindow->setVisible(true);
|
||||
updateWindowPosition();
|
||||
updateIndicatorsVisibility(true);
|
||||
raiseIndicators();
|
||||
} else {
|
||||
m_rubberBand->setVisible(false);
|
||||
m_indicatorWindow->setVisible(false);
|
||||
updateIndicatorsVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicIndicators::updateIndicatorsVisibility(bool visible)
|
||||
{
|
||||
const bool isTheOnlyFrame = m_hoveredFrame && m_hoveredFrame->isTheOnlyFrame();
|
||||
|
||||
m_innerIndicatorsVisible = visible && m_hoveredFrame;
|
||||
|
||||
WindowBeingDragged *windowBeingDragged = DragController::instance()->windowBeingDragged();
|
||||
|
||||
// If there's only 1 frame in the layout, the outer indicators are redundant, as they do the same thing as the internal ones.
|
||||
// But there might be another window obscuring our target, so it's useful to show the outer indicators in this case
|
||||
m_outterIndicatorsVisible = visible && (!isTheOnlyFrame || DockRegistry::self()->isProbablyObscured(m_hoveredFrame->window()->windowHandle(), windowBeingDragged));
|
||||
|
||||
|
||||
// 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_hoveredFrame->isDockable();
|
||||
if (m_tabIndicatorVisible && tabbingAllowedFunc) {
|
||||
const DockWidgetBase::List source = windowBeingDragged->dockWidgets();
|
||||
const DockWidgetBase::List target = m_hoveredFrame->dockWidgets();
|
||||
m_tabIndicatorVisible = tabbingAllowedFunc(source, target);
|
||||
}
|
||||
|
||||
Q_EMIT innerIndicatorsVisibleChanged();
|
||||
Q_EMIT outterIndicatorsVisibleChanged();
|
||||
Q_EMIT tabIndicatorVisibleChanged();
|
||||
Q_EMIT indicatorsVisibleChanged();
|
||||
}
|
||||
|
||||
void ClassicIndicators::raiseIndicators()
|
||||
@@ -123,31 +126,31 @@ void ClassicIndicators::raiseIndicators()
|
||||
m_indicatorWindow->raise();
|
||||
}
|
||||
|
||||
KDDockWidgets::Location locationToMultisplitterLocation(ClassicIndicators::DropLocation location)
|
||||
KDDockWidgets::Location locationToMultisplitterLocation(DropLocation location)
|
||||
{
|
||||
switch (location) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
case DropLocation_Left:
|
||||
return KDDockWidgets::Location_OnLeft;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
case DropLocation_Top:
|
||||
return KDDockWidgets::Location_OnTop;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
case DropLocation_Right:
|
||||
return KDDockWidgets::Location_OnRight;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
case DropLocation_Bottom:
|
||||
return KDDockWidgets::Location_OnBottom;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
case DropLocation_OutterLeft:
|
||||
return KDDockWidgets::Location_OnLeft;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
case DropLocation_OutterTop:
|
||||
return KDDockWidgets::Location_OnTop;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
case DropLocation_OutterRight:
|
||||
return KDDockWidgets::Location_OnRight;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
case DropLocation_OutterBottom:
|
||||
return KDDockWidgets::Location_OnBottom;
|
||||
default:
|
||||
return KDDockWidgets::Location_None;
|
||||
}
|
||||
}
|
||||
|
||||
void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location)
|
||||
void ClassicIndicators::setDropLocation(DropLocation location)
|
||||
{
|
||||
setCurrentDropLocation(location);
|
||||
|
||||
|
||||
@@ -17,41 +17,43 @@ using namespace KDDockWidgets;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
static QString iconName(DropIndicatorOverlayInterface::DropLocation loc, bool active)
|
||||
static QString iconName(DropLocation loc, bool active)
|
||||
{
|
||||
QString suffix = active ? QStringLiteral("_active")
|
||||
: QString();
|
||||
|
||||
QString name;
|
||||
switch (loc) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
case DropLocation_Center:
|
||||
name = QStringLiteral("center");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
case DropLocation_Left:
|
||||
name = QStringLiteral("inner_left");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
case DropLocation_Right:
|
||||
name = QStringLiteral("inner_right");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
case DropLocation_Bottom:
|
||||
name = QStringLiteral("inner_bottom");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
case DropLocation_Top:
|
||||
name = QStringLiteral("inner_top");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
case DropLocation_OutterLeft:
|
||||
name = QStringLiteral("outter_left");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
case DropLocation_OutterBottom:
|
||||
name = QStringLiteral("outter_bottom");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
case DropLocation_OutterRight:
|
||||
name = QStringLiteral("outter_right");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
case DropLocation_OutterTop:
|
||||
name = QStringLiteral("outter_top");
|
||||
break;
|
||||
case DropIndicatorOverlayInterface::DropLocation_None:
|
||||
case DropLocation_None:
|
||||
case DropLocation_Inner:
|
||||
case DropLocation_Outter:
|
||||
return QString();
|
||||
}
|
||||
|
||||
@@ -83,7 +85,7 @@ void Indicator::setHovered(bool hovered)
|
||||
if (hovered) {
|
||||
q->setDropLocation(m_dropLocation);
|
||||
} else if (q->currentDropLocation() == m_dropLocation) {
|
||||
q->setDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
|
||||
q->setDropLocation(DropLocation_None);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,15 +119,15 @@ static Qt::WindowFlags flagsForIndicatorWindow()
|
||||
IndicatorWindow::IndicatorWindow(ClassicIndicators *classicIndicators_)
|
||||
: QWidget(parentForIndicatorWindow(classicIndicators_), flagsForIndicatorWindow())
|
||||
, classicIndicators(classicIndicators_)
|
||||
, m_center(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Center)) // Each indicator is not a top-level. Otherwise there's noticeable delay.
|
||||
, m_left(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Left))
|
||||
, m_right(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Right))
|
||||
, m_bottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Bottom))
|
||||
, m_top(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Top))
|
||||
, m_outterLeft(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterLeft))
|
||||
, m_outterRight(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterRight))
|
||||
, m_outterBottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterBottom))
|
||||
, m_outterTop(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterTop))
|
||||
, m_center(new Indicator(classicIndicators, this, DropLocation_Center)) // Each indicator is not a top-level. Otherwise there's noticeable delay.
|
||||
, m_left(new Indicator(classicIndicators, this, DropLocation_Left))
|
||||
, m_right(new Indicator(classicIndicators, this, DropLocation_Right))
|
||||
, m_bottom(new Indicator(classicIndicators, this, DropLocation_Bottom))
|
||||
, m_top(new Indicator(classicIndicators, this, DropLocation_Top))
|
||||
, m_outterLeft(new Indicator(classicIndicators, this, DropLocation_OutterLeft))
|
||||
, m_outterRight(new Indicator(classicIndicators, this, DropLocation_OutterRight))
|
||||
, m_outterBottom(new Indicator(classicIndicators, this, DropLocation_OutterBottom))
|
||||
, m_outterTop(new Indicator(classicIndicators, this, DropLocation_OutterTop))
|
||||
{
|
||||
setWindowFlag(Qt::FramelessWindowHint, true);
|
||||
|
||||
@@ -136,37 +138,39 @@ IndicatorWindow::IndicatorWindow(ClassicIndicators *classicIndicators_)
|
||||
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
connect(classicIndicators, &ClassicIndicators::innerIndicatorsVisibleChanged,
|
||||
connect(classicIndicators, &ClassicIndicators::indicatorsVisibleChanged,
|
||||
this, &IndicatorWindow::updateIndicatorVisibility);
|
||||
connect(classicIndicators, &ClassicIndicators::outterIndicatorsVisibleChanged,
|
||||
connect(classicIndicators, &ClassicIndicators::indicatorsVisibleChanged,
|
||||
this, &IndicatorWindow::updateIndicatorVisibility);
|
||||
|
||||
m_indicators << m_center << m_left << m_right << m_top << m_bottom
|
||||
<< m_outterBottom << m_outterTop << m_outterLeft << m_outterRight;
|
||||
}
|
||||
|
||||
Indicator *IndicatorWindow::indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
Indicator *IndicatorWindow::indicatorForLocation(DropLocation loc) const
|
||||
{
|
||||
switch (loc) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Center:
|
||||
case DropLocation_Center:
|
||||
return m_center;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
case DropLocation_Left:
|
||||
return m_left;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Right:
|
||||
case DropLocation_Right:
|
||||
return m_right;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Bottom:
|
||||
case DropLocation_Bottom:
|
||||
return m_bottom;
|
||||
case DropIndicatorOverlayInterface::DropLocation_Top:
|
||||
case DropLocation_Top:
|
||||
return m_top;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
|
||||
case DropLocation_OutterLeft:
|
||||
return m_outterLeft;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
|
||||
case DropLocation_OutterBottom:
|
||||
return m_outterBottom;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
|
||||
case DropLocation_OutterRight:
|
||||
return m_outterRight;
|
||||
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
|
||||
case DropLocation_OutterTop:
|
||||
return m_outterTop;
|
||||
case DropIndicatorOverlayInterface::DropLocation_None:
|
||||
case DropLocation_None:
|
||||
case DropLocation_Outter:
|
||||
case DropLocation_Inner:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -195,26 +199,23 @@ void IndicatorWindow::resizeEvent(QResizeEvent *ev)
|
||||
|
||||
void IndicatorWindow::updateIndicatorVisibility()
|
||||
{
|
||||
for (Indicator *indicator : { m_left, m_right, m_bottom, m_top })
|
||||
indicator->setVisible(classicIndicators->innerIndicatorsVisible());
|
||||
|
||||
for (Indicator *indicator : { m_outterTop, m_outterLeft, m_outterRight, m_outterBottom })
|
||||
indicator->setVisible(classicIndicators->outterIndicatorsVisible());
|
||||
|
||||
m_center->setVisible(classicIndicators->tabIndicatorVisible());
|
||||
for (Indicator *indicator : { m_left, m_right, m_bottom, m_top,
|
||||
m_outterTop, m_outterLeft, m_outterRight, m_outterBottom,
|
||||
m_center })
|
||||
indicator->setVisible(classicIndicators->dropIndicatorVisible(indicator->m_dropLocation));
|
||||
|
||||
updateMask();
|
||||
}
|
||||
|
||||
QPoint IndicatorWindow::posForIndicator(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
QPoint IndicatorWindow::posForIndicator(DropLocation loc) const
|
||||
{
|
||||
Indicator *indicator = indicatorForLocation(loc);
|
||||
return indicator->mapToGlobal(indicator->rect().center());
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation IndicatorWindow::hover(QPoint globalPos)
|
||||
DropLocation IndicatorWindow::hover(QPoint globalPos)
|
||||
{
|
||||
DropIndicatorOverlayInterface::DropLocation loc = DropIndicatorOverlayInterface::DropLocation_None;
|
||||
DropLocation loc = DropLocation_None;
|
||||
|
||||
for (Indicator *indicator : qAsConst(m_indicators)) {
|
||||
if (indicator->isVisible()) {
|
||||
@@ -249,7 +250,7 @@ void IndicatorWindow::updatePositions()
|
||||
}
|
||||
}
|
||||
|
||||
Indicator::Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent, ClassicIndicators::DropLocation location)
|
||||
Indicator::Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent, DropLocation location)
|
||||
: QWidget(parent)
|
||||
, q(classicIndicators)
|
||||
, m_dropLocation(location)
|
||||
@@ -295,11 +296,11 @@ IndicatorWindow::IndicatorWindow(KDDockWidgets::ClassicIndicators *classicIndica
|
||||
}
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation IndicatorWindow::hover(QPoint pt)
|
||||
DropLocation IndicatorWindow::hover(QPoint pt)
|
||||
{
|
||||
QQuickItem *item = indicatorForPos(pt);
|
||||
const DropIndicatorOverlayInterface::DropLocation loc = item ? locationForIndicator(item)
|
||||
: DropIndicatorOverlayInterface::DropLocation_None;
|
||||
const DropLocation loc = item ? locationForIndicator(item)
|
||||
: DropLocation_None;
|
||||
classicIndicators()->setDropLocation(loc);
|
||||
return loc;
|
||||
}
|
||||
@@ -327,7 +328,7 @@ void IndicatorWindow::updatePositions()
|
||||
// Not needed to implement, the Indicators use QML anchors
|
||||
}
|
||||
|
||||
QPoint IndicatorWindow::posForIndicator(KDDockWidgets::DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
QPoint IndicatorWindow::posForIndicator(KDDockWidgets::DropLocation loc) const
|
||||
{
|
||||
QQuickItem *indicator = IndicatorWindow::indicatorForLocation(loc);
|
||||
return indicator->mapToGlobal(indicator->boundingRect().center()).toPoint();
|
||||
@@ -335,7 +336,7 @@ QPoint IndicatorWindow::posForIndicator(KDDockWidgets::DropIndicatorOverlayInter
|
||||
|
||||
QString IndicatorWindow::iconName(int loc, bool active) const
|
||||
{
|
||||
return KDDockWidgets::iconName(DropIndicatorOverlayInterface::DropLocation(loc), active);
|
||||
return KDDockWidgets::iconName(DropLocation(loc), active);
|
||||
}
|
||||
|
||||
ClassicIndicators *IndicatorWindow::classicIndicators() const
|
||||
@@ -343,7 +344,7 @@ ClassicIndicators *IndicatorWindow::classicIndicators() const
|
||||
return m_classicIndicators;
|
||||
}
|
||||
|
||||
QQuickItem *IndicatorWindow::indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
QQuickItem *IndicatorWindow::indicatorForLocation(DropLocation loc) const
|
||||
{
|
||||
const QVector<QQuickItem *> indicators = indicatorItems();
|
||||
Q_ASSERT(indicators.size() == 9);
|
||||
@@ -357,9 +358,9 @@ QQuickItem *IndicatorWindow::indicatorForLocation(DropIndicatorOverlayInterface:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation IndicatorWindow::locationForIndicator(const QQuickItem *item) const
|
||||
DropLocation IndicatorWindow::locationForIndicator(const QQuickItem *item) const
|
||||
{
|
||||
return DropIndicatorOverlayInterface::DropLocation(item->property("indicatorType").toInt());
|
||||
return DropLocation(item->property("indicatorType").toInt());
|
||||
}
|
||||
|
||||
QVector<QQuickItem *> IndicatorWindow::indicatorItems() const
|
||||
|
||||
@@ -31,9 +31,9 @@ class IndicatorWindow : public QWidget
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IndicatorWindow(ClassicIndicators *classicIndicators);
|
||||
DropIndicatorOverlayInterface::DropLocation hover(QPoint globalPos);
|
||||
DropLocation hover(QPoint globalPos);
|
||||
void updatePositions();
|
||||
QPoint posForIndicator(DropIndicatorOverlayInterface::DropLocation) const;
|
||||
QPoint posForIndicator(DropLocation) const;
|
||||
|
||||
private:
|
||||
void updateIndicatorVisibility();
|
||||
@@ -43,7 +43,7 @@ private:
|
||||
// Only happens on Linux
|
||||
void updateMask();
|
||||
|
||||
Indicator *indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const;
|
||||
Indicator *indicatorForLocation(DropLocation loc) const;
|
||||
|
||||
ClassicIndicators *const classicIndicators;
|
||||
Indicator *const m_center;
|
||||
@@ -64,7 +64,7 @@ class Indicator : public QWidget
|
||||
public:
|
||||
typedef QList<Indicator *> List;
|
||||
explicit Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent,
|
||||
DropIndicatorOverlayInterface::DropLocation location);
|
||||
DropLocation location);
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
void setHovered(bool hovered);
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
QImage m_imageActive;
|
||||
ClassicIndicators *const q;
|
||||
bool m_hovered = false;
|
||||
const DropIndicatorOverlayInterface::DropLocation m_dropLocation;
|
||||
const DropLocation m_dropLocation;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -92,15 +92,15 @@ class IndicatorWindow : public QQuickView
|
||||
Q_PROPERTY(KDDockWidgets::ClassicIndicators *classicIndicators READ classicIndicators CONSTANT)
|
||||
public:
|
||||
explicit IndicatorWindow(ClassicIndicators *);
|
||||
DropIndicatorOverlayInterface::DropLocation hover(QPoint);
|
||||
DropLocation hover(QPoint);
|
||||
void updatePositions();
|
||||
QPoint posForIndicator(DropIndicatorOverlayInterface::DropLocation) const;
|
||||
QPoint posForIndicator(DropLocation) const;
|
||||
Q_INVOKABLE QString iconName(int loc, bool active) const;
|
||||
KDDockWidgets::ClassicIndicators *classicIndicators() const;
|
||||
QQuickItem *indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const;
|
||||
QQuickItem *indicatorForLocation(DropLocation loc) const;
|
||||
|
||||
private:
|
||||
DropIndicatorOverlayInterface::DropLocation locationForIndicator(const QQuickItem *) const;
|
||||
DropLocation locationForIndicator(const QQuickItem *) const;
|
||||
QQuickItem *indicatorForPos(QPoint) const;
|
||||
QVector<QQuickItem *> indicatorItems() const;
|
||||
ClassicIndicators *const m_classicIndicators;
|
||||
|
||||
@@ -23,9 +23,18 @@ class DOCKS_EXPORT ClassicIndicators : public DropIndicatorOverlayInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool innerIndicatorsVisible READ innerIndicatorsVisible NOTIFY innerIndicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool outterIndicatorsVisible READ outterIndicatorsVisible NOTIFY outterIndicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool tabIndicatorVisible READ tabIndicatorVisible NOTIFY tabIndicatorVisibleChanged)
|
||||
// Properties for QML
|
||||
Q_PROPERTY(bool innerLeftIndicatorVisible READ innerLeftIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool innerRightIndicatorVisible READ innerRightIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool innerTopIndicatorVisible READ innerTopIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool innerBottomIndicatorVisible READ innerBottomIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
|
||||
Q_PROPERTY(bool outterLeftIndicatorVisible READ outterLeftIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool outterRightIndicatorVisible READ outterRightIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool outterTopIndicatorVisible READ outterTopIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
Q_PROPERTY(bool outterBottomIndicatorVisible READ outterBottomIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
|
||||
Q_PROPERTY(bool tabIndicatorVisible READ tabIndicatorVisible NOTIFY indicatorsVisibleChanged)
|
||||
|
||||
public:
|
||||
explicit ClassicIndicators(DropArea *dropArea);
|
||||
@@ -33,33 +42,32 @@ public:
|
||||
DropLocation hover_impl(QPoint globalPos) override;
|
||||
QPoint posForIndicator(DropLocation) const override;
|
||||
|
||||
bool innerIndicatorsVisible() const;
|
||||
bool outterIndicatorsVisible() const;
|
||||
|
||||
// The tab/center indicator
|
||||
// Lots of getters needed because of QML:
|
||||
bool innerLeftIndicatorVisible() const;
|
||||
bool innerRightIndicatorVisible() const;
|
||||
bool innerTopIndicatorVisible() const;
|
||||
bool innerBottomIndicatorVisible() const;
|
||||
bool outterLeftIndicatorVisible() const;
|
||||
bool outterRightIndicatorVisible() const;
|
||||
bool outterTopIndicatorVisible() const;
|
||||
bool outterBottomIndicatorVisible() const;
|
||||
bool tabIndicatorVisible() const;
|
||||
|
||||
protected:
|
||||
bool onResize(QSize newSize) override;
|
||||
void updateVisibility() override;
|
||||
Q_SIGNALS:
|
||||
void innerIndicatorsVisibleChanged();
|
||||
void outterIndicatorsVisibleChanged();
|
||||
void tabIndicatorVisibleChanged();
|
||||
void indicatorsVisibleChanged();
|
||||
|
||||
private:
|
||||
friend class KDDockWidgets::Indicator;
|
||||
friend class KDDockWidgets::IndicatorWindow;
|
||||
bool rubberBandIsTopLevel() const;
|
||||
void updateIndicatorsVisibility(bool visible);
|
||||
void raiseIndicators();
|
||||
QRect geometryForRubberband(QRect localRect) const;
|
||||
void setDropLocation(DropLocation);
|
||||
void updateWindowPosition();
|
||||
|
||||
bool m_innerIndicatorsVisible = false;
|
||||
bool m_outterIndicatorsVisible = false;
|
||||
bool m_tabIndicatorVisible = false;
|
||||
QWidgetOrQuick *const m_rubberBand;
|
||||
IndicatorWindow *const m_indicatorWindow;
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ class DOCKS_EXPORT NullIndicators : public DropIndicatorOverlayInterface
|
||||
public:
|
||||
explicit NullIndicators(DropArea *);
|
||||
~NullIndicators() override;
|
||||
DropIndicatorOverlayInterface::DropLocation hover_impl(QPoint) override
|
||||
DropLocation hover_impl(QPoint) override
|
||||
{
|
||||
return {};
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ SegmentedIndicators::~SegmentedIndicators()
|
||||
{
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation SegmentedIndicators::hover_impl(QPoint pt)
|
||||
DropLocation SegmentedIndicators::hover_impl(QPoint pt)
|
||||
{
|
||||
m_hoveredPt = mapFromGlobal(pt);
|
||||
updateSegments();
|
||||
@@ -51,7 +51,7 @@ DropIndicatorOverlayInterface::DropLocation SegmentedIndicators::hover_impl(QPoi
|
||||
return currentDropLocation();
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation SegmentedIndicators::dropLocationForPos(QPoint pos) const
|
||||
DropLocation SegmentedIndicators::dropLocationForPos(QPoint pos) const
|
||||
{
|
||||
for (auto it = m_segments.cbegin(), end = m_segments.cend(); it != end; ++it) {
|
||||
if (it.value().containsPoint(pos, Qt::OddEvenFill)) {
|
||||
@@ -69,7 +69,7 @@ void SegmentedIndicators::paintEvent(QPaintEvent *)
|
||||
drawSegments(&p);
|
||||
}
|
||||
|
||||
QVector<QPolygon> SegmentedIndicators::segmentsForRect(QRect r, QPolygon ¢er, bool useOffset) const
|
||||
QHash<DropLocation, QPolygon> SegmentedIndicators::segmentsForRect(QRect r, bool inner, bool useOffset) const
|
||||
{
|
||||
const int halfPenWidth = s_segmentPenWidth / 2;
|
||||
|
||||
@@ -99,8 +99,7 @@ QVector<QPolygon> SegmentedIndicators::segmentsForRect(QRect r, QPolygon ¢er
|
||||
bottomRight + QPoint(-l, -l),
|
||||
bottomLeft + QPoint(l, -l) };
|
||||
|
||||
{
|
||||
|
||||
if (inner) {
|
||||
QPolygon bounds = QVector<QPoint> { topLeft + QPoint(l, l),
|
||||
topRight + QPoint(-l, l),
|
||||
bottomRight + QPoint(-l, -l),
|
||||
@@ -119,7 +118,7 @@ QVector<QPolygon> SegmentedIndicators::segmentsForRect(QRect r, QPolygon ¢er
|
||||
const int centerRectTop = centerPos.y() - indicatorHeight / 2;
|
||||
|
||||
|
||||
center = QVector<QPoint> {
|
||||
const auto center = QVector<QPoint> {
|
||||
{ centerRectLeft, centerRectTop },
|
||||
{ centerRectLeft + tabWidth, centerRectTop },
|
||||
{ centerRectLeft + tabWidth, centerRectTop + tabHeight },
|
||||
@@ -127,34 +126,39 @@ QVector<QPolygon> SegmentedIndicators::segmentsForRect(QRect r, QPolygon ¢er
|
||||
{ centerRectRight, centerRectBottom },
|
||||
{ centerRectLeft, centerRectBottom },
|
||||
};
|
||||
}
|
||||
|
||||
return { leftPoints, topPoints, rightPoints, bottomPoints };
|
||||
return {
|
||||
{ DropLocation_Left, leftPoints },
|
||||
{ DropLocation_Top, topPoints },
|
||||
{ DropLocation_Right, rightPoints },
|
||||
{ DropLocation_Bottom, bottomPoints },
|
||||
{ DropLocation_Center, center }
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
{ DropLocation_OutterLeft, leftPoints },
|
||||
{ DropLocation_OutterTop, topPoints },
|
||||
{ DropLocation_OutterRight, rightPoints },
|
||||
{ DropLocation_OutterBottom, bottomPoints }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void SegmentedIndicators::updateSegments()
|
||||
{
|
||||
m_segments.clear();
|
||||
|
||||
const bool hasMultipleFrames = m_dropArea->visibleCount() > 1;
|
||||
const bool needsOutterIndicators = true; // Can't think of a reason not to show them
|
||||
const bool needsInnerIndicators = needsOutterIndicators && hasMultipleFrames && hoveredFrameRect().isValid();
|
||||
|
||||
QPolygon center;
|
||||
const bool needsOutterIndicators = dropIndicatorVisible(DropLocation_Outter);
|
||||
const bool needsInnerIndicators = dropIndicatorVisible(DropLocation_Inner);
|
||||
|
||||
if (needsInnerIndicators) {
|
||||
const bool useOffset = needsOutterIndicators;
|
||||
auto segments = segmentsForRect(hoveredFrameRect(), /*by-ref*/ center, useOffset);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
m_segments.insert(DropLocation(DropLocation_Left + i), segments[i]);
|
||||
|
||||
m_segments.insert(DropLocation_Center, center);
|
||||
m_segments = segmentsForRect(hoveredFrameRect(), /*inner=*/true, useOffset);
|
||||
}
|
||||
|
||||
if (needsOutterIndicators) {
|
||||
auto segments = segmentsForRect(rect(), /*unused*/ center);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
m_segments.insert(DropLocation(DropLocation_OutterLeft + i), segments[i]);
|
||||
auto segments = segmentsForRect(rect(), /*inner=*/false);
|
||||
m_segments.insert(segments);
|
||||
}
|
||||
|
||||
update();
|
||||
@@ -162,8 +166,16 @@ void SegmentedIndicators::updateSegments()
|
||||
|
||||
void SegmentedIndicators::drawSegments(QPainter *p)
|
||||
{
|
||||
for (int i = DropLocation_First; i <= DropLocation_Last; ++i)
|
||||
drawSegment(p, m_segments.value(DropLocation(i)));
|
||||
for (DropLocation loc : { DropLocation_Left,
|
||||
DropLocation_Top,
|
||||
DropLocation_Right,
|
||||
DropLocation_Bottom,
|
||||
DropLocation_Center,
|
||||
DropLocation_OutterLeft,
|
||||
DropLocation_OutterTop,
|
||||
DropLocation_OutterRight,
|
||||
DropLocation_OutterBottom })
|
||||
drawSegment(p, m_segments.value(loc));
|
||||
}
|
||||
|
||||
void SegmentedIndicators::drawSegment(QPainter *p, const QPolygon &segment)
|
||||
@@ -183,7 +195,7 @@ void SegmentedIndicators::drawSegment(QPainter *p, const QPolygon &segment)
|
||||
p->drawPolygon(segment);
|
||||
}
|
||||
|
||||
QPoint KDDockWidgets::SegmentedIndicators::posForIndicator(DropIndicatorOverlayInterface::DropLocation) const
|
||||
QPoint KDDockWidgets::SegmentedIndicators::posForIndicator(DropLocation) const
|
||||
{
|
||||
/// Doesn't apply to segmented indicators, completely different concept
|
||||
return {};
|
||||
|
||||
@@ -25,7 +25,7 @@ class DOCKS_EXPORT SegmentedIndicators : public DropIndicatorOverlayInterface
|
||||
public:
|
||||
explicit SegmentedIndicators(DropArea *dropArea);
|
||||
~SegmentedIndicators() override;
|
||||
DropIndicatorOverlayInterface::DropLocation hover_impl(QPoint globalPos) override;
|
||||
DropLocation hover_impl(QPoint globalPos) override;
|
||||
|
||||
DropLocation dropLocationForPos(QPoint pos) const;
|
||||
|
||||
@@ -42,7 +42,7 @@ protected:
|
||||
QPoint posForIndicator(DropLocation) const override;
|
||||
|
||||
private:
|
||||
QVector<QPolygon> segmentsForRect(QRect, QPolygon ¢er, bool useOffset = false) const;
|
||||
QHash<DropLocation, QPolygon> segmentsForRect(QRect, bool inner, bool useOffset = false) const;
|
||||
void updateSegments();
|
||||
void drawSegments(QPainter *p);
|
||||
void drawSegment(QPainter *p, const QPolygon &segment);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <QTimer>
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef Q_CC_MSVC
|
||||
#pragma warning(push)
|
||||
@@ -2896,7 +2897,10 @@ QVector<int> ItemBoxContainer::calculateSqueezes(SizingInfo::List::ConstIterator
|
||||
|
||||
const auto count = availabilities.count();
|
||||
|
||||
QVector<int> squeezes(count, 0);
|
||||
QVector<int> squeezes;
|
||||
squeezes.resize(count);
|
||||
std::fill(squeezes.begin(), squeezes.end(), 0);
|
||||
|
||||
int missing = needed;
|
||||
|
||||
if (strategy == NeighbourSqueezeStrategy::AllNeighbours) {
|
||||
|
||||
@@ -14,9 +14,14 @@
|
||||
#include "Logging_p.h"
|
||||
#include "Item_p.h"
|
||||
#include "MultiSplitterConfig.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
# include <QWidget>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
@@ -25,6 +30,15 @@ using namespace Layouting;
|
||||
|
||||
Separator *Separator::s_separatorBeingDragged = nullptr;
|
||||
|
||||
namespace {
|
||||
|
||||
bool rubberBandIsTopLevel()
|
||||
{
|
||||
return KDDockWidgets::Config::self().internalFlags() & KDDockWidgets::Config::InternalFlag_TopLevelIndicatorRubberBand;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @brief internal counter just for unit-tests
|
||||
static int s_numSeparators = 0;
|
||||
|
||||
@@ -94,6 +108,10 @@ void Separator::onMousePress()
|
||||
if (d->lazyResizeRubberBand) {
|
||||
setLazyPosition(position());
|
||||
d->lazyResizeRubberBand->show();
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
if (rubberBandIsTopLevel())
|
||||
d->lazyResizeRubberBand->asQWidget()->raise();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +209,8 @@ void Separator::init(ItemBoxContainer *parentContainer, Qt::Orientation orientat
|
||||
|
||||
d->parentContainer = parentContainer;
|
||||
d->orientation = orientation;
|
||||
d->lazyResizeRubberBand = d->usesLazyResize ? createRubberBand(d->m_hostWidget)
|
||||
: nullptr;
|
||||
d->lazyResizeRubberBand = d->usesLazyResize ? createRubberBand(rubberBandIsTopLevel() ? nullptr : d->m_hostWidget)
|
||||
: nullptr;
|
||||
asWidget()->setVisible(true);
|
||||
}
|
||||
|
||||
@@ -238,7 +256,10 @@ void Separator::setLazyPosition(int pos)
|
||||
} else {
|
||||
geo.moveLeft(pos);
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
if (rubberBandIsTopLevel())
|
||||
geo.translate(d->m_hostWidget->asQWidget()->mapToGlobal(QPoint(0, 0)));
|
||||
#endif
|
||||
d->lazyResizeRubberBand->setGeometry(geo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,11 +87,6 @@ void SeparatorWidget::mouseDoubleClickEvent(QMouseEvent *)
|
||||
|
||||
Layouting::Widget *SeparatorWidget::createRubberBand(Layouting::Widget *parent)
|
||||
{
|
||||
if (!parent) {
|
||||
qWarning() << Q_FUNC_INFO << "Parent is required";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new Layouting::Widget_qwidget(new RubberBand(parent));
|
||||
}
|
||||
|
||||
|
||||
@@ -46,3 +46,9 @@ QSize Widget::boundedMaxSize(QSize min, QSize max)
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/** static */
|
||||
QSize Widget::hardcodedMinimumSize()
|
||||
{
|
||||
return Item::hardcodedMinimumSize;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "Item_p.h"
|
||||
|
||||
#include <QRect>
|
||||
#include <QSize>
|
||||
@@ -148,6 +147,8 @@ public:
|
||||
///@brief returns an id for corelation purposes for saving layouts
|
||||
QString id() const;
|
||||
|
||||
static QSize hardcodedMinimumSize();
|
||||
|
||||
template<typename T>
|
||||
static QSize widgetMinSize(const T *w)
|
||||
{
|
||||
@@ -157,7 +158,7 @@ public:
|
||||
const int minH = w->minimumHeight() > 0 ? w->minimumHeight()
|
||||
: w->minimumSizeHint().height();
|
||||
|
||||
return QSize(minW, minH).expandedTo(Item::hardcodedMinimumSize);
|
||||
return QSize(minW, minH).expandedTo(hardcodedMinimumSize());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "Widget_quick.h"
|
||||
#include "Item_p.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QQmlEngine>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "../DockRegistry_p.h"
|
||||
#include "../Utils_p.h"
|
||||
#include "../FloatingWindow_p.h"
|
||||
#include "../multisplitter/Item_p.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
#include <QMouseEvent>
|
||||
@@ -33,6 +34,8 @@
|
||||
#include <QQuickView>
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
#include <qpa/qplatformwindow.h>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
@@ -138,6 +141,8 @@ QWidgetAdapter::QWidgetAdapter(QQuickItem *parent, Qt::WindowFlags flags)
|
||||
}
|
||||
});
|
||||
|
||||
qApp->installEventFilter(this);
|
||||
|
||||
setSize(QSize(800, 800));
|
||||
}
|
||||
|
||||
@@ -178,6 +183,14 @@ void QWidgetAdapter::onMouseRelease()
|
||||
void QWidgetAdapter::onCloseEvent(QCloseEvent *)
|
||||
{
|
||||
}
|
||||
void QWidgetAdapter::onResizeEvent(QResizeEvent *)
|
||||
{
|
||||
updateNormalGeometry();
|
||||
}
|
||||
void QWidgetAdapter::onMoveEvent(QMoveEvent *)
|
||||
{
|
||||
updateNormalGeometry();
|
||||
}
|
||||
|
||||
void QWidgetAdapter::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
|
||||
{
|
||||
@@ -207,6 +220,27 @@ void QWidgetAdapter::itemChange(QQuickItem::ItemChange change, const QQuickItem:
|
||||
}
|
||||
}
|
||||
|
||||
void QWidgetAdapter::updateNormalGeometry()
|
||||
{
|
||||
QWindow *window = windowHandle();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
QRect normalGeometry;
|
||||
if (const QPlatformWindow *pw = window->handle()) {
|
||||
normalGeometry = pw->normalGeometry();
|
||||
}
|
||||
|
||||
if (!normalGeometry.isValid() && isNormalWindowState(window->windowState())) {
|
||||
normalGeometry = window->geometry();
|
||||
}
|
||||
|
||||
if (normalGeometry.isValid()) {
|
||||
setNormalGeometry(normalGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
void QWidgetAdapter::QQUICKITEMgeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
||||
{
|
||||
// Send a few events manually, since QQuickItem doesn't do it for us.
|
||||
@@ -300,23 +334,12 @@ QRect QWidgetAdapter::geometry() const
|
||||
|
||||
QRect QWidgetAdapter::normalGeometry() const
|
||||
{
|
||||
// TODO: There's no such concept in QWindow, do we need to workaround for QtQuick ?
|
||||
return QWidgetAdapter::geometry();
|
||||
return m_normalGeometry;
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setNormalGeometry(QRect geo)
|
||||
{
|
||||
if (!isTopLevel())
|
||||
return;
|
||||
|
||||
if (QWindow *w = windowHandle()) {
|
||||
if (isNormalWindowState(w->windowStates())) {
|
||||
w->setGeometry(geo);
|
||||
} else {
|
||||
// Nothing better at this point, as QWindow doesn't have this concept
|
||||
qDebug() << Q_FUNC_INFO << "TODO";
|
||||
}
|
||||
}
|
||||
m_normalGeometry = geo;
|
||||
}
|
||||
|
||||
QRect QWidgetAdapter::rect() const
|
||||
@@ -749,6 +772,12 @@ bool QWidgetAdapter::eventFilter(QObject *watched, QEvent *ev)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->type() == QEvent::Resize) {
|
||||
onResizeEvent(static_cast<QResizeEvent *>(ev));
|
||||
} else if (ev->type() == QEvent::Move) {
|
||||
onMoveEvent(static_cast<QMoveEvent *>(ev));
|
||||
}
|
||||
}
|
||||
|
||||
return QQuickItem::eventFilter(watched, ev);
|
||||
|
||||
@@ -251,9 +251,13 @@ protected:
|
||||
virtual void onMouseMove(QPoint globalPos);
|
||||
virtual void onMouseRelease();
|
||||
virtual void onCloseEvent(QCloseEvent *);
|
||||
virtual void onResizeEvent(QResizeEvent *);
|
||||
virtual void onMoveEvent(QMoveEvent *);
|
||||
void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &) override;
|
||||
|
||||
private:
|
||||
void updateNormalGeometry();
|
||||
|
||||
QSize m_sizeHint;
|
||||
QSizePolicy m_sizePolicy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
;
|
||||
@@ -265,6 +269,7 @@ private:
|
||||
bool m_isWrapper = false;
|
||||
bool m_inSetParent = false;
|
||||
MouseEventRedirector *m_mouseEventRedirector = nullptr;
|
||||
QRect m_normalGeometry;
|
||||
};
|
||||
|
||||
inline qreal logicalDpiFactor(const QQuickItem *item)
|
||||
|
||||
@@ -15,7 +15,7 @@ import com.kdab.dockwidgets 1.0
|
||||
Image {
|
||||
id: root
|
||||
|
||||
property int indicatorType: DropIndicatorOverlayInterface.DropLocation_None
|
||||
property int indicatorType: KDDockWidgets.DropLocation_None
|
||||
readonly property bool isHovered: _window.classicIndicators.currentDropLocation === indicatorType
|
||||
|
||||
source: "qrc:/img/classic_indicators/" + _window.iconName(indicatorType, isHovered) + ".png";
|
||||
|
||||
@@ -21,8 +21,8 @@ Item {
|
||||
visible: width > 50 && height > 50 // don't show if window is too small'
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterLeft
|
||||
visible: _window.classicIndicators.outterLeftIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_OutterLeft
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: outterMargin
|
||||
@@ -31,8 +31,8 @@ Item {
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterRight
|
||||
visible: _window.classicIndicators.outterRightIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_OutterRight
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: outterMargin
|
||||
@@ -41,8 +41,8 @@ Item {
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterTop
|
||||
visible: _window.classicIndicators.outterTopIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_OutterTop
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: outterMargin
|
||||
@@ -51,8 +51,8 @@ Item {
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
visible: _window.classicIndicators.outterIndicatorsVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_OutterBottom
|
||||
visible: _window.classicIndicators.outterBottomIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_OutterBottom
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: outterMargin
|
||||
@@ -69,10 +69,13 @@ Item {
|
||||
|
||||
width: (centerIndicator * 3) + (2 * innerMargin)
|
||||
height: width
|
||||
visible: _window.classicIndicators.innerIndicatorsVisible
|
||||
visible: _window.classicIndicators.innerLeftIndicatorVisible || _window.classicIndicators.innerRightIndicatorVisible ||
|
||||
_window.classicIndicators.innerTopIndicatorVisible || _window.classicIndicators.innerBottomIndicatorVisible || _window.classicIndicators.tabIndicatorVisible
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Left
|
||||
id: innerLeft
|
||||
visible: _window.classicIndicators.innerLeftIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_Left
|
||||
anchors {
|
||||
right: centerIndicator.left
|
||||
rightMargin: innerMargin
|
||||
@@ -83,12 +86,14 @@ Item {
|
||||
ClassicIndicator {
|
||||
id: centerIndicator
|
||||
visible: _window.classicIndicators.tabIndicatorVisible
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Center
|
||||
indicatorType: KDDockWidgets.DropLocation_Center
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Right
|
||||
id: innerRight
|
||||
visible: _window.classicIndicators.innerRightIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_Right
|
||||
anchors {
|
||||
left: centerIndicator.right
|
||||
leftMargin: innerMargin
|
||||
@@ -97,7 +102,9 @@ Item {
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Top
|
||||
id: innerTop
|
||||
visible: _window.classicIndicators.innerTopIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_Top
|
||||
anchors {
|
||||
bottom: centerIndicator.top
|
||||
bottomMargin: innerMargin
|
||||
@@ -106,7 +113,9 @@ Item {
|
||||
}
|
||||
|
||||
ClassicIndicator {
|
||||
indicatorType: DropIndicatorOverlayInterface.DropLocation_Bottom
|
||||
id: innerBottom
|
||||
visible: _window.classicIndicators.innerBottomIndicatorVisible
|
||||
indicatorType: KDDockWidgets.DropLocation_Bottom
|
||||
anchors {
|
||||
top: centerIndicator.bottom
|
||||
topMargin: innerMargin
|
||||
|
||||
@@ -133,15 +133,11 @@ QWidget *KDDockWidgets::Private::widgetForWindow(QWindow *window)
|
||||
|
||||
void QWidgetAdapter::setNormalGeometry(QRect geo)
|
||||
{
|
||||
if (isNormalWindowState(windowState())) {
|
||||
setGeometry(geo);
|
||||
QWidgetPrivate *priv = QWidgetPrivate::get(this);
|
||||
if (priv->extra && priv->extra->topextra) {
|
||||
priv->topData()->normalGeometry = geo;
|
||||
} else {
|
||||
QWidgetPrivate *priv = QWidgetPrivate::get(this);
|
||||
if (priv->extra && priv->extra->topextra) {
|
||||
priv->topData()->normalGeometry = geo;
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Failing to set normal geometry";
|
||||
}
|
||||
qWarning() << Q_FUNC_INFO << "Failing to set normal geometry";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,3 +169,15 @@ void TabBarWidget::moveTabTo(int from, int to)
|
||||
{
|
||||
moveTab(from, to);
|
||||
}
|
||||
|
||||
void TabBarWidget::tabInserted(int index)
|
||||
{
|
||||
QTabBar::tabInserted(index);
|
||||
Q_EMIT dockWidgetInserted(index);
|
||||
}
|
||||
|
||||
void TabBarWidget::tabRemoved(int index)
|
||||
{
|
||||
QTabBar::tabRemoved(index);
|
||||
Q_EMIT dockWidgetRemoved(index);
|
||||
}
|
||||
|
||||
@@ -50,12 +50,18 @@ public:
|
||||
QRect rectForTab(int index) const override;
|
||||
void moveTabTo(int from, int to) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void dockWidgetInserted(int index);
|
||||
void dockWidgetRemoved(int index);
|
||||
|
||||
protected:
|
||||
bool dragCanStart(QPoint pressPos, QPoint pos) const override;
|
||||
void mousePressEvent(QMouseEvent *) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *e) override;
|
||||
bool event(QEvent *) override;
|
||||
void tabInserted(int index) override;
|
||||
void tabRemoved(int index) override;
|
||||
|
||||
private:
|
||||
TabWidget *const m_tabWidget;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
TabWidgetWidget::TabWidgetWidget(Frame *parent)
|
||||
TabWidgetWidget::TabWidgetWidget(Frame *parent, TabWidgetOptions options)
|
||||
: QTabWidget(parent)
|
||||
, TabWidget(this, parent)
|
||||
, m_tabBar(Config::self().frameworkWidgetFactory()->createTabBar(this))
|
||||
@@ -65,6 +65,8 @@ TabWidgetWidget::TabWidgetWidget(Frame *parent)
|
||||
setFocusProxy(nullptr);
|
||||
|
||||
setupTabBarButtons();
|
||||
|
||||
setDocumentMode(options & TabWidgetOption_DocumentMode);
|
||||
}
|
||||
|
||||
TabBar *TabWidgetWidget::tabBar() const
|
||||
|
||||
@@ -39,7 +39,7 @@ class DOCKS_EXPORT TabWidgetWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TabWidgetWidget(Frame *parent);
|
||||
explicit TabWidgetWidget(Frame *parent, TabWidgetOptions = TabWidgetOption_None);
|
||||
|
||||
TabBar *tabBar() const override;
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ protected:
|
||||
bool isFloatButtonEnabled() const override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
protected:
|
||||
void init();
|
||||
int buttonAreaWidth() const;
|
||||
void updateMargins();
|
||||
|
||||
@@ -25,6 +25,7 @@ set(TESTING_SRCS utils.cpp Testing.cpp)
|
||||
include_directories(..)
|
||||
include_directories(../src)
|
||||
include_directories(../src/private)
|
||||
add_definitions(-DQT_NO_KEYWORDS)
|
||||
|
||||
set(TESTING_SRCS utils.cpp Testing.cpp)
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
#include "TabWidget_p.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "MDIArea.h"
|
||||
#include "multisplitter/Separator_p.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "private/MultiSplitter_p.h"
|
||||
|
||||
#include <QAction>
|
||||
@@ -323,8 +325,8 @@ void TestDocks::tst_detachPos()
|
||||
m->addDockWidget(dock1, Location_OnLeft);
|
||||
m->addDockWidget(dock2, Location_OnRight);
|
||||
|
||||
QVERIFY(!dock1->dptr()->lastPositions().lastFloatingGeometry().isValid());
|
||||
QVERIFY(!dock2->dptr()->lastPositions().lastFloatingGeometry().isValid());
|
||||
QVERIFY(!dock1->dptr()->lastPosition()->lastFloatingGeometry().isValid());
|
||||
QVERIFY(!dock2->dptr()->lastPosition()->lastFloatingGeometry().isValid());
|
||||
|
||||
const int previousWidth = dock1->width();
|
||||
dock1->setFloating(true);
|
||||
@@ -382,7 +384,7 @@ void TestDocks::tst_tabbingWithAffinities()
|
||||
auto dropArea = m1->dropArea();
|
||||
WindowBeingDragged wbd(fw2, fw2);
|
||||
QVERIFY(!dropArea->drop(&wbd, dw1->dptr()->frame(),
|
||||
DropIndicatorOverlayInterface::DropLocation_Center));
|
||||
DropLocation_Center));
|
||||
QVERIFY(dw1->window() != dw2->window());
|
||||
}
|
||||
|
||||
@@ -790,11 +792,11 @@ void TestDocks::tst_doubleClose()
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
||||
m->addDockWidget(dock1, Location_OnBottom);
|
||||
|
||||
QVERIFY(!dock1->dptr()->lastPositions().wasFloating());
|
||||
QVERIFY(!dock1->dptr()->lastPosition()->wasFloating());
|
||||
dock1->close();
|
||||
QVERIFY(!dock1->dptr()->lastPositions().wasFloating());
|
||||
QVERIFY(!dock1->dptr()->lastPosition()->wasFloating());
|
||||
dock1->close();
|
||||
QVERIFY(!dock1->dptr()->lastPositions().wasFloating());
|
||||
QVERIFY(!dock1->dptr()->lastPosition()->wasFloating());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1678,7 +1680,7 @@ void TestDocks::tst_removeItem()
|
||||
|
||||
m->addDockWidget(dock1, Location_OnBottom);
|
||||
m->addDockWidget(dock2, Location_OnTop, nullptr, InitialVisibilityOption::StartHidden);
|
||||
Item *item2 = dock2->dptr()->lastPositions().lastItem();
|
||||
Item *item2 = dock2->dptr()->lastPosition()->lastItem();
|
||||
|
||||
auto dropArea = m->dropArea();
|
||||
MultiSplitter *layout = dropArea;
|
||||
@@ -1694,7 +1696,7 @@ void TestDocks::tst_removeItem()
|
||||
QCOMPARE(layout->placeholderCount(), 0);
|
||||
|
||||
// 2. Remove an item that has an actual widget
|
||||
Item *item1 = dock1->dptr()->lastPositions().lastItem();
|
||||
Item *item1 = dock1->dptr()->lastPosition()->lastItem();
|
||||
layout->removeItem(item1);
|
||||
QCOMPARE(layout->count(), 0);
|
||||
QCOMPARE(layout->placeholderCount(), 0);
|
||||
@@ -1716,11 +1718,11 @@ void TestDocks::tst_removeItem()
|
||||
QCOMPARE(layout->placeholderCount(), 2);
|
||||
|
||||
// Now remove the items
|
||||
layout->removeItem(dock2->dptr()->lastPositions().lastItem());
|
||||
layout->removeItem(dock2->dptr()->lastPosition()->lastItem());
|
||||
QCOMPARE(layout->count(), 2);
|
||||
QCOMPARE(layout->placeholderCount(), 1);
|
||||
layout->checkSanity();
|
||||
layout->removeItem(dock1->dptr()->lastPositions().lastItem());
|
||||
layout->removeItem(dock1->dptr()->lastPosition()->lastItem());
|
||||
QCOMPARE(layout->count(), 1);
|
||||
QCOMPARE(layout->placeholderCount(), 0);
|
||||
|
||||
@@ -1733,11 +1735,11 @@ void TestDocks::tst_removeItem()
|
||||
QVERIFY(Testing::waitForDeleted(frame1));
|
||||
|
||||
// Now remove the items, but first dock1
|
||||
layout->removeItem(dock1->dptr()->lastPositions().lastItem());
|
||||
layout->removeItem(dock1->dptr()->lastPosition()->lastItem());
|
||||
QCOMPARE(layout->count(), 2);
|
||||
QCOMPARE(layout->placeholderCount(), 1);
|
||||
layout->checkSanity();
|
||||
layout->removeItem(dock2->dptr()->lastPositions().lastItem());
|
||||
layout->removeItem(dock2->dptr()->lastPosition()->lastItem());
|
||||
QCOMPARE(layout->count(), 1);
|
||||
QCOMPARE(layout->placeholderCount(), 0);
|
||||
layout->checkSanity();
|
||||
@@ -1755,7 +1757,7 @@ void TestDocks::tst_removeItem()
|
||||
Testing::waitForDeleted(frame3);
|
||||
|
||||
// The second anchor is now following the 3rd, while the 3rd is following 'bottom'
|
||||
layout->removeItem(dock3->dptr()->lastPositions().lastItem()); // will trigger the 3rd anchor to
|
||||
layout->removeItem(dock3->dptr()->lastPosition()->lastItem()); // will trigger the 3rd anchor to
|
||||
// be removed
|
||||
QCOMPARE(layout->count(), 2);
|
||||
QCOMPARE(layout->placeholderCount(), 1);
|
||||
@@ -1883,7 +1885,7 @@ void TestDocks::tst_crash()
|
||||
QVERIFY(dock1->isFloating());
|
||||
QVERIFY(!dock1->isInMainWindow());
|
||||
|
||||
Item *layoutItem = dock1->dptr()->lastPositions().lastItem();
|
||||
Item *layoutItem = dock1->dptr()->lastPosition()->lastItem();
|
||||
QVERIFY(layoutItem && DockRegistry::self()->itemIsInMainWindow(layoutItem));
|
||||
QCOMPARE(layoutItem, item1);
|
||||
|
||||
@@ -1940,7 +1942,7 @@ void TestDocks::tst_refUnrefItem()
|
||||
QVERIFY(dock2);
|
||||
QVERIFY(item2.data());
|
||||
QCOMPARE(item2->refCount(), 1);
|
||||
QCOMPARE(dock2->dptr()->lastPositions().lastItem(), item2.data());
|
||||
QCOMPARE(dock2->dptr()->lastPosition()->lastItem(), item2.data());
|
||||
delete dock2;
|
||||
|
||||
QVERIFY(!item2.data());
|
||||
@@ -2534,8 +2536,8 @@ void TestDocks::tst_setFloatingWhenWasTabbed()
|
||||
QVERIFY(!dock1->isFloating());
|
||||
QVERIFY(dock2->isFloating());
|
||||
|
||||
QCOMPARE(dock2->dptr()->lastPositions().lastTabIndex(), 1);
|
||||
QVERIFY(dock2->dptr()->lastPositions().isValid());
|
||||
QCOMPARE(dock2->dptr()->lastPosition()->lastTabIndex(), 1);
|
||||
QVERIFY(dock2->dptr()->lastPosition()->isValid());
|
||||
dock2->setFloating(false);
|
||||
|
||||
QVERIFY(dock1->isTabbed());
|
||||
@@ -2710,7 +2712,7 @@ void TestDocks::tst_dockWidgetGetsFocusWhenDocked()
|
||||
QVERIFY(dw1->isFocused());
|
||||
|
||||
QVERIFY(fw1->isActiveWindow());
|
||||
dragFloatingWindowTo(fw2, fw1->dropArea(), DropIndicatorOverlayInterface::DropLocation_Left);
|
||||
dragFloatingWindowTo(fw2, fw1->dropArea(), DropLocation_Left);
|
||||
Testing::waitForEvent(fw1, QEvent::WindowActivate);
|
||||
|
||||
/// We dropped into floating window 1, it should still be active
|
||||
@@ -2806,10 +2808,10 @@ void TestDocks::tst_floatingLastPosAfterDoubleClose()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto d1 = new DockWidgetType(QStringLiteral("a"));
|
||||
QVERIFY(d1->dptr()->lastPositions().lastFloatingGeometry().isNull());
|
||||
QVERIFY(d1->dptr()->lastPosition()->lastFloatingGeometry().isNull());
|
||||
QVERIFY(!d1->isVisible());
|
||||
d1->close();
|
||||
QVERIFY(d1->dptr()->lastPositions().lastFloatingGeometry().isNull());
|
||||
QVERIFY(d1->dptr()->lastPosition()->lastFloatingGeometry().isNull());
|
||||
delete d1;
|
||||
}
|
||||
|
||||
@@ -2886,7 +2888,7 @@ void TestDocks::tst_dockWindowWithTwoSideBySideFramesIntoRight()
|
||||
auto fw2 = createFloatingWindow();
|
||||
fw2->move(fw->x() + fw->width() + 100, fw->y());
|
||||
|
||||
dragFloatingWindowTo(fw, fw2->dropArea(), DropIndicatorOverlayInterface::DropLocation_Right); // Outer right instead of Left
|
||||
dragFloatingWindowTo(fw, fw2->dropArea(), DropLocation_Right); // Outer right instead of Left
|
||||
QCOMPARE(fw2->frames().size(), 3);
|
||||
QVERIFY(fw2->dropArea()->checkSanity());
|
||||
|
||||
@@ -2910,7 +2912,7 @@ void TestDocks::tst_dockWindowWithTwoSideBySideFramesIntoLeft()
|
||||
fw2->move(fw->x() + fw->width() + 100, fw->y());
|
||||
|
||||
QVERIFY(fw2->dropArea()->checkSanity());
|
||||
dragFloatingWindowTo(fw, fw2->dropArea(), DropIndicatorOverlayInterface::DropLocation_Left);
|
||||
dragFloatingWindowTo(fw, fw2->dropArea(), DropLocation_Left);
|
||||
QCOMPARE(fw2->frames().size(), 3);
|
||||
|
||||
QVERIFY(fw2->dropArea()->checkSanity());
|
||||
@@ -2987,8 +2989,11 @@ void TestDocks::tst_preventClose()
|
||||
fw->close();
|
||||
QVERIFY(dock1->isVisible());
|
||||
|
||||
dock1->deleteLater();
|
||||
QVERIFY(Testing::waitForDeleted(dock1));
|
||||
// Put into a main window
|
||||
auto m = createMainWindow();
|
||||
m->addDockWidget(dock1, KDDockWidgets::Location_OnRight);
|
||||
m->close();
|
||||
QVERIFY(dock1->isVisible());
|
||||
}
|
||||
|
||||
void TestDocks::tst_propagateMinSize()
|
||||
@@ -3051,7 +3056,7 @@ void TestDocks::tst_addAndReadd()
|
||||
auto fw = dock1->floatingWindow();
|
||||
QVERIFY(fw);
|
||||
auto dropArea = m->dropArea();
|
||||
dragFloatingWindowTo(fw, dropArea, DropIndicatorOverlayInterface::DropLocation_Right);
|
||||
dragFloatingWindowTo(fw, dropArea, DropLocation_Right);
|
||||
QVERIFY(dock1->dptr()->frame()->titleBar()->isVisible());
|
||||
fw->titleBar()->makeWindow();
|
||||
m->layoutWidget()->checkSanity();
|
||||
@@ -3147,7 +3152,7 @@ void TestDocks::tst_addToSmallMainWindow3()
|
||||
auto fw = dock2->dptr()->morphIntoFloatingWindow();
|
||||
QVERIFY(fw->isVisible());
|
||||
QVERIFY(dropArea->checkSanity());
|
||||
dragFloatingWindowTo(fw, dropArea, DropIndicatorOverlayInterface::DropLocation_Right);
|
||||
dragFloatingWindowTo(fw, dropArea, DropLocation_Right);
|
||||
QVERIFY(m->dropArea()->checkSanity());
|
||||
delete fw;
|
||||
}
|
||||
@@ -4141,7 +4146,7 @@ void TestDocks::tst_dragOverTitleBar()
|
||||
const QPoint titleBarPoint = fw1->titleBar()->mapToGlobal(QPoint(5, 5));
|
||||
|
||||
auto loc = da->hover(&wbd, titleBarPoint);
|
||||
QCOMPARE(loc, DropIndicatorOverlayInterface::DropLocation_None);
|
||||
QCOMPARE(loc, DropLocation_None);
|
||||
}
|
||||
|
||||
delete fw1;
|
||||
@@ -4205,7 +4210,7 @@ void TestDocks::tst_setFloatingAfterDraggedFromTabToSideBySide()
|
||||
|
||||
m->addDockWidget(dock1, KDDockWidgets::Location_OnLeft);
|
||||
dock1->addDockWidgetAsTab(dock2);
|
||||
Item *oldItem2 = dock2->dptr()->lastPositions().lastItem();
|
||||
Item *oldItem2 = dock2->dptr()->lastPosition()->lastItem();
|
||||
QCOMPARE(oldItem2, layout->itemForFrame(dock2->dptr()->frame()));
|
||||
|
||||
|
||||
@@ -4214,7 +4219,7 @@ void TestDocks::tst_setFloatingAfterDraggedFromTabToSideBySide()
|
||||
QVERIFY(layout->checkSanity());
|
||||
auto fw2 = dock2->floatingWindow();
|
||||
QVERIFY(fw2);
|
||||
QCOMPARE(dock2->dptr()->lastPositions().lastItem(), oldItem2);
|
||||
QCOMPARE(dock2->dptr()->lastPosition()->lastItem(), oldItem2);
|
||||
Item *item2 = fw2->dropArea()->itemForFrame(dock2->dptr()->frame());
|
||||
QVERIFY(item2);
|
||||
QCOMPARE(item2->hostWidget()->asQObject(), fw2->dropArea());
|
||||
@@ -4223,7 +4228,7 @@ void TestDocks::tst_setFloatingAfterDraggedFromTabToSideBySide()
|
||||
// Move from tab to bottom
|
||||
layout->addWidget(fw2->dropArea(), KDDockWidgets::Location_OnRight, nullptr);
|
||||
QVERIFY(layout->checkSanity());
|
||||
QVERIFY(dock2->dptr()->lastPositions().lastItem());
|
||||
QVERIFY(dock2->dptr()->lastPosition()->lastItem());
|
||||
QCOMPARE(layout->count(), 2);
|
||||
QCOMPARE(layout->placeholderCount(), 0);
|
||||
|
||||
@@ -4843,7 +4848,7 @@ void TestDocks::tst_lastFloatingPositionIsRestored()
|
||||
|
||||
// Now dock it:
|
||||
m1->addDockWidget(dock1, Location_OnTop);
|
||||
QCOMPARE(dock1->dptr()->lastPositions().lastFloatingGeometry().topLeft(), targetPos);
|
||||
QCOMPARE(dock1->dptr()->lastPosition()->lastFloatingGeometry().topLeft(), targetPos);
|
||||
|
||||
dock1->setFloating(true);
|
||||
QCOMPARE(dock1->window()->geometry().topLeft(), targetPos);
|
||||
@@ -5058,6 +5063,303 @@ void TestDocks::tst_dockableMainWindows()
|
||||
fw->dropArea()->addDockWidget(dock1, Location::Location_OnLeft, nullptr);
|
||||
}
|
||||
|
||||
void TestDocks::tst_mdi_mixed_with_docking()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(500, 500), MainWindowOption_HasCentralWidget);
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
||||
|
||||
m->addDockWidget(dock1, Location_OnBottom);
|
||||
|
||||
auto mdiArea = new MDIArea();
|
||||
m->setPersistentCentralWidget(mdiArea);
|
||||
|
||||
auto mdiWidget1 = createDockWidget("mdi1", new QPushButton("mdi1"));
|
||||
auto mdiWidget2 = createDockWidget("mdi2", new QPushButton("mdi12"));
|
||||
|
||||
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
||||
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
||||
|
||||
Frame *frameMDI1 = mdiWidget1->d->frame();
|
||||
Frame *frame1 = dock1->d->frame();
|
||||
QVERIFY(!frame1->isMDI());
|
||||
QVERIFY(frameMDI1->isMDI());
|
||||
QVERIFY(!frame1->mdiLayoutWidget());
|
||||
QVERIFY(frameMDI1->mdiLayoutWidget());
|
||||
|
||||
QVERIFY(!dock1->titleBar()->isMDI());
|
||||
|
||||
auto tb1 = mdiWidget1->titleBar();
|
||||
QVERIFY(tb1->isMDI());
|
||||
QVERIFY(Testing::waitForEvent(tb1, QEvent::Show));
|
||||
QVERIFY(tb1->isVisible());
|
||||
|
||||
// Press the float button
|
||||
tb1->onFloatClicked();
|
||||
|
||||
QVERIFY(mdiWidget1->d->lastPosition()->isValid());
|
||||
QVERIFY(mdiWidget1->titleBar()->isVisible());
|
||||
QVERIFY(mdiWidget1->isFloating());
|
||||
|
||||
// Dock again, and check it went back
|
||||
mdiWidget1->titleBar()->onFloatClicked();
|
||||
QVERIFY(!mdiWidget1->isFloating());
|
||||
}
|
||||
|
||||
void TestDocks::tst_mdi_mixed_with_docking2()
|
||||
{
|
||||
// Here, the MDI dock widgets are themselves main windows which will show drop-indicators.
|
||||
// It will be super nested: MainWindow -> MDI -> MainWindow
|
||||
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
||||
|
||||
m->addDockWidget(dock1, Location_OnBottom);
|
||||
|
||||
auto mdiArea = new MDIArea();
|
||||
m->setPersistentCentralWidget(mdiArea);
|
||||
|
||||
|
||||
auto createSheet = [](int id) -> DockWidgetBase* {
|
||||
auto dock = new DockWidget(QStringLiteral("dw-sheet-%1").arg(id), DockWidgetBase::Option_MDINestable);
|
||||
dock->setWidget(new QPushButton(QStringLiteral("Sheet %1").arg(id)));
|
||||
dock->setTitle(QStringLiteral("Sheet %1").arg(id));
|
||||
|
||||
return dock;
|
||||
};
|
||||
|
||||
auto mdiWidget1 = createSheet(1);
|
||||
auto mdiWidget2 = createSheet(2);
|
||||
auto mdiWidget3 = createSheet(3);
|
||||
/*auto mdiWidget4 = createSheet(4);
|
||||
auto mdiWidget5 = createSheet(5);
|
||||
auto mdiWidget6 = createSheet(6);*/
|
||||
|
||||
|
||||
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
||||
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
||||
|
||||
Frame *frame1 = mdiWidget1->d->frame();
|
||||
Frame *mdiFrame1 = frame1->mdiFrame();
|
||||
|
||||
QPointer<Frame> frame2 = mdiWidget2->d->frame();
|
||||
QPointer<Frame> mdiFrame2 = frame2->mdiFrame();
|
||||
QPointer<DropArea> dropArea2 = frame2->mdiDropAreaWrapper();
|
||||
|
||||
QPointer<DropArea> dropArea1 = frame1->mdiDropAreaWrapper();
|
||||
dropArea1->addDockWidget(mdiWidget3, Location_OnLeft, nullptr);
|
||||
|
||||
QVERIFY(!frame1->isMDI());
|
||||
QVERIFY(frame1->isMDIWrapper());
|
||||
QVERIFY(frame1->mdiDockWidgetWrapper());
|
||||
QVERIFY(dropArea1->isMDIWrapper());
|
||||
QVERIFY(dropArea2->isMDIWrapper());
|
||||
QVERIFY(!mdiFrame1->isMDIWrapper());
|
||||
QVERIFY(mdiFrame1->isMDI());
|
||||
QVERIFY(!mdiWidget1->d->isMDIWrapper());
|
||||
|
||||
// Test title bars:
|
||||
|
||||
auto tb1 = mdiWidget1->titleBar();
|
||||
auto mdiTb1 = mdiFrame1->titleBar();
|
||||
auto mdiTb2 = mdiFrame2->titleBar();
|
||||
|
||||
Testing::waitForEvent(mdiTb1, QEvent::Show);
|
||||
|
||||
QVERIFY(mdiTb1->isVisible());
|
||||
QVERIFY(mdiTb2->isVisible());
|
||||
QVERIFY(tb1->isVisible());
|
||||
QCOMPARE(tb1->title(), QString("Sheet 1"));
|
||||
QCOMPARE(mdiTb1->title(), QString("dockwidgets-unit-tests"));
|
||||
QCOMPARE(mdiTb2->title(), QString("Sheet 2"));
|
||||
|
||||
QVERIFY(tb1 != mdiTb1);
|
||||
QCOMPARE(mdiWidget2->titleBar(), mdiTb2);
|
||||
|
||||
// Test that closing will delete the wrappers:
|
||||
mdiWidget2->close();
|
||||
QVERIFY(!mdiWidget2->isOpen());
|
||||
|
||||
Testing::waitForDeleted(dropArea2);
|
||||
QVERIFY(dropArea2.isNull());
|
||||
QVERIFY(!mdiFrame2);
|
||||
|
||||
mdiWidget1->close();
|
||||
QVERIFY(!mdiWidget1->isOpen());
|
||||
QTest::qWait(500); // wait some event loops to make sure there's no delete later. (There isn't, but a bug could introduce them)
|
||||
QVERIFY(!dropArea1.isNull()); // Not deleted, as sheet3 is still there
|
||||
QCOMPARE(dropArea1->visibleCount(), 1);
|
||||
QVERIFY(mdiTb1->isVisible());
|
||||
QCOMPARE(mdiWidget3->titleBar(), mdiTb1);
|
||||
Frame *frame3 = mdiWidget3->d->frame();
|
||||
QVERIFY(!frame3->titleBar()->isVisible());
|
||||
|
||||
mdiWidget3->close();
|
||||
QVERIFY(Testing::waitForDeleted(dropArea1));
|
||||
QVERIFY(!mdiWidget3->isOpen());
|
||||
QVERIFY(dropArea1.isNull());
|
||||
|
||||
// Reopen everything again:
|
||||
|
||||
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
||||
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
||||
frame1 = mdiWidget1->d->frame();
|
||||
mdiFrame1 = frame1->mdiFrame();
|
||||
dropArea1 = frame1->mdiDropAreaWrapper();
|
||||
dropArea1->addDockWidget(mdiWidget3, Location_OnLeft, nullptr);
|
||||
|
||||
// Test floating:
|
||||
frame2 = mdiWidget2->d->frame();
|
||||
QPointer<DockWidgetBase> dwWrapper2 = frame2->mdiDockWidgetWrapper();
|
||||
dropArea2 = frame2->mdiDropAreaWrapper();
|
||||
QVERIFY(mdiWidget2->isVisible());
|
||||
QVERIFY(frame2->isMDIWrapper());
|
||||
QVERIFY(dwWrapper2->d->isMDIWrapper());
|
||||
mdiFrame2 = frame2->mdiFrame();
|
||||
mdiWidget2->setFloating(true);
|
||||
QVERIFY(mdiWidget2->isFloating());
|
||||
|
||||
QVERIFY(!mdiWidget2->d->frame()->isMDI());
|
||||
QVERIFY(!mdiWidget2->d->frame()->isMDIWrapper());
|
||||
QVERIFY(Testing::waitForDeleted(mdiFrame2));
|
||||
|
||||
QVERIFY(dropArea2.isNull());
|
||||
QVERIFY(dwWrapper2.isNull());
|
||||
|
||||
auto mdiFrames = mdiArea->frames();
|
||||
QCOMPARE(mdiFrames.count(), 1);
|
||||
mdiFrame1 = mdiFrames.first();
|
||||
QVERIFY(mdiFrame1->isMDI());
|
||||
QVERIFY(mdiFrame1->hasNestedMDIDockWidgets());
|
||||
auto mdiTitleBar1 = mdiFrame1->titleBar();
|
||||
QVERIFY(mdiFrame1->titleBar()->isVisible());
|
||||
mdiTitleBar1->makeWindow();
|
||||
|
||||
QVERIFY(Testing::waitForDeleted(mdiFrame1));
|
||||
QCOMPARE(mdiArea->frames().size(), 0);
|
||||
|
||||
// Dock again:
|
||||
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
||||
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
||||
|
||||
frame1 = mdiWidget1->d->frame();
|
||||
dropArea1 = frame1->mdiDropAreaWrapper();
|
||||
dropArea1->addDockWidget(mdiWidget3, Location_OnLeft, nullptr);
|
||||
|
||||
// Detach an internal dock widget by dragging
|
||||
const QPoint globalSrc = mdiWidget1->mapToGlobal(QPoint(5, 5));
|
||||
const QPoint globalDest = globalSrc + QPoint(100, 100);
|
||||
|
||||
drag(mdiWidget1, globalDest);
|
||||
|
||||
QCOMPARE(mdiArea->frames().count(), 2);
|
||||
auto mdiTitleBar = mdiArea->frames().first()->titleBar();
|
||||
QVERIFY(mdiTitleBar->isVisible());
|
||||
|
||||
QVERIFY(!mdiWidget3->isFloating());
|
||||
QVERIFY(mdiWidget3->d->lastPosition()->isValid());
|
||||
mdiTitleBar->onFloatClicked();
|
||||
QVERIFY(mdiWidget3->isFloating());
|
||||
|
||||
QVERIFY(Testing::waitForDeleted(mdiArea->frames().constFirst()));
|
||||
QCOMPARE(mdiArea->frames().size(), 1);
|
||||
|
||||
QVERIFY(!mdiWidget2->isFloating());
|
||||
Frame *lastMdiFrame = mdiArea->frames().constFirst();
|
||||
QVERIFY(lastMdiFrame->titleBar()->isVisible());
|
||||
QVERIFY(!lastMdiFrame->titleBar()->isFloating());
|
||||
lastMdiFrame->titleBar()->onFloatClicked();
|
||||
QVERIFY(mdiWidget2->isFloating());
|
||||
|
||||
// put it in the MDI area again
|
||||
mdiWidget2->titleBar()->onFloatClicked();
|
||||
QVERIFY(!mdiWidget2->isFloating());
|
||||
}
|
||||
|
||||
void TestDocks::tstCloseNestedMdi()
|
||||
{
|
||||
// Tests a bug where closing a mdi dock widget would close its main window too
|
||||
EnsureTopLevelsDeleted e;
|
||||
|
||||
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
||||
QPointer<MainWindowBase> p = m.get();
|
||||
|
||||
auto mdi = new KDDockWidgets::MDIArea();
|
||||
m->setPersistentCentralWidget(mdi);
|
||||
|
||||
auto dock1 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock1"));
|
||||
dock1->setWidget( new QPushButton("1"));
|
||||
|
||||
mdi->addDockWidget(dock1, {});
|
||||
|
||||
dock1->titleBar()->onCloseClicked();
|
||||
QVERIFY(p);
|
||||
QVERIFY(m->isVisible());
|
||||
}
|
||||
|
||||
void TestDocks::tstCloseNestedMDIPropagates()
|
||||
{
|
||||
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
||||
QPointer<MainWindowBase> p = m.get();
|
||||
|
||||
auto mdi = new KDDockWidgets::MDIArea();
|
||||
m->setPersistentCentralWidget(mdi);
|
||||
|
||||
auto dock1 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock1"));
|
||||
dock1->setWidget(new NonClosableWidget());
|
||||
mdi->addDockWidget(dock1, {});
|
||||
|
||||
auto dock2 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock2"));
|
||||
dock2->setWidget(new NonClosableWidget());
|
||||
dock2->show();
|
||||
|
||||
QVERIFY(Testing::waitForEvent(dock1, QEvent::Show));
|
||||
QVERIFY(dock1->isVisible());
|
||||
QVERIFY(dock2->isVisible());
|
||||
|
||||
m->close();
|
||||
|
||||
QVERIFY(dock2->isVisible());
|
||||
QVERIFY(dock1->isVisible());
|
||||
}
|
||||
|
||||
void TestDocks::tst_mdi_mixed_with_docking_setMDISize()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
||||
|
||||
m->addDockWidget(dock1, Location_OnBottom);
|
||||
|
||||
auto mdiArea = new MDIArea();
|
||||
m->setPersistentCentralWidget(mdiArea);
|
||||
|
||||
auto createSheet = [](int id) -> DockWidgetBase* {
|
||||
auto dock = new DockWidget(QStringLiteral("dw-sheet-%1").arg(id), DockWidgetBase::Option_MDINestable);
|
||||
dock->setWidget(new QPushButton(QStringLiteral("Sheet %1").arg(id)));
|
||||
dock->setTitle(QStringLiteral("Sheet %1").arg(id));
|
||||
|
||||
return dock;
|
||||
};
|
||||
|
||||
auto mdiWidget1 = createSheet(1);
|
||||
auto mdiWidget2 = createSheet(2);
|
||||
|
||||
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
||||
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
||||
|
||||
Frame *frame1 = mdiArea->frames().at(0);
|
||||
|
||||
const QSize sz1 = frame1->QWidgetAdapter::size();
|
||||
const QSize increment(200, 200);
|
||||
|
||||
QVERIFY(mdiWidget1->d->mdiLayout());
|
||||
mdiWidget1->setMDISize(sz1 + increment);
|
||||
|
||||
QCOMPARE(frame1->QWidgetAdapter::size(), sz1 + increment);
|
||||
}
|
||||
|
||||
// No need to port to QtQuick
|
||||
void TestDocks::tst_floatingWindowDeleted()
|
||||
{
|
||||
@@ -5432,7 +5734,7 @@ void TestDocks::tst_embeddedMainWindow()
|
||||
auto dropArea = window->mainWindow->dropArea();
|
||||
auto fw = dock1->floatingWindow();
|
||||
|
||||
dragFloatingWindowTo(fw, dropArea, DropIndicatorOverlayInterface::DropLocation_Left);
|
||||
dragFloatingWindowTo(fw, dropArea, DropLocation_Left);
|
||||
|
||||
auto layout = dropArea;
|
||||
QVERIFY(Testing::waitForDeleted(fw));
|
||||
@@ -7064,7 +7366,7 @@ void TestDocks::tst_dragByTabBar()
|
||||
QVERIFY(fw->isVisible());
|
||||
QVERIFY(!fw->titleBar()->isVisible());
|
||||
|
||||
dragFloatingWindowTo(fw, dropArea, DropIndicatorOverlayInterface::DropLocation_Right);
|
||||
dragFloatingWindowTo(fw, dropArea, DropLocation_Right);
|
||||
}
|
||||
|
||||
void TestDocks::tst_dock2FloatingWidgetsTabbed()
|
||||
@@ -7382,6 +7684,58 @@ void TestDocks::tst_resizePropagatesEvenly()
|
||||
QVERIFY(qAbs(dock2->height() - dock1->height()) < 3);
|
||||
}
|
||||
|
||||
void TestDocks::tst_unfloatTabbedFloatingWidgets()
|
||||
{
|
||||
/// A main window with 2 tabbed dock widgets.
|
||||
/// Tests that we're able to float the entire tab group and
|
||||
/// put it back into the main window when float button is pressed again.
|
||||
|
||||
auto m = createMainWindow(QSize(1000, 1000), MainWindowOption_None);
|
||||
auto dock0 = createDockWidget("dock0", new MyWidget2());
|
||||
auto dock1 = createDockWidget("dock1", new MyWidget2());
|
||||
m->addDockWidget(dock0, Location_OnLeft);
|
||||
dock0->addDockWidgetAsTab(dock1);
|
||||
|
||||
dock0->titleBar()->onFloatClicked();
|
||||
QVERIFY(dock0->titleBar()->isFloating());
|
||||
QVERIFY(!dock0->mainWindow());
|
||||
|
||||
dock0->titleBar()->onFloatClicked();
|
||||
QVERIFY(!dock0->titleBar()->isFloating());
|
||||
QVERIFY(dock0->mainWindow());
|
||||
}
|
||||
|
||||
void TestDocks::tst_unfloatTabbedFloatingWidgets2()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
|
||||
// Like tst_unfloatTabbedFloatingWidgets, but now there's no main window, just a FloatingWindow
|
||||
// with nesting.
|
||||
|
||||
auto dock0 = createDockWidget("dock0", new MyWidget2());
|
||||
auto dock1 = createDockWidget("dock1", new MyWidget2());
|
||||
auto dock2 = createDockWidget("dock2", new MyWidget2());
|
||||
|
||||
dock0->show();
|
||||
dock1->show();
|
||||
dock2->show();
|
||||
|
||||
dock0->addDockWidgetAsTab(dock1);
|
||||
dock0->addDockWidgetToContainingWindow(dock2, KDDockWidgets::Location_OnBottom);
|
||||
|
||||
// Float:
|
||||
dock0->titleBar()->onFloatClicked();
|
||||
QVERIFY(dock0->titleBar()->isFloating());
|
||||
QCOMPARE(dock0->floatingWindow(), dock1->floatingWindow());
|
||||
QVERIFY(dock0->floatingWindow() != dock2->floatingWindow());
|
||||
|
||||
// redock, nothing happens as we don't have a previous docked position in main window
|
||||
dock0->titleBar()->onFloatClicked();
|
||||
QVERIFY(dock0->titleBar()->isFloating());
|
||||
QCOMPARE(dock0->floatingWindow(), dock1->floatingWindow());
|
||||
QVERIFY(dock0->floatingWindow() != dock2->floatingWindow());
|
||||
}
|
||||
|
||||
void TestDocks::tst_addMDIDockWidget()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
|
||||
@@ -240,6 +240,8 @@ private Q_SLOTS:
|
||||
void tst_toggleTabbed();
|
||||
void tst_toggleTabbed2();
|
||||
void tst_resizePropagatesEvenly();
|
||||
void tst_unfloatTabbedFloatingWidgets();
|
||||
void tst_unfloatTabbedFloatingWidgets2();
|
||||
|
||||
void tst_addMDIDockWidget();
|
||||
void tst_redockToMDIRestoresPosition();
|
||||
@@ -250,6 +252,11 @@ private Q_SLOTS:
|
||||
|
||||
void tst_mainWindowAlwaysHasCentralWidget();
|
||||
void tst_dockableMainWindows();
|
||||
void tst_mdi_mixed_with_docking();
|
||||
void tst_mdi_mixed_with_docking2();
|
||||
void tst_mdi_mixed_with_docking_setMDISize();
|
||||
void tstCloseNestedMdi();
|
||||
void tstCloseNestedMDIPropagates();
|
||||
|
||||
// But these are fine to be widget only:
|
||||
void tst_tabsNotClickable();
|
||||
|
||||
@@ -393,9 +393,13 @@ inline void drag(WidgetType *sourceWidget, QPoint pressGlobalPos, QPoint globalD
|
||||
if (s_pauseBeforeMove)
|
||||
QTest::qWait(DEBUGGING_PAUSE_DURATION);
|
||||
|
||||
qDebug() << "Moving sourceWidget to" << globalDest
|
||||
qDebug() << "Moving sourceWidget=" << sourceWidget << "to" << globalDest
|
||||
<< "; sourceWidget->size=" << sourceWidget->size()
|
||||
<< "; from=" << QCursor::pos();
|
||||
<< "; pressPosGlobal=" << pressGlobalPos
|
||||
<< "; pressPosLocal=" << sourceWidget->mapFromGlobal(pressGlobalPos)
|
||||
<< "; from=" << QCursor::pos()
|
||||
<< "; actions=" << buttonActions
|
||||
<< "; visible=" << sourceWidget->isVisible();
|
||||
moveMouseTo(globalDest, sourceWidget);
|
||||
qDebug() << "Arrived at" << QCursor::pos();
|
||||
pressGlobalPos = KDDockWidgets::mapToGlobal(sourceWidget, QPoint(10, 10));
|
||||
@@ -411,7 +415,7 @@ inline void drag(WidgetType *sourceWidget, QPoint globalDest,
|
||||
WidgetType *draggable = draggableFor(sourceWidget);
|
||||
|
||||
Q_ASSERT(draggable && draggable->isVisible());
|
||||
const QPoint pressGlobalPos = KDDockWidgets::mapToGlobal(draggable, QPoint(6, 6));
|
||||
const QPoint pressGlobalPos = KDDockWidgets::mapToGlobal(draggable, QPoint(15, 15));
|
||||
|
||||
drag(draggable, pressGlobalPos, globalDest, buttonActions);
|
||||
}
|
||||
@@ -425,7 +429,7 @@ inline void dragFloatingWindowTo(FloatingWindow *fw, QPoint globalDest,
|
||||
drag(draggable, KDDockWidgets::mapToGlobal(draggable, QPoint(10, 10)), globalDest, buttonActions);
|
||||
}
|
||||
|
||||
inline void dragFloatingWindowTo(FloatingWindow *fw, DropArea *target, DropIndicatorOverlayInterface::DropLocation dropLocation)
|
||||
inline void dragFloatingWindowTo(FloatingWindow *fw, DropArea *target, DropLocation dropLocation)
|
||||
{
|
||||
auto draggable = draggableFor(fw);
|
||||
Q_ASSERT(draggable);
|
||||
|
||||
Reference in New Issue
Block a user