Compare commits
336 Commits
fix-python
...
v1.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fb70009cc | ||
|
|
289ddffbe2 | ||
|
|
54738bbea2 | ||
|
|
5c6eb352d6 | ||
|
|
f657399ef8 | ||
|
|
c4ffe10e12 | ||
|
|
efcad6d2be | ||
|
|
b6925c928a | ||
|
|
75368d334a | ||
|
|
d39ce8f66e | ||
|
|
805ea41d8a | ||
|
|
d7ed2494be | ||
|
|
0990337cdc | ||
|
|
e41cdb6f78 | ||
|
|
666673a251 | ||
|
|
34cb2ae5f0 | ||
|
|
51d8c2ff3e | ||
|
|
aa9f50d0f4 | ||
|
|
b7c36a2ec9 | ||
|
|
e18fb7ffd8 | ||
|
|
96439339c7 | ||
|
|
04d418b2e9 | ||
|
|
c04d856322 | ||
|
|
1c41c33f33 | ||
|
|
1dae128511 | ||
|
|
eab80c0545 | ||
|
|
288c3df30b | ||
|
|
e8728e8a35 | ||
|
|
94bfc4f2d1 | ||
|
|
d2da07508a | ||
|
|
7082e40cd5 | ||
|
|
2c8bbd10f7 | ||
|
|
ed8a401fe8 | ||
|
|
72428075f0 | ||
|
|
562db7c812 | ||
|
|
3ee15d1307 | ||
|
|
cf232dda34 | ||
|
|
bfeac02a45 | ||
|
|
22f4c36eb0 | ||
|
|
3dc56ea4ef | ||
|
|
cbedc06e97 | ||
|
|
8f85f28ed4 | ||
|
|
b5c2757874 | ||
|
|
46f57ffbbc | ||
|
|
fb6e2afd7b | ||
|
|
f74eb73326 | ||
|
|
ceb796d807 | ||
|
|
9a9488117c | ||
|
|
e55d75ba98 | ||
|
|
742763e6e5 | ||
|
|
d7242f17b7 | ||
|
|
eba395dc4c | ||
|
|
89635d8b98 | ||
|
|
f475312f11 | ||
|
|
9f604829dd | ||
|
|
85f829f97a | ||
|
|
e3bb0b3d48 | ||
|
|
22c0b6f9b6 | ||
|
|
200cb7aded | ||
|
|
4999fdd819 | ||
|
|
76aca4139a | ||
|
|
64276cb872 | ||
|
|
aad63d117b | ||
|
|
bd66af0a9f | ||
|
|
a21d80279e | ||
|
|
4347aefc8f | ||
|
|
b6341154fb | ||
|
|
16f6692b79 | ||
|
|
6c1026956a | ||
|
|
97679abb02 | ||
|
|
e173a4cfff | ||
|
|
26971ef1e2 | ||
|
|
d7bde47105 | ||
|
|
143c82291d | ||
|
|
979b2fdd40 | ||
|
|
46337d900b | ||
|
|
ec1f1bea9a | ||
|
|
d207028d60 | ||
|
|
a237eae508 | ||
|
|
243396f22b | ||
|
|
f240bf5d40 | ||
|
|
785db1b50c | ||
|
|
b6a7048a4f | ||
|
|
52bff59024 | ||
|
|
bba0195196 | ||
|
|
41fdb9c7df | ||
|
|
c1c1da25a8 | ||
|
|
b4e7b97646 | ||
|
|
2c687fe469 | ||
|
|
10e0402afa | ||
|
|
ebb1179167 | ||
|
|
15c196d865 | ||
|
|
e897ce6e8e | ||
|
|
83d9db1b64 | ||
|
|
60331fc654 | ||
|
|
e8f16dd172 | ||
|
|
44bd451362 | ||
|
|
1d2a791dfc | ||
|
|
a4ba45b423 | ||
|
|
12576970c6 | ||
|
|
e0ee7d14b0 | ||
|
|
66f447ad3f | ||
|
|
75db599142 | ||
|
|
a5c65ae039 | ||
|
|
5c055e0b8d | ||
|
|
090483f04e | ||
|
|
953219f6f3 | ||
|
|
8356bb0c3c | ||
|
|
758548f7a2 | ||
|
|
2aa16eb6d9 | ||
|
|
9d6cef24c1 | ||
|
|
52999d4cc9 | ||
|
|
bc2fff2c04 | ||
|
|
40fa4e98f8 | ||
|
|
a07f63a2c7 | ||
|
|
39c9a4da9b | ||
|
|
e0aa547393 | ||
|
|
08eab8882f | ||
|
|
04723ac3a9 | ||
|
|
c25043fa00 | ||
|
|
5372920cd0 | ||
|
|
28ae4c3b8c | ||
|
|
6158ebd520 | ||
|
|
b77430e574 | ||
|
|
fad81d595a | ||
|
|
0980a7f601 | ||
|
|
46830713e0 | ||
|
|
cd796db0ff | ||
|
|
29da5f4a8a | ||
|
|
315bdc71e5 | ||
|
|
a8965bea91 | ||
|
|
bf259c7ffc | ||
|
|
8a990451d7 | ||
|
|
974bdbd637 | ||
|
|
cb9d77cd18 | ||
|
|
af10efa587 | ||
|
|
a0fb47af58 | ||
|
|
598fbdc51b | ||
|
|
81c3f3f0c6 | ||
|
|
b9962b3df0 | ||
|
|
a71386e62a | ||
|
|
812ce1c08b | ||
|
|
189e82450b | ||
|
|
a3dbc3739c | ||
|
|
c8d34375af | ||
|
|
6c3775ea45 | ||
|
|
5a72e1adab | ||
|
|
0f7f310734 | ||
|
|
e8bf2a5222 | ||
|
|
468f545c9a | ||
|
|
a59ff6dfee | ||
|
|
4fa415ba05 | ||
|
|
d851c60b2f | ||
|
|
bf097098e5 | ||
|
|
8c93b85a24 | ||
|
|
f87d67dd59 | ||
|
|
bc3278b218 | ||
|
|
d2c55a67df | ||
|
|
a3414fd92b | ||
|
|
12f3ba9074 | ||
|
|
034d2c8aee | ||
|
|
ad3f4141c8 | ||
|
|
cde2e4e571 | ||
|
|
e0775467b2 | ||
|
|
b20ffcde61 | ||
|
|
43bdb6a4c2 | ||
|
|
929aabdc0d | ||
|
|
6a90a5125f | ||
|
|
77016a619f | ||
|
|
dc328ff7c4 | ||
|
|
dc13665566 | ||
|
|
d1279ab119 | ||
|
|
80bf6032f3 | ||
|
|
22437e75c6 | ||
|
|
801e49de9d | ||
|
|
a847a574ed | ||
|
|
ef8807bc09 | ||
|
|
d441477fa9 | ||
|
|
ece7b22bec | ||
|
|
97d8e4f18b | ||
|
|
9937f5d789 | ||
|
|
675edfe6db | ||
|
|
c23d179385 | ||
|
|
36af020505 | ||
|
|
7b2d195139 | ||
|
|
984ab3bb13 | ||
|
|
0331f90791 | ||
|
|
b19c53d650 | ||
|
|
3670cf2377 | ||
|
|
864670b0a1 | ||
|
|
0cf148b389 | ||
|
|
921d0892a0 | ||
|
|
beb2d9e659 | ||
|
|
59168da231 | ||
|
|
3dbf699c49 | ||
|
|
baa7561b13 | ||
|
|
ac5f4b871c | ||
|
|
52bf449366 | ||
|
|
08a1c4e6df | ||
|
|
156dad6e03 | ||
|
|
b642d2df2f | ||
|
|
5cedfab82c | ||
|
|
af9d62a58c | ||
|
|
0758496b0d | ||
|
|
a452723919 | ||
|
|
774e66ba6f | ||
|
|
f13de89db5 | ||
|
|
1393ae224f | ||
|
|
d92d7c258c | ||
|
|
619ca74051 | ||
|
|
aa39a71ae5 | ||
|
|
f4e33c1409 | ||
|
|
ad96336a36 | ||
|
|
50d1e75709 | ||
|
|
793c4e509b | ||
|
|
e4a33ad8b7 | ||
|
|
52cf53ce5c | ||
|
|
8791870efb | ||
|
|
4f8c47bfa4 | ||
|
|
ad141df6b1 | ||
|
|
72605292b7 | ||
|
|
1443eff1d9 | ||
|
|
22d5db32ce | ||
|
|
e9a321039f | ||
|
|
b93f115b53 | ||
|
|
7faaf2cc69 | ||
|
|
978f9d3a5e | ||
|
|
09793b3481 | ||
|
|
f4d9a96ddb | ||
|
|
4ac892038f | ||
|
|
387ba291be | ||
|
|
5d3d189774 | ||
|
|
a6a1047f75 | ||
|
|
3e70b846e8 | ||
|
|
0a2aebd78d | ||
|
|
ddad0feaf3 | ||
|
|
aba1cce1f6 | ||
|
|
7318675e84 | ||
|
|
cf700f8eb6 | ||
|
|
2c1d099c83 | ||
|
|
91ff29ae64 | ||
|
|
523dfb0d12 | ||
|
|
b84e0f3605 | ||
|
|
f72e8e6a1c | ||
|
|
c6c1fe79c3 | ||
|
|
ea382dcc17 | ||
|
|
c142eb8ecd | ||
|
|
46c039153e | ||
|
|
473f03360c | ||
|
|
3fb3984a72 | ||
|
|
9c5e3cf5af | ||
|
|
7419ca806d | ||
|
|
8a51c31663 | ||
|
|
a586a7894b | ||
|
|
31fcbebaff | ||
|
|
c4cc6b3e6e | ||
|
|
420ac9044e | ||
|
|
392dac5691 | ||
|
|
29744c01c6 | ||
|
|
a16adb9578 | ||
|
|
49e488df24 | ||
|
|
1a3f00eac8 | ||
|
|
c6ea8d5525 | ||
|
|
7738585d01 | ||
|
|
61bc24c6ea | ||
|
|
ae90001d7a | ||
|
|
c0ea3a097c | ||
|
|
abca57be11 | ||
|
|
645201480c | ||
|
|
8cffba3e22 | ||
|
|
8f62004f5b | ||
|
|
4fff6edb7b | ||
|
|
64cff4ba49 | ||
|
|
ce3c4d5661 | ||
|
|
5f333f0934 | ||
|
|
f70722934c | ||
|
|
b9eb9f10d4 | ||
|
|
6f89d94eef | ||
|
|
3a494d706a | ||
|
|
2ffbe07bcf | ||
|
|
371fd361a8 | ||
|
|
97416607e5 | ||
|
|
51ccbe7c7c | ||
|
|
65599399c7 | ||
|
|
c0816d4924 | ||
|
|
2988e97e14 | ||
|
|
046ceae500 | ||
|
|
33c0cda582 | ||
|
|
df7acc1075 | ||
|
|
3859e4b277 | ||
|
|
26253b65c7 | ||
|
|
424453ab57 | ||
|
|
d7de0ebd20 | ||
|
|
bf1c5140cd | ||
|
|
fb7a35db5b | ||
|
|
5872c2fbe3 | ||
|
|
ba04c70d5a | ||
|
|
de1e2d301f | ||
|
|
b67bdf779e | ||
|
|
78a3221395 | ||
|
|
f698b56dad | ||
|
|
4ed18fdf1d | ||
|
|
6e05f13c77 | ||
|
|
cb51d0af11 | ||
|
|
a146cd81b2 | ||
|
|
8dbd6df456 | ||
|
|
ac6d845c8d | ||
|
|
cfc9d1abcd | ||
|
|
a66748f6ca | ||
|
|
e5f46ead3b | ||
|
|
171023558e | ||
|
|
059a424b88 | ||
|
|
307b22deaf | ||
|
|
e405688f67 | ||
|
|
68554119f4 | ||
|
|
86a4a740ef | ||
|
|
0a004b83ca | ||
|
|
4fa47403c5 | ||
|
|
9e418ced53 | ||
|
|
bc04863439 | ||
|
|
77f259a435 | ||
|
|
16bcace663 | ||
|
|
52fddaa1cd | ||
|
|
f3d7400c15 | ||
|
|
7ebc3f3533 | ||
|
|
0ee94b425e | ||
|
|
d44a173945 | ||
|
|
ac001d6f32 | ||
|
|
e3de2df69c | ||
|
|
39d3c90b2f | ||
|
|
bca21defa5 | ||
|
|
dd3116ae7f | ||
|
|
49b3765eae | ||
|
|
1f5dd35bec | ||
|
|
e57b46979d | ||
|
|
683b67abb0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,7 +34,6 @@ latex
|
||||
html
|
||||
custom_titlebar
|
||||
libkddockwidgets.so*
|
||||
libkddockwidgets_multisplitter.so*
|
||||
*.depends
|
||||
kddockwidgets_basic_quick
|
||||
/src/KDDockWidgetsConfig.cmake
|
||||
|
||||
@@ -11,12 +11,17 @@
|
||||
|
||||
# Pass the following variables to cmake to control the build:
|
||||
#
|
||||
# -DKDDockWidgets_QT6=[true|false]
|
||||
# Build against Qt6 rather than Qt5
|
||||
# Default=false (Qt5 will be used even if Qt6 is available)
|
||||
#
|
||||
# -DKDDockWidgets_STATIC=[true|false]
|
||||
# Build static versions of the libraries
|
||||
# Default=false
|
||||
#
|
||||
# -DKDDockWidgets_TESTS=[true|false]
|
||||
# Build the test harness.
|
||||
# Currently does nothing unless you also set KDDockWidgets_DEVELOPER_MODE=True
|
||||
# Default=false
|
||||
#
|
||||
# -DKDDockWidgets_EXAMPLES=[true|false]
|
||||
@@ -42,9 +47,13 @@
|
||||
# Default=false
|
||||
#
|
||||
# -DKDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX=[path]
|
||||
# alternative install path for python bindings
|
||||
# Set an alternative install path for Python bindings
|
||||
# Default=CMAKE_INSTALL_PREFIX
|
||||
#
|
||||
# -DKDDockWidgets_UNITY_BUILD=[true|false]
|
||||
# Build with CMake's UNITY_BUILD (requires CMake version 3.16 or higher)
|
||||
# Default=true
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
if(POLICY CMP0020)
|
||||
@@ -72,19 +81,26 @@ else()
|
||||
endif()
|
||||
|
||||
set(${PROJECT_NAME}_VERSION_MAJOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 95)
|
||||
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 2)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 0)
|
||||
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
|
||||
set(${PROJECT_NAME}_SOVERSION "1.2")
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
option(${PROJECT_NAME}_QT6 "Build against Qt 6" OFF)
|
||||
option(${PROJECT_NAME}_DEVELOPER_MODE "Developer Mode" OFF)
|
||||
option(${PROJECT_NAME}_PYTHON_BINDINGS "Build python bindings" OFF)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
|
||||
option(${PROJECT_NAME}_UNITY_BUILD "Build with CMake's UNITY_BUILD" ON)
|
||||
endif()
|
||||
|
||||
|
||||
if(${PROJECT_NAME}_PYTHON_BINDINGS AND (CMAKE_BUILD_TYPE MATCHES "^[Dd]eb" OR ${PROJECT_NAME}_STATIC))
|
||||
message(FATAL_ERROR "** Python Bindings are disabled in debug or static builds.")
|
||||
endif()
|
||||
|
||||
option(${PROJECT_NAME}_TESTS "Build the tests" OFF)
|
||||
option(${PROJECT_NAME}_EXAMPLES "Build the examples" ON)
|
||||
option(${PROJECT_NAME}_DOCS "Build the API documentation" OFF)
|
||||
@@ -96,9 +112,18 @@ endif()
|
||||
|
||||
#option(${PROJECT_NAME}_QTQUICK "Build for QtQuick instead of QtWidgets" OFF)
|
||||
|
||||
find_package(Qt5Widgets 5.9 REQUIRED)
|
||||
if (${PROJECT_NAME}_QT6)
|
||||
find_package(Qt6Widgets REQUIRED)
|
||||
find_package(Qt6Test REQUIRED)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
else()
|
||||
find_package(Qt5Widgets 5.9 REQUIRED)
|
||||
find_package(Qt5Test 5.9 REQUIRED)
|
||||
set(QT_MAJOR_VERSION 5)
|
||||
endif()
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(ECM_MODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ECM/modules/")
|
||||
set(PYTHON_MODULE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake/Python")
|
||||
@@ -111,8 +136,8 @@ include(QtInstallPaths) #to set QT_INSTALL_FOO variables
|
||||
|
||||
macro(set_compiler_flags targetName)
|
||||
if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
target_compile_definitions(${targetName} PRIVATE DOCKS_DEVELOPER_MODE QT_FORCE_ASSERTS)
|
||||
if(NOT MSVC)
|
||||
target_compile_definitions(${targetName} PUBLIC DOCKS_DEVELOPER_MODE PRIVATE QT_FORCE_ASSERTS)
|
||||
if(NOT MSVC AND NOT ${PROJECT_NAME}_QT6) # We're not warnings clean with Qt6 yet
|
||||
target_compile_options(${targetName} PRIVATE -Wall -Wextra -Werror -Wno-error=deprecated-declarations)
|
||||
if (APPLE)
|
||||
target_compile_options(${targetName} PRIVATE -Wweak-vtables)
|
||||
@@ -163,7 +188,6 @@ endif()
|
||||
if(${PROJECT_NAME}_EXAMPLES)
|
||||
if (${PROJECT_NAME}_QTQUICK)
|
||||
add_subdirectory(examples/qtquick)
|
||||
set_compiler_flags(kddockwidgets_example_quick)
|
||||
else()
|
||||
add_subdirectory(examples/dockwidgets)
|
||||
add_subdirectory(examples/minimal)
|
||||
@@ -178,10 +202,9 @@ if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
|
||||
if (NOT ${PROJECT_NAME}_QTQUICK)
|
||||
#Require Qt5.15.1 or higher to run the tests_launcher tests on Mac
|
||||
if(NOT APPLE OR Qt5Widgets_VERSION VERSION_GREATER 5.15.0)
|
||||
# tst_docks.exe is pretty big (140 tests), so split it in 6 runs so we can use threads.
|
||||
# Require Qt5.15.1 or higher to run the tests_launcher tests on Mac
|
||||
if (NOT APPLE OR Qt5Widgets_VERSION VERSION_GREATER 5.15.0)
|
||||
# tst_docks.exe is pretty big (160 tests), so split it in more runs so we can use threads.
|
||||
add_test(NAME tst_docks0 COMMAND tests_launcher 0 5)
|
||||
add_test(NAME tst_docks1 COMMAND tests_launcher 1 5)
|
||||
add_test(NAME tst_docks2 COMMAND tests_launcher 2 5)
|
||||
@@ -204,15 +227,20 @@ if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
add_test(NAME tst_docks19 COMMAND tests_launcher 18 5)
|
||||
add_test(NAME tst_docks20 COMMAND tests_launcher 19 5)
|
||||
add_test(NAME tst_docks21 COMMAND tests_launcher 20 5) # one more for rounding leftovers
|
||||
endif()
|
||||
endif()
|
||||
if (NOT ${PROJECT_NAME}_QTQUICK)
|
||||
# tst_multisplitter depends on QWidget
|
||||
add_test(NAME tst_multisplitter COMMAND tst_multisplitter)
|
||||
endif()
|
||||
|
||||
add_test(NAME tst_multisplitter COMMAND tst_multisplitter)
|
||||
add_test(NAME tst_common COMMAND tst_common)
|
||||
|
||||
add_test(NAME tst_docks COMMAND tst_docks)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_DOCS)
|
||||
add_subdirectory(docs) # needs to go last, in case there are build source files
|
||||
endif()
|
||||
|
||||
if (${PROJECT_NAME}_UNITY_BUILD)
|
||||
set_target_properties(kddockwidgets PROPERTIES UNITY_BUILD ON)
|
||||
endif()
|
||||
|
||||
24
Changelog
24
Changelog
@@ -1,7 +1,19 @@
|
||||
* v1.2.0 (unreleased)
|
||||
- QtQuick support
|
||||
* v1.3.0 (unreleased)
|
||||
- [TODO] QtQuick support
|
||||
|
||||
* v1.1.0 (unreleased)
|
||||
* v1.2.0 (17 December 2020)
|
||||
- Wayland support
|
||||
- Added Flag_KeepAboveIfNotUtilityWindow, so you can have keep above even if
|
||||
floating window is shown in the task-bar.
|
||||
- Added DockWidget::windowActiveAboutToChange() signal
|
||||
- Added support for Qt6 (PySide6 support is lacking)
|
||||
- Added WASM support
|
||||
|
||||
* v1.1.1 (11 December 2020)
|
||||
- Windows: Fixed a crash when clicking on the close button for floating windows in some situations (#110)
|
||||
- Don't show dock/undock icon when dockwidget is not dockable (#99)
|
||||
|
||||
* v1.1.0 (26 October 2020)
|
||||
- New drop indicator style type: Segmented Indicators
|
||||
- Windows: Drop Shadow for floating windows
|
||||
- Added AutoHide / SideBar support
|
||||
@@ -12,6 +24,8 @@
|
||||
- Added Config::Flag_TitleBarHasMinimizeButton
|
||||
- Added Config::Flag_TitleBarNoFloatButton
|
||||
- Added Config::Flag_AutoHideSupport
|
||||
- Added Config::setTabbingAllowedFunc(TabbingAllowedFunc func)
|
||||
- HDPI improvements, new high-res icons
|
||||
- Bugfixes:
|
||||
- Windows: Fixed windows not having proper minimum size.
|
||||
- Windows: Fixed moving windows across screens with different DPI (#72)
|
||||
@@ -19,9 +33,7 @@
|
||||
- Fixed floating window's title not being correct (#74)
|
||||
- Fixed focus scope not reacting when clicking on current tab (#71)
|
||||
- Fixed floating window borders not being rendered correctly on HDPI due to rounding errors.
|
||||
|
||||
* v1.0.1 (unreleased)
|
||||
- cmake/Python - don't require pkg-config, only use if available (#68)
|
||||
- cmake/Python - don't require pkg-config, only use if available (#68)
|
||||
|
||||
* v1.0.0 (2 September 2020)
|
||||
- PySide2 bindings
|
||||
|
||||
29
README-WASM.md
Normal file
29
README-WASM.md
Normal file
@@ -0,0 +1,29 @@
|
||||
WebAssembly
|
||||
===========
|
||||
|
||||
KDDockWidgets works with WebAssembly with the following known limitations:
|
||||
|
||||
- Classic drop indicators are not supported, only the segmented ones. This is because
|
||||
WASM doesn't support windows with translucency.
|
||||
|
||||
- It's slow while dragging Windows and resizing.
|
||||
Please file a bug with Qt, as it's out of scope for KDDW to fix.
|
||||
|
||||
|
||||
Build tips for KDDW:
|
||||
====================
|
||||
|
||||
- Visit https://doc.qt.io/qt-5/wasm.html if you haven't yet
|
||||
- Open a terminal suitable for WASM development (with the correct Qt and toolchain in PATH, etc)
|
||||
- KDDockWidgets can be built with `cmake -DCMAKE_TOOLCHAIN_FILE=/usr/local/emsdk-1.39.8/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_FIND_ROOT_PATH=~/Qt/5.15.1/wasm_32/ -DKDDockWidgets_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Release`
|
||||
(Adapt the paths to your own situation)
|
||||
|
||||
Builds tips for your own app:
|
||||
=============================
|
||||
- Link to KDDW (libkddockwidgets.so, or similar)
|
||||
- As the build is static, don't forget to initialize KDDW's resources:
|
||||
```
|
||||
#ifdef QT_STATIC
|
||||
Q_INIT_RESOURCE(kddockwidgets_resources);
|
||||
#endif
|
||||
```
|
||||
34
README-Wayland.md
Normal file
34
README-Wayland.md
Normal file
@@ -0,0 +1,34 @@
|
||||
Wayland support is done and has been tested on KDE (Kwin) and weston.
|
||||
|
||||
Limitations
|
||||
============
|
||||
|
||||
Wayland works very differently than traditional desktops and imposes us some,
|
||||
limitations. Here's a list of different behaviours which KDDockWidgets will have
|
||||
when running on Wayland:
|
||||
|
||||
|
||||
- A title bar can either be used for drag&dock or for moving the window around.
|
||||
|
||||
- For this reason, floating windows now have two title bars.
|
||||
The native one, drawn by the server and the client one, drawn by KDDockWidgets.
|
||||
The native one allows you to drag the window around but not drop/dock.
|
||||
The client title bar allows you to perform a drag and drop/dock but not move the window around.
|
||||
|
||||
- You can detach a window by:
|
||||
- Clicking the title-bar's float button
|
||||
- Double-clicking the title bar of a docked widget
|
||||
- Double-clicking a tab
|
||||
- If no title bar is shown, double-clicking the empty space of the tab bar will detach
|
||||
the entire group of tabbed dock widgets
|
||||
|
||||
- Layout save/restore won't restore the position of floating windows, as wayland
|
||||
doesn't allow us to set geometry.
|
||||
|
||||
- Kwin specific:
|
||||
- The pixmap that's shown during a drag can't be bigger than 250x250. Might be a bug.
|
||||
|
||||
|
||||
|
||||
All in all it's pretty decent and usable. Any further improvements should be done at the server or
|
||||
protocol level now.
|
||||
@@ -43,6 +43,8 @@ Features
|
||||
- Customize title bars
|
||||
- Customize window frames
|
||||
- Custom widget separators
|
||||
- Crossplatform (macOS, Linux, Windows, WebAssembly, Wayland, X11/XCB, EGLFS are working)
|
||||
See README-Wayland.md and README-WASM.md for platform specific information.
|
||||
- Layouting engine honouring min/max size constraints and some size policies
|
||||
- PySide2 bindings
|
||||
- Clean codebase
|
||||
@@ -136,6 +138,7 @@ Supported Qt versions
|
||||
======================
|
||||
KDDockWidgets requires Qt >= 5.9 (or >=5.12 if Python bindings are enabled).
|
||||
The QtQuick support will require Qt >= 5.15.
|
||||
Qt 6 will be support as long as QTBUG-88611 is finished, most likely for 6.1.
|
||||
|
||||
Licensing
|
||||
=========
|
||||
@@ -170,3 +173,8 @@ to the Qt Project. We can give advanced or standard trainings anywhere
|
||||
around the globe on Qt as well as C++, OpenGL, 3D and more.
|
||||
|
||||
Please visit https://www.kdab.com to meet the people who write code like this.
|
||||
|
||||
Stay up-to-date with KDAB product announcements:
|
||||
|
||||
* [KDAB Newsletter](https://news.kdab.com)
|
||||
* [KDAB Blogs](https://www.kdab.com/category/blogs)
|
||||
|
||||
@@ -11,7 +11,7 @@ if (NOT ${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX)
|
||||
SET(${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE FILEPATH "Custom path to install python bindings.")
|
||||
endif()
|
||||
|
||||
message(STATUS "PYTHON INSTALL PREFIX ${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}")
|
||||
message(STATUS "PYTHON INSTALL PREFIX ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}")
|
||||
|
||||
if (WIN32)
|
||||
set(PATH_SEP "\;")
|
||||
@@ -153,5 +153,5 @@ macro(CREATE_PYTHON_BINDINGS
|
||||
LINK_FLAGS "-undefined dynamic_lookup")
|
||||
endif()
|
||||
install(TARGETS ${TARGET_NAME}
|
||||
LIBRARY DESTINATION ${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/${TARGET_NAME})
|
||||
LIBRARY DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/${TARGET_NAME})
|
||||
endmacro()
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
|
||||
#
|
||||
# Create variables for all the various install paths for the Qt version in use
|
||||
# Make sure to have found Qt5 before using this.
|
||||
# Make sure to have found Qt before using this.
|
||||
# sets variables like QT_INSTALL_PREFIX, QT_INSTALL_DATA, QT_INSTALL_DOCS, etc.
|
||||
# run qmake -query to see a full list
|
||||
|
||||
if(TARGET Qt5::qmake)
|
||||
get_target_property(QT_QMAKE_EXECUTABLE Qt5::qmake LOCATION)
|
||||
if(TARGET Qt${QT_MAJOR_VERSION}::qmake)
|
||||
get_target_property(QT_QMAKE_EXECUTABLE Qt${QT_MAJOR_VERSION}::qmake LOCATION)
|
||||
else()
|
||||
message(FATAL_ERROR "No supported Qt version found. Make sure you find Qt before calling this")
|
||||
endif()
|
||||
|
||||
@@ -11,7 +11,7 @@ from conans import ConanFile, CMake, tools
|
||||
|
||||
class KDDockWidgetsConan(ConanFile):
|
||||
name = "kddockwidgets"
|
||||
version = "1.1.95"
|
||||
version = "1.2.0"
|
||||
default_user = "kdab"
|
||||
default_channel = "stable"
|
||||
license = ("https://raw.githubusercontent.com/KDAB/KDDockWidgets/master/LICENSES/GPL-2.0-only.txt",
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
kddockwidgets (1.2.0) release candidate; urgency=high
|
||||
|
||||
* 1.2.0 final
|
||||
|
||||
-- Allen Winter <allen.winter@kdab.com> Thu, 17 Dec 2020 12:00:00 -0500
|
||||
|
||||
kddockwidgets (1.1.1) release candidate; urgency=high
|
||||
|
||||
* 1.1.1 final
|
||||
|
||||
-- Allen Winter <allen.winter@kdab.com> Fri, 11 Dec 2020 12:00:00 -0500
|
||||
|
||||
kddockwidgets (1.1.0) release candidate; urgency=high
|
||||
|
||||
* 1.1.0 final
|
||||
|
||||
-- Allen Winter <allen.winter@kdab.com> Mon, 26 Oct 2020 12:00:00 -0500
|
||||
|
||||
kddockwidgets (1.0.0) release candidate; urgency=high
|
||||
|
||||
* 1.0.0 final
|
||||
|
||||
@@ -31,7 +31,7 @@ add_custom_command(
|
||||
OUTPUT ${DOXYGEN_OUTPUT_DIR}/qch/kddockwidgets-api.qch
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
#handle a bug in doxygen where image files referred to in markdown are not copied the output
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/screencap.gif ${DOXYGEN_OUTPUT_DIR}/html
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/../../screencap.gif ${DOXYGEN_OUTPUT_DIR}/html
|
||||
DEPENDS ${_dox_deps} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
@@ -13,6 +13,7 @@ cmake_minimum_required(VERSION 3.7)
|
||||
project(kddockwidgets_example)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIRS ON)
|
||||
|
||||
if(NOT TARGET kddockwidgets)
|
||||
@@ -21,7 +22,7 @@ if(NOT TARGET kddockwidgets)
|
||||
find_package(KDDockWidgets REQUIRED)
|
||||
endif()
|
||||
|
||||
qt5_add_resources(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/resources_example.qrc)
|
||||
set(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_example
|
||||
main.cpp
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <QRandomGenerator>
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
@@ -26,8 +26,10 @@ using namespace KDDockWidgets;
|
||||
|
||||
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"));
|
||||
@@ -91,6 +93,9 @@ int main(int argc, char **argv)
|
||||
QCommandLineOption noUtilityWindows("u", QCoreApplication::translate("main", "FloatingWindows will be normal windows instead of utility windows"));
|
||||
parser.addOption(noUtilityWindows);
|
||||
|
||||
QCommandLineOption keepAbove("o", QCoreApplication::translate("main", "FloatingWindows will have Qt::WindowStaysOnTopHint. Implies not being an utility window (try it with -u too)"));
|
||||
parser.addOption(keepAbove);
|
||||
|
||||
parser.addPositionalArgument("savedlayout", QCoreApplication::translate("main", "loads the specified json file at startup"));
|
||||
|
||||
#ifdef KDDOCKWIDGETS_SUPPORTS_NESTED_MAINWINDOWS
|
||||
@@ -111,8 +116,13 @@ int main(int argc, char **argv)
|
||||
|
||||
QCommandLineOption noQtTool("no-qttool", QCoreApplication::translate("main", "(internal) Don't use Qt::Tool"));
|
||||
QCommandLineOption noParentForFloating("no-parent-for-floating", QCoreApplication::translate("main", "(internal) FloatingWindows won't have a parent"));
|
||||
QCommandLineOption nativeTitleBar("native-title-bar", QCoreApplication::translate("main", "(internal) FloatingWindows a native title bar"));
|
||||
QCommandLineOption noDropIndicators("no-drop-indicators", QCoreApplication::translate("main", "(internal) Don't use any drop indicators"));
|
||||
|
||||
parser.addOption(noQtTool);
|
||||
parser.addOption(noParentForFloating);
|
||||
parser.addOption(nativeTitleBar);
|
||||
parser.addOption(noDropIndicators);
|
||||
|
||||
# if defined(Q_OS_WIN)
|
||||
QCommandLineOption noAeroSnap("no-aero-snap", QCoreApplication::translate("main", "(internal) Disable AeroSnap"));
|
||||
@@ -143,12 +153,21 @@ int main(int argc, char **argv)
|
||||
if (parser.isSet(noQtTool))
|
||||
flags |= KDDockWidgets::Config::Flag_internal_DontUseQtToolWindowsForFloatingWindows;
|
||||
|
||||
if (parser.isSet(keepAbove))
|
||||
flags |= KDDockWidgets::Config::Flag_KeepAboveIfNotUtilityWindow;
|
||||
|
||||
if (parser.isSet(noParentForFloating))
|
||||
flags |= KDDockWidgets::Config::Flag_internal_DontUseParentForFloatingWindows;
|
||||
|
||||
if (parser.isSet(nativeTitleBar))
|
||||
flags |= KDDockWidgets::Config::Flag_NativeTitleBar;
|
||||
|
||||
if (parser.isSet(noDropIndicators))
|
||||
KDDockWidgets::DefaultWidgetFactory::s_dropIndicatorType = KDDockWidgets::DropIndicatorType::None;
|
||||
|
||||
# if defined(Q_OS_WIN)
|
||||
if (parser.isSet(noAeroSnap))
|
||||
flags &= ~KDDockWidgets::Config::Flag_AeroSnapWithClientDecos;
|
||||
flags |= KDDockWidgets::Config::Flag_internal_NoAeroSnap;
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,6 +13,7 @@ cmake_minimum_required(VERSION 3.7)
|
||||
project(kddockwidgets_minimal_example)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIRS ON)
|
||||
|
||||
if(NOT TARGET kddockwidgets)
|
||||
@@ -21,7 +22,7 @@ if(NOT TARGET kddockwidgets)
|
||||
find_package(KDDockWidgets REQUIRED)
|
||||
endif()
|
||||
|
||||
qt5_add_resources(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../dockwidgets/resources_example.qrc)
|
||||
set(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../dockwidgets/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_minimal_example
|
||||
main.cpp
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <kddockwidgets/MainWindow.h>
|
||||
|
||||
#include <QStyleFactory>
|
||||
#include <QApplication>
|
||||
|
||||
// clazy:excludeall=qstring-allocations
|
||||
|
||||
@@ -22,8 +23,10 @@ using namespace KDDockWidgets;
|
||||
|
||||
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"));
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# SPDX-FileCopyrightText: 2020 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
|
||||
@@ -9,26 +8,8 @@
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(kddockwidgets_example_quick)
|
||||
add_subdirectory(customtitlebar)
|
||||
add_subdirectory(dockwidgets)
|
||||
|
||||
set(CMAKE_AUTOMOC 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()
|
||||
|
||||
qt5_add_resources(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_example_quick
|
||||
main.cpp
|
||||
${RESOURCES_EXAMPLE_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(kddockwidgets_example_quick
|
||||
PRIVATE
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
set_compiler_flags(kddockwidgets_example_quick)
|
||||
set_compiler_flags(kddockwidgets_customtitlebar_quick)
|
||||
|
||||
37
examples/qtquick/customtitlebar/CMakeLists.txt
Normal file
37
examples/qtquick/customtitlebar/CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2020 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_customtitlebar_quick)
|
||||
|
||||
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}/resources_qtquick_example.qrc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../dockwidgets/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_customtitlebar_quick
|
||||
main.cpp
|
||||
${RESOURCES_EXAMPLE_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(kddockwidgets_customtitlebar_quick
|
||||
PRIVATE
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
36
examples/qtquick/customtitlebar/Guest.qml
Normal file
36
examples/qtquick/customtitlebar/Guest.qml
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
property alias background: background.source
|
||||
property alias logo: logo.source
|
||||
|
||||
|
||||
Image {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
Image {
|
||||
id: logo
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
examples/qtquick/customtitlebar/Guest1.qml
Normal file
18
examples/qtquick/customtitlebar/Guest1.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
background: "qrc:/assets/triangles.png"
|
||||
logo: "qrc:/assets/KDAB_bubble_white.png"
|
||||
}
|
||||
@@ -11,10 +11,7 @@
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "pink"
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget #2!"
|
||||
}
|
||||
logo: "qrc:/assets/KDAB_bubble_blue.png"
|
||||
}
|
||||
@@ -11,10 +11,8 @@
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "lightblue"
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget #1 !"
|
||||
}
|
||||
background: "qrc:/assets/base.png"
|
||||
logo: "qrc:/assets/KDAB_bubble_fulcolor.png"
|
||||
}
|
||||
54
examples/qtquick/customtitlebar/MyTitleBar.qml
Normal file
54
examples/qtquick/customtitlebar/MyTitleBar.qml
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.6
|
||||
|
||||
// Will be moved to a plugin in the future
|
||||
import "qrc:/kddockwidgets/private/quick/qml/" as KDDW
|
||||
|
||||
KDDW.TitleBarBase {
|
||||
id: root
|
||||
color: "black"
|
||||
border.color: "orange"
|
||||
border.width: 2
|
||||
heightWhenVisible: 50
|
||||
|
||||
Text {
|
||||
color: "orange"
|
||||
font.bold: true
|
||||
text: root.title
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 10
|
||||
verticalCenter: root.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: closeButton
|
||||
enabled: root.closeButtonEnabled
|
||||
radius: 5
|
||||
color: "green"
|
||||
height: root.height - 20
|
||||
width: height
|
||||
anchors {
|
||||
right: root.right
|
||||
rightMargin: 10
|
||||
verticalCenter: root.verticalCenter
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
root.closeButtonClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,17 +10,41 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "private/DockRegistry_p.h"
|
||||
#include "private/quick/DockWidgetQuick.h"
|
||||
#include "Config.h"
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/DockWidgetQuick.h>
|
||||
#include <kddockwidgets/private/DockRegistry_p.h>
|
||||
#include <kddockwidgets/FrameworkWidgetFactory.h>
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QGuiApplication>
|
||||
|
||||
class CustomFrameworkWidgetFactory : public KDDockWidgets::DefaultWidgetFactory
|
||||
{
|
||||
public:
|
||||
|
||||
~CustomFrameworkWidgetFactory() override;
|
||||
|
||||
QUrl titleBarFilename() const override
|
||||
{
|
||||
return QUrl("qrc:/MyTitleBar.qml");
|
||||
}
|
||||
};
|
||||
|
||||
CustomFrameworkWidgetFactory::~CustomFrameworkWidgetFactory() = default;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
QGuiApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
#endif
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
auto &config = KDDockWidgets::Config::self();
|
||||
auto flags = config.flags();
|
||||
|
||||
config.setFlags(flags);
|
||||
config.setFrameworkWidgetFactory(new CustomFrameworkWidgetFactory());
|
||||
|
||||
QQuickView view;
|
||||
view.setObjectName("MainWindow QQuickView");
|
||||
KDDockWidgets::Config::self().setQmlEngine(view.engine());
|
||||
@@ -42,13 +66,10 @@ int main(int argc, char *argv[])
|
||||
|
||||
auto dw3 = new KDDockWidgets::DockWidgetQuick("Dock #3");
|
||||
dw3->setWidget(QStringLiteral("qrc:/Guest3.qml"));
|
||||
dw3->resize(QSize(800, 800));
|
||||
dw3->show();
|
||||
|
||||
dw1->addDockWidgetToContainingWindow(dw3, KDDockWidgets::Location_OnRight);
|
||||
|
||||
KDDockWidgets::MainWindowBase *mainWindow = KDDockWidgets::DockRegistry::self()->mainwindows().constFirst();
|
||||
mainWindow->addDockWidget(dw2, KDDockWidgets::Location_OnTop);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>main.qml</file>
|
||||
<file>Guest1.qml</file>
|
||||
<file>Guest2.qml</file>
|
||||
<file>Guest3.qml</file>
|
||||
<file>Guest.qml</file>
|
||||
<file>MyTitleBar.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -12,9 +12,7 @@
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "blue"
|
||||
id: root
|
||||
color: "green"
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget!"
|
||||
}
|
||||
}
|
||||
37
examples/qtquick/dockwidgets/CMakeLists.txt
Normal file
37
examples/qtquick/dockwidgets/CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2020 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_example_quick)
|
||||
|
||||
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}/resources_qtquick_example.qrc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../dockwidgets/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_example_quick
|
||||
main.cpp
|
||||
${RESOURCES_EXAMPLE_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(kddockwidgets_example_quick
|
||||
PRIVATE
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
36
examples/qtquick/dockwidgets/Guest.qml
Normal file
36
examples/qtquick/dockwidgets/Guest.qml
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
property alias background: background.source
|
||||
property alias logo: logo.source
|
||||
|
||||
|
||||
Image {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
Image {
|
||||
id: logo
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 50
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
examples/qtquick/dockwidgets/Guest1.qml
Normal file
47
examples/qtquick/dockwidgets/Guest1.qml
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.12
|
||||
import com.kdab.dockwidgets 1.0 as KDDW
|
||||
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
background: "qrc:/assets/triangles.png"
|
||||
logo: "qrc:/assets/KDAB_bubble_white.png"
|
||||
|
||||
KDDW.DockWidget {
|
||||
id: another
|
||||
uniqueName: "another1"
|
||||
source: ":/Another.qml"
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Toggle Another"
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
margins: 5
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
|
||||
if (another.dockWidget.visible) {
|
||||
another.dockWidget.close();
|
||||
} else {
|
||||
another.dockWidget.show();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,10 +11,7 @@
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "gray"
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
Text {
|
||||
text: "Guest Widget #3!"
|
||||
}
|
||||
logo: "qrc:/assets/KDAB_bubble_blue.png"
|
||||
}
|
||||
18
examples/qtquick/dockwidgets/Guest3.qml
Normal file
18
examples/qtquick/dockwidgets/Guest3.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
background: "qrc:/assets/base.png"
|
||||
logo: "qrc:/assets/KDAB_bubble_fulcolor.png"
|
||||
}
|
||||
103
examples/qtquick/dockwidgets/main.cpp
Normal file
103
examples/qtquick/dockwidgets/main.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/DockWidgetQuick.h>
|
||||
#include <kddockwidgets/private/DockRegistry_p.h>
|
||||
#include <kddockwidgets/FrameworkWidgetFactory.h>
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QGuiApplication>
|
||||
#include <QCommandLineParser>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
QGuiApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
#endif
|
||||
QGuiApplication app(argc, argv);
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("KDDockWidgets example application");
|
||||
parser.addHelpOption();
|
||||
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
QCommandLineOption noQtTool("no-qttool", QCoreApplication::translate("main", "(internal) Don't use Qt::Tool"));
|
||||
QCommandLineOption noParentForFloating("no-parent-for-floating", QCoreApplication::translate("main", "(internal) FloatingWindows won't have a parent"));
|
||||
QCommandLineOption nativeTitleBar("native-title-bar", QCoreApplication::translate("main", "(internal) FloatingWindows a native title bar"));
|
||||
QCommandLineOption noDropIndicators("no-drop-indicators", QCoreApplication::translate("main", "(internal) Don't use any drop indicators"));
|
||||
|
||||
parser.addOption(noQtTool);
|
||||
parser.addOption(noParentForFloating);
|
||||
parser.addOption(nativeTitleBar);
|
||||
parser.addOption(noDropIndicators);
|
||||
|
||||
# if defined(Q_OS_WIN)
|
||||
QCommandLineOption noAeroSnap("no-aero-snap", QCoreApplication::translate("main", "(internal) Disable AeroSnap"));
|
||||
parser.addOption(noAeroSnap);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
auto flags = KDDockWidgets::Config::self().flags();
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(noQtTool))
|
||||
flags |= KDDockWidgets::Config::Flag_internal_DontUseQtToolWindowsForFloatingWindows;
|
||||
|
||||
if (parser.isSet(noParentForFloating))
|
||||
flags |= KDDockWidgets::Config::Flag_internal_DontUseParentForFloatingWindows;
|
||||
|
||||
if (parser.isSet(nativeTitleBar))
|
||||
flags |= KDDockWidgets::Config::Flag_NativeTitleBar;
|
||||
else if (parser.isSet(noDropIndicators))
|
||||
KDDockWidgets::DefaultWidgetFactory::s_dropIndicatorType = KDDockWidgets::DropIndicatorType::None;
|
||||
|
||||
# if defined(Q_OS_WIN)
|
||||
if (parser.isSet(noAeroSnap))
|
||||
flags |= KDDockWidgets::Config::Flag_internal_NoAeroSnap;
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
KDDockWidgets::Config::self().setFlags(flags);
|
||||
|
||||
QQuickView view;
|
||||
view.setObjectName("MainWindow QQuickView");
|
||||
KDDockWidgets::Config::self().setQmlEngine(view.engine());
|
||||
view.resize(1000, 800);
|
||||
view.show();
|
||||
view.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
|
||||
auto dw1 = new KDDockWidgets::DockWidgetQuick("Dock #1");
|
||||
view.setSource(QUrl("qrc:/main.qml"));
|
||||
|
||||
dw1->setWidget(QStringLiteral("qrc:/Guest1.qml"));
|
||||
dw1->resize(QSize(800, 800));
|
||||
dw1->show();
|
||||
|
||||
auto dw2 = new KDDockWidgets::DockWidgetQuick("Dock #2");
|
||||
dw2->setWidget(QStringLiteral("qrc:/Guest2.qml"));
|
||||
dw2->resize(QSize(800, 800));
|
||||
dw2->show();
|
||||
|
||||
auto dw3 = new KDDockWidgets::DockWidgetQuick("Dock #3");
|
||||
dw3->setWidget(QStringLiteral("qrc:/Guest3.qml"));
|
||||
|
||||
dw1->addDockWidgetToContainingWindow(dw3, KDDockWidgets::Location_OnRight);
|
||||
|
||||
KDDockWidgets::MainWindowBase *mainWindow = KDDockWidgets::DockRegistry::self()->mainwindows().constFirst();
|
||||
mainWindow->addDockWidget(dw2, KDDockWidgets::Location_OnTop);
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
23
examples/qtquick/dockwidgets/main.qml
Normal file
23
examples/qtquick/dockwidgets/main.qml
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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.
|
||||
*/
|
||||
|
||||
import QtQuick 2.6
|
||||
import com.kdab.dockwidgets 1.0 as KDDW
|
||||
|
||||
KDDW.MainWindow {
|
||||
id: root
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
root.init("MyWindowName-1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,7 @@
|
||||
<file>Guest1.qml</file>
|
||||
<file>Guest2.qml</file>
|
||||
<file>Guest3.qml</file>
|
||||
<file>Guest.qml</file>
|
||||
<file>Another.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
1
kddockwidgets-rpmlintrc
Normal file
1
kddockwidgets-rpmlintrc
Normal file
@@ -0,0 +1 @@
|
||||
addFilter("E: shlib-policy-name-error")
|
||||
@@ -1,10 +1,10 @@
|
||||
Format: 1.0
|
||||
Source: kddockwidgets
|
||||
Version: 1.0.0
|
||||
Version: 1.2.0-1
|
||||
Binary: kddockwidgets
|
||||
Maintainer: Allen Winter <allen.winter@kdab.com>
|
||||
Architecture: any
|
||||
Build-Depends: debhelper (>=9), cdbs, cmake, qt5-default, qtbase5-dev, libqt5x11extras5-dev
|
||||
|
||||
Files:
|
||||
00000000000000000000000000000000 00000 kddockwidgets-1.0.0.tar.gz
|
||||
00000000000000000000000000000000 00000 kddockwidgets-1.2.0.tar.gz
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
Name: kddockwidgets
|
||||
Version: 1.0.0
|
||||
Version: 1.2.0
|
||||
Release: 1
|
||||
Summary: KDAB's Dock Widget Framework for Qt
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
Source1: %{name}-%{version}.tar.gz.asc
|
||||
Source2: %{name}-rpmlintrc
|
||||
URL: https://github.com/KDAB/KDDockWidgets
|
||||
Group: System/Libraries
|
||||
License: GPL-2.0-only OR GPL-3.0-only
|
||||
@@ -75,7 +76,6 @@ cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
|
||||
%defattr(-,root,root)
|
||||
%{_prefix}/share/doc/KDDockWidgets
|
||||
%{_libdir}/libkddockwidgets.so.*
|
||||
%{_libdir}/libkddockwidgets_multisplitter.so.*
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
@@ -85,10 +85,15 @@ cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
|
||||
%dir %{_libdir}/cmake/KDDockWidgets
|
||||
%{_libdir}/cmake/KDDockWidgets/*
|
||||
%{_libdir}/libkddockwidgets.so
|
||||
%{_libdir}/libkddockwidgets_multisplitter.so
|
||||
|
||||
%changelog
|
||||
* Wed Sep 02 2020 Allen Winter <allen.winter@kdb.com> 1.0.0
|
||||
* Thu Dec 17 2020 Allen Winter <allen.winter@kdab.com> 1.2.0
|
||||
1.2.0 final
|
||||
* Fri Dec 11 2020 Allen Winter <allen.winter@kdab.com> 1.1.1
|
||||
1.1.1 final
|
||||
* Mon Oct 26 2020 Allen Winter <allen.winter@kdab.com> 1.1.0
|
||||
1.1.0 final
|
||||
* Wed Sep 02 2020 Allen Winter <allen.winter@kdab.com> 1.0.0
|
||||
1.0.0 final
|
||||
* Thu Aug 06 2020 Allen Winter <allen.winter@kdb.com> 0.99.9
|
||||
* Thu Aug 06 2020 Allen Winter <allen.winter@kdab.com> 0.99.9
|
||||
1.0.0 release candidate
|
||||
|
||||
@@ -41,7 +41,7 @@ set(PyKDDockWidgets_typesystem_paths
|
||||
|
||||
# Include flags/path that will be set in 'target_include_directories'
|
||||
set(PyKDDockWidgets_target_include_directories
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
# Libraries that will be necessary to link the target, this will used in the command 'target_link_libraries'
|
||||
@@ -74,8 +74,8 @@ create_python_bindings(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
# Make moduled import from build dir works
|
||||
# Make module import from build dir work
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${CMAKE_CURRENT_BINARY_DIR}/__init__.py)
|
||||
|
||||
# install
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py DESTINATION ${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/PyKDDockWidgets)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/PyKDDockWidgets)
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
// Define PYTHON_BINDINGS this will be used in some part of c++ to skip problematic parts
|
||||
#define PYTHON_BINDINGS
|
||||
|
||||
#include <MainWindowBase.h>
|
||||
#include <MainWindow.h>
|
||||
#include <DockWidgetBase.h>
|
||||
#include <DockWidget.h>
|
||||
#ifndef QT_WIDGETS_LIB
|
||||
# define QT_WIDGETS_LIB
|
||||
#endif
|
||||
|
||||
#include <kddockwidgets/MainWindowBase.h>
|
||||
#include <kddockwidgets/MainWindow.h>
|
||||
#include <kddockwidgets/DockWidgetBase.h>
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
|
||||
@@ -23,30 +23,66 @@ add_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS
|
||||
|
||||
set(DOCKSLIBS_SRCS
|
||||
Config.cpp
|
||||
Config.h
|
||||
Qt5Qt6Compat_p.h
|
||||
FocusScope.cpp
|
||||
FocusScope.h
|
||||
FrameworkWidgetFactory.cpp
|
||||
FrameworkWidgetFactory.h
|
||||
DockWidgetBase.cpp
|
||||
DockWidgetBase.h
|
||||
MainWindowBase.cpp
|
||||
MainWindowBase.h
|
||||
LayoutSaver.cpp
|
||||
LayoutSaver.h
|
||||
LayoutSaver_p.h
|
||||
private/MultiSplitter.cpp
|
||||
private/MultiSplitter_p.h
|
||||
private/Position.cpp
|
||||
private/ObjectViewer.cpp
|
||||
private/Position_p.h
|
||||
private/DropIndicatorOverlayInterface.cpp
|
||||
private/DropIndicatorOverlayInterface_p.h
|
||||
private/DropArea.cpp
|
||||
private/DropArea_p.h
|
||||
private/FloatingWindow.cpp
|
||||
private/FloatingWindow_p.h
|
||||
private/Logging.cpp
|
||||
private/Logging_p.h
|
||||
private/TitleBar.cpp
|
||||
private/TitleBar_p.h
|
||||
private/SideBar.cpp
|
||||
private/SideBar_p.h
|
||||
private/DockRegistry.cpp
|
||||
private/DockRegistry_p.h
|
||||
private/Draggable.cpp
|
||||
private/Draggable_p.h
|
||||
private/WindowBeingDragged.cpp
|
||||
private/WindowBeingDragged_p.h
|
||||
private/DragController.cpp
|
||||
private/DragController_p.h
|
||||
private/Frame.cpp
|
||||
private/Frame_p.h
|
||||
private/DropAreaWithCentralFrame.cpp
|
||||
private/DropAreaWithCentralFrame_p.h
|
||||
private/WidgetResizeHandler.cpp
|
||||
private/WidgetResizeHandler_p.h
|
||||
private/indicators/NullIndicators.cpp
|
||||
private/indicators/NullIndicators_p.h
|
||||
private/indicators/ClassicIndicators.cpp
|
||||
private/indicators/ClassicIndicators_p.h
|
||||
private/indicators/ClassicIndicatorsWindow.cpp
|
||||
private/indicators/ClassicIndicatorsWindow_p.h
|
||||
|
||||
private/multisplitter/Item.cpp
|
||||
private/multisplitter/Item_p.h
|
||||
private/multisplitter/Logging.cpp
|
||||
private/multisplitter/Logging_p.h
|
||||
private/multisplitter/MultiSplitterConfig.cpp
|
||||
private/multisplitter/MultiSplitterConfig.h
|
||||
private/multisplitter/Separator.cpp
|
||||
private/multisplitter/Separator_p.h
|
||||
private/multisplitter/Widget.cpp
|
||||
private/multisplitter/Widget.h
|
||||
)
|
||||
|
||||
set(DOCKS_INSTALLABLE_INCLUDES
|
||||
@@ -55,6 +91,7 @@ set(DOCKS_INSTALLABLE_INCLUDES
|
||||
FrameworkWidgetFactory.h
|
||||
DockWidgetBase.h
|
||||
KDDockWidgets.h
|
||||
Qt5Qt6Compat_p.h
|
||||
FocusScope.h
|
||||
QWidgetAdapter.h
|
||||
LayoutSaver.h
|
||||
@@ -70,6 +107,7 @@ set(DOCKS_INSTALLABLE_PRIVATE_INCLUDES
|
||||
private/SideBar_p.h
|
||||
private/TitleBar_p.h
|
||||
private/WindowBeingDragged_p.h
|
||||
private/DockRegistry_p.h
|
||||
)
|
||||
|
||||
set(DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES
|
||||
@@ -85,33 +123,67 @@ set(DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
set(DOCKSLIBS_SRCS ${DOCKSLIBS_SRCS}
|
||||
private/quick/DockWidgetQuick.cpp
|
||||
DockWidgetQuick.cpp
|
||||
DockWidgetQuick.h
|
||||
private/quick/DockWidgetInstantiator.cpp
|
||||
private/quick/DockWidgetInstantiator_p.h
|
||||
private/quick/QWidgetAdapter_quick.cpp
|
||||
private/quick/QWidgetAdapter_quick_p.h
|
||||
private/quick/FloatingWindowQuick.cpp
|
||||
private/quick/FloatingWindowQuick_p.h
|
||||
private/quick/TitleBarQuick.cpp
|
||||
private/quick/TitleBarQuick_p.h
|
||||
private/quick/QmlTypes.cpp
|
||||
private/quick/QmlTypes.h
|
||||
private/quick/FrameQuick.cpp
|
||||
private/quick/FrameQuick_p.h
|
||||
private/quick/RubberBandQuick.cpp
|
||||
private/quick/RubberBandQuick.h
|
||||
private/quick/MainWindowQuick.cpp
|
||||
private/quick/MainWindowQuick_p.h
|
||||
private/quick/MainWindowWrapper.cpp
|
||||
)
|
||||
|
||||
qt5_add_resources(RESOURCES_QUICK ${CMAKE_CURRENT_SOURCE_DIR}/qtquick.qrc)
|
||||
private/quick/MainWindowWrapper_p.h
|
||||
private/multisplitter/Widget_quick.cpp
|
||||
private/multisplitter/Widget_quick.h
|
||||
private/multisplitter/Separator_quick.cpp
|
||||
private/multisplitter/Separator_quick.h
|
||||
private/multisplitter/Rubberband_quick.cpp
|
||||
private/multisplitter/Rubberband_quick.h
|
||||
kddockwidgets_qtquick.qrc)
|
||||
else()
|
||||
set(DOCKSLIBS_SRCS ${DOCKSLIBS_SRCS}
|
||||
private/DebugWindow.cpp
|
||||
private/DebugWindow_p.h
|
||||
private/ObjectViewer.cpp
|
||||
private/ObjectViewer_p.h
|
||||
MainWindow.cpp
|
||||
MainWindow.h
|
||||
DockWidget.h
|
||||
private/multisplitter/Widget_qwidget.cpp
|
||||
private/multisplitter/Widget_qwidget.h
|
||||
private/multisplitter/Separator_qwidget.cpp
|
||||
private/multisplitter/Separator_qwidget.h
|
||||
private/widgets/TabWidget.cpp
|
||||
private/widgets/TabWidget_p.h
|
||||
private/widgets/TabBarWidget.cpp
|
||||
private/widgets/TabBarWidget_p.h
|
||||
private/widgets/FloatingWindowWidget.cpp
|
||||
private/widgets/FloatingWindowWidget_p.h
|
||||
private/widgets/FrameWidget.cpp
|
||||
private/widgets/FrameWidget_p.h
|
||||
private/widgets/SideBarWidget.cpp
|
||||
private/widgets/SideBarWidget_p.h
|
||||
private/widgets/TabWidgetWidget.cpp
|
||||
private/widgets/TabWidgetWidget_p.h
|
||||
private/widgets/TitleBarWidget.cpp
|
||||
private/widgets/TitleBarWidget_p.h
|
||||
private/widgets/DockWidget.cpp
|
||||
private/widgets/QWidgetAdapter_widgets.cpp
|
||||
private/widgets/QWidgetAdapter_widgets_p.h
|
||||
private/indicators/SegmentedIndicators.cpp
|
||||
private/indicators/SegmentedIndicators_p.h
|
||||
# private/indicators/AnimatedIndicators.cpp
|
||||
)
|
||||
)
|
||||
|
||||
set(DOCKS_INSTALLABLE_INCLUDES
|
||||
${DOCKS_INSTALLABLE_INCLUDES}
|
||||
@@ -127,9 +199,7 @@ else()
|
||||
set(IS_CLANG_BUILD FALSE)
|
||||
endif()
|
||||
|
||||
add_subdirectory(private/multisplitter)
|
||||
|
||||
qt5_add_resources(RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/resources.qrc)
|
||||
set(RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/kddockwidgets_resources.qrc)
|
||||
|
||||
add_library(kddockwidgets ${KDDockWidgets_LIBRARY_MODE} ${DOCKSLIBS_SRCS} ${DOCKS_INSTALLABLE_INCLUDES} ${RESOURCES} ${RESOURCES_QUICK})
|
||||
add_library(KDAB::kddockwidgets ALIAS kddockwidgets)
|
||||
@@ -138,12 +208,11 @@ set_compiler_flags(kddockwidgets)
|
||||
target_include_directories(kddockwidgets
|
||||
PUBLIC
|
||||
$<INSTALL_INTERFACE:include>
|
||||
$<INSTALL_INTERFACE:include/kddockwidgets>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/fwd_headers>
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/private
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/private/multisplitter/
|
||||
)
|
||||
|
||||
target_compile_definitions(kddockwidgets
|
||||
@@ -168,19 +237,23 @@ if(CMAKE_COMPILER_IS_GNUCXX OR IS_CLANG_BUILD)
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt5::Widgets Qt5::Quick Qt5::QuickControls2 kddockwidgets_multisplitter PRIVATE Qt5::GuiPrivate)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${QT_MAJOR_VERSION}::Widgets Qt${QT_MAJOR_VERSION}::Quick Qt${QT_MAJOR_VERSION}::QuickControls2)
|
||||
else()
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt5::Widgets kddockwidgets_multisplitter PRIVATE Qt5::GuiPrivate)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${QT_MAJOR_VERSION}::Widgets)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(kddockwidgets PRIVATE Dwmapi)
|
||||
elseif(NOT APPLE)
|
||||
find_package(Qt5X11Extras)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt5::X11Extras)
|
||||
target_link_libraries(kddockwidgets PRIVATE Qt${QT_MAJOR_VERSION}::GuiPrivate Dwmapi)
|
||||
elseif(NOT APPLE AND NOT EMSCRIPTEN AND NOT ${PROJECT_NAME}_QT6)
|
||||
find_package(Qt${QT_MAJOR_VERSION}X11Extras)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${QT_MAJOR_VERSION}::X11Extras)
|
||||
endif()
|
||||
|
||||
set_target_properties(kddockwidgets PROPERTIES VERSION ${${PROJECT_NAME}_SOVERSION})
|
||||
set_target_properties(kddockwidgets PROPERTIES
|
||||
SOVERSION ${${PROJECT_NAME}_SOVERSION}
|
||||
VERSION ${${PROJECT_NAME}_VERSION}
|
||||
)
|
||||
|
||||
#version libraries on Windows
|
||||
if(WIN32)
|
||||
set(postfix ${${PROJECT_NAME}_VERSION_MAJOR})
|
||||
@@ -208,7 +281,6 @@ install(FILES private/multisplitter/Widget.h DESTINATION include/kddockwidgets/p
|
||||
install(FILES private/multisplitter/Widget_qwidget.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Separator_p.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Separator_qwidget.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/multisplitter_export.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES} DESTINATION include/kddockwidgets/private/widgets)
|
||||
|
||||
install(FILES private/indicators/ClassicIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
|
||||
@@ -238,6 +310,7 @@ if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
|
||||
if (NOT ${PROJECT_NAME}_QTQUICK) # TODO: We can support it
|
||||
add_executable(kddockwidgets_linter layoutlinter_main.cpp)
|
||||
target_link_libraries(kddockwidgets_linter kddockwidgets kddockwidgets_multisplitter Qt5::Widgets)
|
||||
target_link_libraries(kddockwidgets_linter kddockwidgets Qt${QT_MAJOR_VERSION}::Widgets)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
@@ -18,15 +18,19 @@
|
||||
|
||||
#include "Config.h"
|
||||
#include "multisplitter/MultiSplitterConfig.h"
|
||||
#include "multisplitter/Widget_qwidget.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QOperatingSystemVersion>
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
# include <QQmlEngine>
|
||||
# include <QQmlContext>
|
||||
#endif
|
||||
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
|
||||
@@ -48,7 +52,8 @@ public:
|
||||
QQmlEngine *m_qmlEngine = nullptr;
|
||||
DockWidgetFactoryFunc m_dockWidgetFactoryFunc = nullptr;
|
||||
MainWindowFactoryFunc m_mainWindowFactoryFunc = nullptr;
|
||||
FrameworkWidgetFactory *m_frameworkWidgetFactory;
|
||||
TabbingAllowedFunc m_tabbingAllowedFunc = nullptr;
|
||||
FrameworkWidgetFactory *m_frameworkWidgetFactory = nullptr;
|
||||
Flags m_flags = Flag_Default;
|
||||
qreal m_draggedWindowOpacity = Q_QNAN;
|
||||
};
|
||||
@@ -157,6 +162,17 @@ qreal Config::draggedWindowOpacity() const
|
||||
return d->m_draggedWindowOpacity;
|
||||
}
|
||||
|
||||
void Config::setTabbingAllowedFunc(TabbingAllowedFunc func)
|
||||
{
|
||||
d->m_tabbingAllowedFunc = func;
|
||||
}
|
||||
|
||||
TabbingAllowedFunc Config::tabbingAllowedFunc() const
|
||||
{
|
||||
return d->m_tabbingAllowedFunc;
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
void Config::setQmlEngine(QQmlEngine *qmlEngine)
|
||||
{
|
||||
if (d->m_qmlEngine) {
|
||||
@@ -164,13 +180,22 @@ void Config::setQmlEngine(QQmlEngine *qmlEngine)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qmlEngine) {
|
||||
qWarning() << Q_FUNC_INFO << "Null QML engine";
|
||||
return;
|
||||
}
|
||||
|
||||
d->m_qmlEngine = qmlEngine;
|
||||
|
||||
QQmlContext *context = qmlEngine->rootContext();
|
||||
context->setContextProperty(QStringLiteral("_kddw_widgetFactory"), d->m_frameworkWidgetFactory);
|
||||
}
|
||||
|
||||
QQmlEngine *Config::qmlEngine() const
|
||||
{
|
||||
return d->m_qmlEngine;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Config::Private::fixFlags()
|
||||
{
|
||||
@@ -206,9 +231,19 @@ void Config::Private::fixFlags()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
|
||||
#if (!defined(Q_OS_WIN) && !defined(Q_OS_MACOS))
|
||||
// QtQuick doesn't support AeroSnap yet. Some problem with the native events not being received...
|
||||
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
// We allow to disable aero-snap during development
|
||||
if (m_flags & Flag_internal_NoAeroSnap) {
|
||||
// The only way to disable AeroSnap
|
||||
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
77
src/Config.h
77
src/Config.h
@@ -35,6 +35,14 @@ class FrameworkWidgetFactory;
|
||||
typedef KDDockWidgets::DockWidgetBase* (*DockWidgetFactoryFunc)(const QString &name);
|
||||
typedef KDDockWidgets::MainWindowBase* (*MainWindowFactoryFunc)(const QString &name);
|
||||
|
||||
/// @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
|
||||
/// @return true if the docking is allowed.
|
||||
/// @sa setTabbingAllowedFunc
|
||||
typedef bool (*TabbingAllowedFunc)(const QVector<DockWidgetBase*> &source,
|
||||
const QVector<DockWidgetBase*> &target);
|
||||
|
||||
/**
|
||||
* @brief Singleton to allow to choose certain behaviours of the framework.
|
||||
*
|
||||
@@ -53,29 +61,31 @@ public:
|
||||
|
||||
///@brief Flag enum to tune certain behaviours, the defaults are Flag_Default
|
||||
enum Flag {
|
||||
Flag_None = 0, ///> No option set
|
||||
Flag_NativeTitleBar = 1, ///> Enables the Native OS title bar on OSes that support it (Windows 10, macOS), ignored otherwise. This is mutually exclusive with Flag_AeroSnap
|
||||
Flag_AeroSnapWithClientDecos = 2, ///> Deprecated. This is now default and cannot be turned off. Moving a window on Windows 10 uses native moving, as that works well across screens with different HDPI settings. There's no reason to use manual client/Qt window moving.
|
||||
Flag_AlwaysTitleBarWhenFloating = 4, ///> Floating windows will have a title bar even if Flag_HideTitleBarWhenTabsVisible is specified. Unneeded if Flag_HideTitleBarWhenTabsVisible isn't specified, as that's the default already.
|
||||
Flag_HideTitleBarWhenTabsVisible = 8, ///> Hides the title bar if there's tabs visible. The empty space in the tab bar becomes draggable.
|
||||
Flag_AlwaysShowTabs = 16, ///> Always show tabs, even if there's only one,
|
||||
Flag_AllowReorderTabs = 32, /// Allows user to re-order tabs by dragging them
|
||||
Flag_TabsHaveCloseButton = 64, /// Tabs will have a close button. Equivalent to QTabWidget::setTabsClosable(true).
|
||||
Flag_DoubleClickMaximizes = 128, /// Double clicking the titlebar will maximize a floating window instead of re-docking it
|
||||
Flag_TitleBarHasMaximizeButton = 256, /// The title bar will have a maximize/restore button when floating. This is mutually-exclusive with the floating button (since many apps behave that way).
|
||||
Flag_TitleBarIsFocusable = 512, /// You can click the title bar and it will focus the last focused widget in the focus scope. If no previously focused widget then it focuses the user's dock widget guest, which should accept focus or use a focus proxy.
|
||||
Flag_LazyResize = 1024, /// The dock widgets are resized in a lazy manner. The actual resize only happens when you release the mouse button.
|
||||
Flag_None = 0, ///< No option set
|
||||
Flag_NativeTitleBar = 1, ///< Enables the Native OS title bar on OSes that support it (Windows 10, macOS), ignored otherwise. This is mutually exclusive with Flag_AeroSnap
|
||||
Flag_AeroSnapWithClientDecos = 2, ///< Deprecated. This is now default and cannot be turned off. Moving a window on Windows 10 uses native moving, as that works well across screens with different HDPI settings. There's no reason to use manual client/Qt window moving.
|
||||
Flag_AlwaysTitleBarWhenFloating = 4, ///< Floating windows will have a title bar even if Flag_HideTitleBarWhenTabsVisible is specified. Unneeded if Flag_HideTitleBarWhenTabsVisible isn't specified, as that's the default already.
|
||||
Flag_HideTitleBarWhenTabsVisible = 8, ///< Hides the title bar if there's tabs visible. The empty space in the tab bar becomes draggable.
|
||||
Flag_AlwaysShowTabs = 16, ///< Always show tabs, even if there's only one,
|
||||
Flag_AllowReorderTabs = 32, ///< Allows user to re-order tabs by dragging them
|
||||
Flag_TabsHaveCloseButton = 64, ///< Tabs will have a close button. Equivalent to QTabWidget::setTabsClosable(true).
|
||||
Flag_DoubleClickMaximizes = 128, ///< Double clicking the titlebar will maximize a floating window instead of re-docking it
|
||||
Flag_TitleBarHasMaximizeButton = 256, ///< The title bar will have a maximize/restore button when floating. This is mutually-exclusive with the floating button (since many apps behave that way).
|
||||
Flag_TitleBarIsFocusable = 512, ///< You can click the title bar and it will focus the last focused widget in the focus scope. If no previously focused widget then it focuses the user's dock widget guest, which should accept focus or use a focus proxy.
|
||||
Flag_LazyResize = 1024, ///< The dock widgets are resized in a lazy manner. The actual resize only happens when you release the mouse button.
|
||||
|
||||
// These two are internal, for testing purposes across platforms. Use Flag_DontUseUtilityFloatingWindows instead.
|
||||
Flag_internal_DontUseQtToolWindowsForFloatingWindows = 0x800, ///> FloatingWindows will use Qt::Window instead of Qt::Tool. Internal, use Flag_DontUseUtilityFloatingWindows instead.
|
||||
Flag_internal_DontUseParentForFloatingWindows = 0x1000, ///> FloatingWindows won't have a parent top-level. Internal, use Flag_DontUseUtilityFloatingWindows instead.
|
||||
Flag_internal_DontUseQtToolWindowsForFloatingWindows = 0x800, ///< FloatingWindows will use Qt::Window instead of Qt::Tool. Internal, use Flag_DontUseUtilityFloatingWindows instead.
|
||||
Flag_internal_DontUseParentForFloatingWindows = 0x1000, ///< FloatingWindows won't have a parent top-level. Internal, use Flag_DontUseUtilityFloatingWindows instead.
|
||||
|
||||
Flag_DontUseUtilityFloatingWindows = Flag_internal_DontUseQtToolWindowsForFloatingWindows | Flag_internal_DontUseParentForFloatingWindows,
|
||||
Flag_TitleBarHasMinimizeButton = 0x2000 | Flag_DontUseUtilityFloatingWindows, ///> The title bar will have a minimize button when floating. This implies Flag_DontUseUtilityFloatingWindows too, otherwise they wouldn't appear in the task bar.
|
||||
Flag_TitleBarNoFloatButton = 0x4000, ///> The TitleBar won't show the float button
|
||||
Flag_AutoHideSupport = 0x8000 | Flag_TitleBarNoFloatButton, ///> Supports minimizing dock widgets to the side-bar.
|
||||
///> By default it also turns off the float button, but you can remove Flag_TitleBarNoFloatButton to have both.
|
||||
Flag_Default = Flag_AeroSnapWithClientDecos ///> The defaults
|
||||
Flag_TitleBarHasMinimizeButton = 0x2000 | Flag_DontUseUtilityFloatingWindows, ///< The title bar will have a minimize button when floating. This implies Flag_DontUseUtilityFloatingWindows too, otherwise they wouldn't appear in the task bar.
|
||||
Flag_TitleBarNoFloatButton = 0x4000, ///< The TitleBar won't show the float button
|
||||
Flag_AutoHideSupport = 0x8000 | Flag_TitleBarNoFloatButton, ///< Supports minimizing dock widgets to the side-bar.
|
||||
///< By default it also turns off the float button, but you can remove Flag_TitleBarNoFloatButton to have both.
|
||||
Flag_KeepAboveIfNotUtilityWindow = 0x10000, ///< Only meaningful if Flag_DontUseUtilityFloatingWindows is set. If floating windows are normal windows, you might still want them to keep above and not minimize when you focus the main window.
|
||||
Flag_internal_NoAeroSnap = 0x20000, ///< Internal flag, only for development. Disables Aero-snap.
|
||||
Flag_Default = Flag_AeroSnapWithClientDecos ///< The defaults
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
@@ -150,9 +160,38 @@ public:
|
||||
///By default it's 1.0, fully opaque
|
||||
qreal draggedWindowOpacity() const;
|
||||
|
||||
/**
|
||||
* @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
|
||||
* it returns true, then tabbing is allowed, otherwise not.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* #include <kddockwidgets/Config.h>
|
||||
* (...)
|
||||
*
|
||||
* auto func = [] (const KDDockWidgets::DockWidgetBase::List &source,
|
||||
* const KDDockWidgets::DockWidgetBase::List &target)
|
||||
* {
|
||||
* // disallows dockFoo to be tabbed with dockBar.
|
||||
* return !(source.contains(dockFoo) && target.contains(dockBar));
|
||||
* }
|
||||
* @endcode
|
||||
* KDDockWidgets::Config::self()->setTabbingAllowedFunc(func);
|
||||
*/
|
||||
void setTabbingAllowedFunc(TabbingAllowedFunc func);
|
||||
|
||||
///@brief Used internally by the framework. Returns the function which was passed to setTabbingAllowedFunc()
|
||||
///By default it's nullptr.
|
||||
///@sa setTabbingAllowedFunc().
|
||||
TabbingAllowedFunc tabbingAllowedFunc() const;
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
///@brief Sets the QQmlEngine to use. Applicable only when using QtQuick.
|
||||
void setQmlEngine(QQmlEngine *);
|
||||
QQmlEngine* qmlEngine() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Config)
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "SideBar_p.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QEvent>
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
@@ -146,6 +145,9 @@ DockWidgetBase::DockWidgetBase(const QString &name, Options options)
|
||||
|
||||
if (name.isEmpty())
|
||||
qWarning() << Q_FUNC_INFO << "Name can't be null";
|
||||
|
||||
setAttribute(Qt::WA_PendingMoveEvent, false);
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
DockWidgetBase::~DockWidgetBase()
|
||||
@@ -183,7 +185,7 @@ void DockWidgetBase::addDockWidgetAsTab(DockWidgetBase *other, AddingOption addi
|
||||
Frame *frame = this->frame();
|
||||
|
||||
if (frame) {
|
||||
if (frame->contains(other)) {
|
||||
if (frame->containsDockWidget(other)) {
|
||||
qWarning() << Q_FUNC_INFO << "Already contains" << other;
|
||||
return;
|
||||
}
|
||||
@@ -528,7 +530,7 @@ FloatingWindow *DockWidgetBase::morphIntoFloatingWindow()
|
||||
if (geo.isNull()) {
|
||||
geo = geometry();
|
||||
|
||||
if (!testAttribute(Qt::WA_Moved)) { // If user already moved it, we don't interfere
|
||||
if (!testAttribute(Qt::WA_PendingMoveEvent)) { // If user already moved it, we don't interfere
|
||||
const QPoint center = d->defaultCenterPosForFloating();
|
||||
if (!center.isNull())
|
||||
geo.moveCenter(center);
|
||||
@@ -594,6 +596,16 @@ void DockWidgetBase::updateFloatAction()
|
||||
d->updateFloatAction();
|
||||
}
|
||||
|
||||
bool DockWidgetBase::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
const bool isWindowActivate = event->type() == QEvent::WindowActivate;
|
||||
const bool isWindowDeactivate = event->type() == QEvent::WindowDeactivate;
|
||||
if ((isWindowActivate || isWindowDeactivate) && watched == window())
|
||||
Q_EMIT windowActiveAboutToChange(isWindowActivate);
|
||||
|
||||
return QWidgetAdapter::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
|
||||
{
|
||||
MainWindowBase::List mainWindows = DockRegistry::self()->mainwindows();
|
||||
@@ -653,14 +665,12 @@ void DockWidgetBase::Private::onDockWidgetShown()
|
||||
{
|
||||
updateToggleAction();
|
||||
updateFloatAction();
|
||||
qCDebug(hiding) << Q_FUNC_INFO << "parent=" << q->parentWidget();
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::onDockWidgetHidden()
|
||||
{
|
||||
updateToggleAction();
|
||||
updateFloatAction();
|
||||
qCDebug(hiding) << Q_FUNC_INFO << "parent=" << q->parentWidget();
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::close()
|
||||
|
||||
@@ -30,10 +30,81 @@ QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace Layouting {
|
||||
class Item;
|
||||
}
|
||||
|
||||
#if defined(QT_WIDGETS_LIB)
|
||||
# include <QAction>
|
||||
#else
|
||||
// A QAction for QtQuick. Just so it compiles, for now
|
||||
class QAction : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QObject::QObject;
|
||||
|
||||
bool isChecked() const {
|
||||
return m_isChecked ;
|
||||
}
|
||||
|
||||
void setCheckable(bool is) {
|
||||
m_isCheckable = is;
|
||||
}
|
||||
|
||||
void setText(const QString &text) {
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
void setToolTip(const QString &text) {
|
||||
m_toolTip = text;
|
||||
}
|
||||
|
||||
QString toolTip() const {
|
||||
returm m_toolTip;
|
||||
}
|
||||
|
||||
bool enabled() const {
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled) {
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
bool checked() const {
|
||||
return m_checked;
|
||||
}
|
||||
|
||||
void setChecked(bool checked) {
|
||||
m_checked = checked;
|
||||
}
|
||||
|
||||
bool isEnabled() const {
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void toggle() {
|
||||
m_enabled = !m_enabled;
|
||||
Q_EMIT toggled(m_enabled);
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
bool toggled(bool);
|
||||
private:
|
||||
QString m_text;
|
||||
QString m_toolTip;
|
||||
|
||||
bool m_isChecked = false;
|
||||
bool m_isCheckable = false;
|
||||
bool m_enabled = false;
|
||||
bool m_checked = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
struct LastPositions;
|
||||
@@ -46,6 +117,7 @@ class TabWidget;
|
||||
class TitleBar;
|
||||
class MainWindowBase;
|
||||
class StateDragging;
|
||||
class FrameQuick;
|
||||
|
||||
/**
|
||||
* @brief The DockWidget base-class. DockWidget and DockWidgetBase are only
|
||||
@@ -256,7 +328,7 @@ public:
|
||||
* @brief Like QWidget::close() but the hosted widget won't be asked if we
|
||||
* should close.
|
||||
*/
|
||||
void forceClose();
|
||||
Q_INVOKABLE void forceClose();
|
||||
|
||||
/**
|
||||
* @brief Returns this dock widget's title bar.
|
||||
@@ -301,7 +373,7 @@ public:
|
||||
QStringList affinities() const;
|
||||
|
||||
/// @brief Equivalent to QWidget::show(), but it's optimized to reduce flickering on some platforms
|
||||
void show();
|
||||
Q_INVOKABLE void show();
|
||||
|
||||
/// @brief Brings the dock widget to the front.
|
||||
///
|
||||
@@ -310,7 +382,7 @@ public:
|
||||
/// - If the dock widget is floating, QWindow::raise() is called.
|
||||
///
|
||||
/// This only applies if the dock widget is already open. If closed, does nothing.
|
||||
void raise();
|
||||
Q_INVOKABLE void raise();
|
||||
|
||||
/**
|
||||
* @brief Returns whether widget() is a KDDockWidget::MainWindow
|
||||
@@ -407,6 +479,14 @@ Q_SIGNALS:
|
||||
///Only relevant for the auto-hide/sidebar feature
|
||||
void removedFromSideBar();
|
||||
|
||||
///@brief Emitted when the top-level window this dock widget is in is activated or deactivated
|
||||
///This is convenience to replace tracking dockWidget->window(), since the window changes when
|
||||
///docking and undocking
|
||||
///
|
||||
/// It's called 'aboutTo' because it's done in an event filter and the target window doesn't
|
||||
/// have it's 'activeWindow' property updated yet at this point.
|
||||
void windowActiveAboutToChange(bool activated);
|
||||
|
||||
protected:
|
||||
void onParentChanged();
|
||||
void onShown(bool spontaneous);
|
||||
@@ -439,7 +519,7 @@ private:
|
||||
friend class MultiSplitter;
|
||||
friend class Frame;
|
||||
friend class DropArea;
|
||||
friend class TestDocks;
|
||||
friend class ::TestDocks;
|
||||
friend class StateDragging;
|
||||
friend class KDDockWidgets::TabWidget;
|
||||
friend class KDDockWidgets::TitleBar;
|
||||
@@ -447,6 +527,7 @@ private:
|
||||
friend class KDDockWidgets::DockRegistry;
|
||||
friend class KDDockWidgets::LayoutSaver;
|
||||
friend class KDDockWidgets::MainWindowBase;
|
||||
friend class KDDockWidgets::FrameQuick;
|
||||
|
||||
/**
|
||||
* @brief the Frame which contains this dock widgets.
|
||||
@@ -478,6 +559,9 @@ private:
|
||||
///@brief Updates the floatAction state
|
||||
void updateFloatAction();
|
||||
|
||||
///@reimp
|
||||
bool eventFilter(QObject *, QEvent *) override;
|
||||
|
||||
class Private;
|
||||
Private *const d;
|
||||
};
|
||||
|
||||
@@ -66,7 +66,7 @@ void DockWidgetQuick::setWidget(const QString &qmlFilename)
|
||||
setWidget(adapter);
|
||||
}
|
||||
|
||||
void DockWidgetQuick::setWidget(QWidgetOrQuick *widget)
|
||||
void DockWidgetQuick::setWidget(QWidgetAdapter *widget)
|
||||
{
|
||||
widget->QWidgetAdapter::setParent(this);
|
||||
QWidgetAdapter::makeItemFillParent(widget);
|
||||
@@ -87,3 +87,23 @@ bool DockWidgetQuick::event(QEvent *e)
|
||||
|
||||
return DockWidgetBase::event(e);
|
||||
}
|
||||
|
||||
QSize DockWidgetQuick::minimumSize() const
|
||||
{
|
||||
if (QWidgetAdapter *guestWidget = widget()) {
|
||||
// The guests min-size is the same as the widget's, there's no spacing or margins.
|
||||
return guestWidget->minimumSize();
|
||||
}
|
||||
|
||||
return DockWidgetBase::minimumSize();
|
||||
}
|
||||
|
||||
QSize DockWidgetQuick::maximumSize() const
|
||||
{
|
||||
if (QWidgetAdapter *guestWidget = widget()) {
|
||||
// The guests max-size is the same as the widget's, there's no spacing or margins.
|
||||
return guestWidget->maximumSize();
|
||||
}
|
||||
|
||||
return DockWidgetBase::maximumSize();
|
||||
}
|
||||
@@ -55,7 +55,13 @@ public:
|
||||
void setWidget(const QString &qmlFilename);
|
||||
|
||||
/// @reimp
|
||||
void setWidget(QWidgetOrQuick *widget) override;
|
||||
void setWidget(QWidgetAdapter *widget) override;
|
||||
|
||||
/// @reimp
|
||||
QSize minimumSize() const override;
|
||||
|
||||
/// @reimp
|
||||
QSize maximumSize() const override;
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e) override;
|
||||
@@ -18,9 +18,12 @@
|
||||
|
||||
#include "FocusScope.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "DockRegistry_p.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QPointer>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
@@ -45,6 +48,7 @@ public:
|
||||
void setIsFocused(bool);
|
||||
void onFocusObjectChanged(QObject *);
|
||||
bool isInFocusScope(WidgetType *) const;
|
||||
void emitDockWidgetFocusChanged();
|
||||
|
||||
FocusScope *const q;
|
||||
QWidgetAdapter *const m_thisWidget;
|
||||
@@ -101,6 +105,9 @@ void FocusScope::Private::setIsFocused(bool is)
|
||||
if (is != m_isFocused) {
|
||||
m_isFocused = is;
|
||||
|
||||
if (is)
|
||||
emitDockWidgetFocusChanged();
|
||||
|
||||
if (!m_inCtor) // Hack so we don't call pure-virtual
|
||||
Q_EMIT q->isFocusedChanged();
|
||||
}
|
||||
@@ -109,16 +116,19 @@ void FocusScope::Private::setIsFocused(bool is)
|
||||
void FocusScope::Private::onFocusObjectChanged(QObject *obj)
|
||||
{
|
||||
auto widget = qobject_cast<WidgetType*>(obj);
|
||||
if (!widget)
|
||||
if (!widget) {
|
||||
setIsFocused(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is = isInFocusScope(widget);
|
||||
if (is && m_lastFocusedInScope != widget && !qobject_cast<TitleBar*>(obj)) {
|
||||
m_lastFocusedInScope = widget;
|
||||
setIsFocused(is);
|
||||
Q_EMIT q->focusedWidgetChanged();
|
||||
} else {
|
||||
setIsFocused(is);
|
||||
}
|
||||
|
||||
setIsFocused(is);
|
||||
}
|
||||
|
||||
bool FocusScope::Private::isInFocusScope(WidgetType *widget) const
|
||||
@@ -133,3 +143,33 @@ bool FocusScope::Private::isInFocusScope(WidgetType *widget) const
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FocusScope::Private::emitDockWidgetFocusChanged()
|
||||
{
|
||||
auto p = qobject_cast<WidgetType*>(qApp->focusObject());
|
||||
if (!p) return;
|
||||
|
||||
// Find the nearest DockWidget and send the focusChangedSignal
|
||||
while (p) {
|
||||
if (auto frame = qobject_cast<Frame*>(p)) {
|
||||
// Special case: The focused widget is inside the frame but not inside the dockwidget.
|
||||
// For example, it's a line edit in the QTabBar. We still need to send the signal for
|
||||
// the current dw in the tab group
|
||||
if (auto dw = frame->currentDockWidget()) {
|
||||
DockRegistry::self()->setFocusedDockWidget(dw);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == m_thisWidget)
|
||||
break;
|
||||
|
||||
if (auto dw = qobject_cast<DockWidgetBase*>(p)) {
|
||||
DockRegistry::self()->setFocusedDockWidget(dw);
|
||||
break;
|
||||
}
|
||||
|
||||
p = KDDockWidgets::Private::parentWidget(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
///@brief Allows to implement a similar functionality to QtQuick's FocusScope item, in QtWidgets
|
||||
class FocusScope
|
||||
class DOCKS_EXPORT FocusScope
|
||||
{
|
||||
public:
|
||||
///@brief constructor
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Config.h"
|
||||
#include "indicators/ClassicIndicators_p.h"
|
||||
#include "indicators/NullIndicators_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
# include "indicators/ClassicIndicators_p.h"
|
||||
# include "widgets/TabWidget_p.h"
|
||||
# include "widgets/FrameWidget_p.h"
|
||||
# include "widgets/TitleBarWidget_p.h"
|
||||
@@ -32,10 +33,11 @@
|
||||
# include <QRubberBand>
|
||||
# include <QToolButton>
|
||||
#else
|
||||
# include "DockWidgetQuick.h"
|
||||
# include "quick/FrameQuick_p.h"
|
||||
# include "quick/DockWidgetQuick.h"
|
||||
# include "quick/TitleBarQuick_p.h"
|
||||
# include "quick/FloatingWindowQuick_p.h"
|
||||
# include "quick/RubberBandQuick.h"
|
||||
# include "multisplitter/Separator_quick.h"
|
||||
#endif
|
||||
|
||||
@@ -90,11 +92,18 @@ FloatingWindow *DefaultWidgetFactory::createFloatingWindow(Frame *frame, MainWin
|
||||
|
||||
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *dropArea) const
|
||||
{
|
||||
#ifdef Q_OS_WASM
|
||||
// On WASM windows don't support translucency, which is required for the classic indicators.
|
||||
return new SegmentedIndicators(dropArea);
|
||||
#endif
|
||||
|
||||
switch (s_dropIndicatorType) {
|
||||
case DropIndicatorType::Classic:
|
||||
return new ClassicIndicators(dropArea);
|
||||
case DropIndicatorType::Segmented:
|
||||
return new SegmentedIndicators(dropArea);
|
||||
case DropIndicatorType::None:
|
||||
return new NullIndicators(dropArea);
|
||||
}
|
||||
|
||||
return new ClassicIndicators(dropArea);
|
||||
@@ -157,6 +166,16 @@ FloatingWindow *DefaultWidgetFactory::createFloatingWindow(Frame *frame, MainWin
|
||||
|
||||
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *dropArea) const
|
||||
{
|
||||
switch (s_dropIndicatorType) {
|
||||
case DropIndicatorType::Classic:
|
||||
return new ClassicIndicators(dropArea);
|
||||
case DropIndicatorType::Segmented:
|
||||
qWarning() << "Segmented indicators not supported for QtQuick yet";
|
||||
return new NullIndicators(dropArea);
|
||||
case DropIndicatorType::None:
|
||||
return new NullIndicators(dropArea);
|
||||
}
|
||||
|
||||
return new ClassicIndicators(dropArea);
|
||||
}
|
||||
|
||||
@@ -181,7 +200,7 @@ Layouting::Separator *DefaultWidgetFactory::createSeparator(Layouting::Widget *p
|
||||
|
||||
QWidgetOrQuick *DefaultWidgetFactory::createRubberBand(QWidgetOrQuick *parent) const
|
||||
{
|
||||
return new QWidgetOrQuick(parent);
|
||||
return new RubberBandQuick(parent);
|
||||
}
|
||||
|
||||
SideBar *DefaultWidgetFactory::createSideBar(SideBarLocation loc, MainWindowBase *parent) const
|
||||
@@ -193,6 +212,11 @@ SideBar *DefaultWidgetFactory::createSideBar(SideBarLocation loc, MainWindowBase
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QUrl DefaultWidgetFactory::titleBarFilename() const
|
||||
{
|
||||
return QUrl(QStringLiteral("qrc:/kddockwidgets/private/quick/qml/TitleBar.qml"));
|
||||
}
|
||||
|
||||
#endif // QtQuick
|
||||
|
||||
// iconForButtonType impl is the same for QtQuick and QtWidgets
|
||||
@@ -233,10 +257,11 @@ QIcon DefaultWidgetFactory::iconForButtonType(TitleBarButtonType type, qreal dpr
|
||||
const bool isFractional = int(dpr) != dpr;
|
||||
if (isFractional) {
|
||||
// We don't support 1.5x yet.
|
||||
// Linux is the only one affected as Windows and macOS use integral factors.
|
||||
// Problem with Linux is that rendering is off due to a rounding bug only fixed in 5.15.2
|
||||
// Will enable for fractional later.
|
||||
// QTBUG-86170
|
||||
// Mostly affects Linux. Unless you're using Qt::HighDpiScaleFactorRoundingPolicy::PassThrough, in which case it will
|
||||
// affect other OSes too.
|
||||
return icon;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -61,7 +61,12 @@ class TabBar;
|
||||
*
|
||||
* @sa Config::setFrameworkWidgetFactory()
|
||||
*/
|
||||
class DOCKS_EXPORT FrameworkWidgetFactory {
|
||||
class DOCKS_EXPORT FrameworkWidgetFactory : public QObject
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
Q_PROPERTY(QUrl titleBarFilename READ titleBarFilename CONSTANT)
|
||||
#endif
|
||||
Q_OBJECT
|
||||
public:
|
||||
FrameworkWidgetFactory() = default;
|
||||
|
||||
@@ -134,10 +139,10 @@ public:
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
///@brief Called internally by the framework to create a title bar button
|
||||
///@parent the button's parent
|
||||
///@p parent the button's parent
|
||||
virtual QAbstractButton* createTitleBarButton(QWidget *parent, TitleBarButtonType) const = 0;
|
||||
#else
|
||||
// QtQuick will have some other base class for buttons
|
||||
virtual QUrl titleBarFilename() const = 0;
|
||||
#endif
|
||||
|
||||
/// @brief Returns the icon to be used with the specified @p type
|
||||
@@ -168,6 +173,8 @@ public:
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
QAbstractButton* createTitleBarButton(QWidget *parent, TitleBarButtonType) const override;
|
||||
#else
|
||||
QUrl titleBarFilename() const override;
|
||||
#endif
|
||||
|
||||
QIcon iconForButtonType(TitleBarButtonType type, qreal dpr) const override;
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
#ifndef KD_KDDOCKWIDGETS_H
|
||||
#define KD_KDDOCKWIDGETS_H
|
||||
|
||||
#include "Qt5Qt6Compat_p.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// Only on Windows, where this is popular. On linux it the Qt::Tool windows need reparenting. Untested on macOS.
|
||||
// Only on Windows, where this is popular. On linux the Qt::Tool windows need reparenting. Untested on macOS.
|
||||
# define KDDOCKWIDGETS_SUPPORTS_NESTED_MAINWINDOWS
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
enum Location {
|
||||
@@ -76,7 +76,8 @@ namespace KDDockWidgets
|
||||
|
||||
enum class DropIndicatorType {
|
||||
Classic, ///< The default
|
||||
Segmented
|
||||
Segmented, ///< Segmented indicators
|
||||
None ///< Don't show any drop indicators while dragging
|
||||
};
|
||||
|
||||
///@internal
|
||||
@@ -119,7 +120,7 @@ namespace KDDockWidgets
|
||||
};
|
||||
|
||||
///@internal
|
||||
inline uint qHash(SideBarLocation loc, uint seed)
|
||||
inline Qt5Qt6Compat::qhashtype qHash(SideBarLocation loc, Qt5Qt6Compat::qhashtype seed)
|
||||
{
|
||||
return ::qHash(static_cast<uint>(loc), seed);
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
|
||||
#include <qmath.h>
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
|
||||
#include <memory>
|
||||
@@ -700,6 +700,12 @@ QVariantMap LayoutSaver::MainWindow::toVariantMap() const
|
||||
map.insert(QStringLiteral("isVisible"), isVisible);
|
||||
map.insert(QStringLiteral("affinities"), stringListToVariant(affinities));
|
||||
|
||||
for (SideBarLocation loc : { SideBarLocation::North, SideBarLocation::East, SideBarLocation::West, SideBarLocation::South }) {
|
||||
const QStringList dockWidgets = dockWidgetsPerSideBar.value(loc);
|
||||
if (!dockWidgets.isEmpty())
|
||||
map.insert(QStringLiteral("sidebar-%1").arg(int(loc)), stringListToVariant(dockWidgets));
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -720,6 +726,13 @@ void LayoutSaver::MainWindow::fromVariantMap(const QVariantMap &map)
|
||||
affinities.push_back(affinityName);
|
||||
}
|
||||
|
||||
// Load the SideBars:
|
||||
dockWidgetsPerSideBar.clear();
|
||||
for (SideBarLocation loc : { SideBarLocation::North, SideBarLocation::East, SideBarLocation::West, SideBarLocation::South }) {
|
||||
const QVariantList dockWidgets = map.value(QStringLiteral("sidebar-%1").arg(int(loc))).toList();
|
||||
if (!dockWidgets.isEmpty())
|
||||
dockWidgetsPerSideBar.insert(loc, variantToStringList(dockWidgets));
|
||||
}
|
||||
}
|
||||
|
||||
bool LayoutSaver::MultiSplitter::isValid() const
|
||||
|
||||
@@ -27,6 +27,8 @@ QT_BEGIN_NAMESPACE
|
||||
class QByteArray;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class DockWidgetBase;
|
||||
@@ -105,7 +107,7 @@ public:
|
||||
struct ScreenInfo;
|
||||
private:
|
||||
Q_DISABLE_COPY(LayoutSaver)
|
||||
friend class TestDocks;
|
||||
friend class ::TestDocks;
|
||||
|
||||
class Private;
|
||||
Private *const d;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <QRect>
|
||||
#include <QDebug>
|
||||
#include <QScreen>
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <memory>
|
||||
@@ -236,6 +236,7 @@ public:
|
||||
QVariantMap toVariantMap() const;
|
||||
void fromVariantMap(const QVariantMap &map);
|
||||
|
||||
QHash<SideBarLocation, QStringList> dockWidgetsPerSideBar;
|
||||
KDDockWidgets::MainWindowOptions options;
|
||||
LayoutSaver::MultiSplitter multiSplitterLayout;
|
||||
QString uniqueName;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPainter>
|
||||
|
||||
@@ -99,8 +98,6 @@ MainWindow::MainWindow(const QString &name, MainWindowOptions options,
|
||||
}
|
||||
|
||||
setCentralWidget(centralWidget);
|
||||
|
||||
// qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
QRect rectForOverlay(Frame *, SideBarLocation) const;
|
||||
SideBarLocation preferredSideBar(DockWidgetBase *) const;
|
||||
void updateOverlayGeometry();
|
||||
void clearSideBars();
|
||||
|
||||
QString name;
|
||||
QStringList affinities;
|
||||
@@ -337,6 +338,15 @@ void MainWindowBase::Private::updateOverlayGeometry()
|
||||
m_overlayedDockWidget->frame()->QWidgetAdapter::setGeometry(rectForOverlay(m_overlayedDockWidget->frame(), sb->location()));
|
||||
}
|
||||
|
||||
void MainWindowBase::Private::clearSideBars()
|
||||
{
|
||||
for (auto loc : { SideBarLocation::North, SideBarLocation::South,
|
||||
SideBarLocation::East, SideBarLocation::West }) {
|
||||
if (SideBar *sb = q->sideBar(loc))
|
||||
sb->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindowBase::moveToSideBar(DockWidgetBase *dw)
|
||||
{
|
||||
moveToSideBar(dw, d->preferredSideBar(dw));
|
||||
@@ -401,7 +411,7 @@ void MainWindowBase::overlayOnSideBar(DockWidgetBase *dw)
|
||||
void MainWindowBase::toggleOverlayOnSideBar(DockWidgetBase *dw)
|
||||
{
|
||||
const bool wasOverlayed = d->m_overlayedDockWidget == dw;
|
||||
clearSideBarOverlay();
|
||||
clearSideBarOverlay(); // Because only 1 dock widget can be overlayed each time
|
||||
if (!wasOverlayed) {
|
||||
overlayOnSideBar(dw);
|
||||
}
|
||||
@@ -425,7 +435,7 @@ SideBar *MainWindowBase::sideBarForDockWidget(const DockWidgetBase *dw) const
|
||||
SideBarLocation::East, SideBarLocation::West }) {
|
||||
|
||||
if (SideBar *sb = sideBar(loc)) {
|
||||
if (sb->contains(const_cast<DockWidgetBase *>(dw)))
|
||||
if (sb->containsDockWidget(const_cast<DockWidgetBase *>(dw)))
|
||||
return sb;
|
||||
}
|
||||
}
|
||||
@@ -440,8 +450,20 @@ DockWidgetBase *MainWindowBase::overlayedDockWidget() const
|
||||
|
||||
bool MainWindowBase::sideBarIsVisible(SideBarLocation loc) const
|
||||
{
|
||||
if (SideBar *sb = sideBar(loc))
|
||||
return sb->isVisible();
|
||||
if (SideBar *sb = sideBar(loc)) {
|
||||
return !sb->isEmpty(); // isVisible() is always true, but its height is 0 when empty.
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MainWindowBase::anySideBarIsVisible() const
|
||||
{
|
||||
for (auto loc : { SideBarLocation::North, SideBarLocation::South,
|
||||
SideBarLocation::East, SideBarLocation::West }) {
|
||||
if (sideBarIsVisible(loc))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -481,7 +503,34 @@ bool MainWindowBase::deserialize(const LayoutSaver::MainWindow &mw)
|
||||
d->affinities = mw.affinities;
|
||||
}
|
||||
|
||||
return dropArea()->deserialize(mw.multiSplitterLayout);
|
||||
const bool success = dropArea()->deserialize(mw.multiSplitterLayout);
|
||||
|
||||
// Restore the SideBars
|
||||
d->clearSideBars();
|
||||
for (SideBarLocation loc : { SideBarLocation::North, SideBarLocation::East, SideBarLocation::West, SideBarLocation::South }) {
|
||||
SideBar *sb = sideBar(loc);
|
||||
if (!sb)
|
||||
continue;
|
||||
|
||||
const QStringList dockWidgets = mw.dockWidgetsPerSideBar.value(loc);
|
||||
for (const QString &uniqueName : dockWidgets) {
|
||||
|
||||
DockWidgetBase *dw = DockRegistry::self()->dockByName(uniqueName);
|
||||
if (!dw) {
|
||||
qWarning() << Q_FUNC_INFO << "Could not find dock widget" << uniqueName
|
||||
<< ". Won't restore it to sidebar";
|
||||
continue;
|
||||
}
|
||||
|
||||
sb->addDockWidget(dw);
|
||||
}
|
||||
}
|
||||
|
||||
// Commented-out for now, we dont' want to restore the popup/overlay. popups are perishable
|
||||
//if (!mw.overlayedDockWidget.isEmpty())
|
||||
// overlayOnSideBar(DockRegistry::self()->dockByName(mw.overlayedDockWidget));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
LayoutSaver::MainWindow MainWindowBase::serialize() const
|
||||
@@ -497,5 +546,13 @@ LayoutSaver::MainWindow MainWindowBase::serialize() const
|
||||
m.multiSplitterLayout = dropArea()->serialize();
|
||||
m.affinities = d->affinities;
|
||||
|
||||
for (SideBarLocation loc : { SideBarLocation::North, SideBarLocation::East, SideBarLocation::West, SideBarLocation::South }) {
|
||||
if (SideBar *sb = sideBar(loc)) {
|
||||
const QStringList dockwidgets = sb->serialize();
|
||||
if (!dockwidgets.isEmpty())
|
||||
m.dockWidgetsPerSideBar.insert(loc, dockwidgets);
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <QVector>
|
||||
#include <QMargins>
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class DockWidgetBase;
|
||||
@@ -166,6 +168,9 @@ public:
|
||||
/// @brief Returns whether the specified sidebar is visible
|
||||
bool sideBarIsVisible(SideBarLocation) const;
|
||||
|
||||
/// @brief Returns whether any side bar is visible
|
||||
bool anySideBarIsVisible() const;
|
||||
|
||||
protected:
|
||||
void setUniqueName(const QString &uniqueName);
|
||||
void onResized(QResizeEvent *); // Because QtQuick doesn't have resizeEvent()
|
||||
@@ -180,6 +185,7 @@ private:
|
||||
class Private;
|
||||
Private *const d;
|
||||
|
||||
friend class ::TestDocks;
|
||||
friend class LayoutSaver;
|
||||
bool deserialize(const LayoutSaver::MainWindow &);
|
||||
LayoutSaver::MainWindow serialize() const;
|
||||
|
||||
@@ -13,20 +13,39 @@
|
||||
#define KDDOCKWIDGETS_QT5QT6_COMPAT_P_H
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QDropEvent>
|
||||
|
||||
namespace KDDockWidgets {
|
||||
namespace Qt5Qt6Compat {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
|
||||
using QEnterEvent = QEnterEvent;
|
||||
using qintptr = ::qintptr;
|
||||
using qhashtype = size_t;
|
||||
|
||||
inline QPoint eventPos(QDropEvent *ev)
|
||||
{
|
||||
return ev->position().toPoint();
|
||||
}
|
||||
|
||||
inline QPoint eventGlobalPos(QMouseEvent *ev)
|
||||
{
|
||||
return ev->globalPosition().toPoint();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Qt 5:
|
||||
|
||||
using QEnterEvent = QEvent;
|
||||
using qintptr = long;
|
||||
using qhashtype = uint;
|
||||
|
||||
inline QPoint eventPos(QDropEvent *ev)
|
||||
{
|
||||
return ev->pos();
|
||||
}
|
||||
|
||||
inline QPoint eventGlobalPos(QMouseEvent *ev)
|
||||
{
|
||||
return ev->globalPos();
|
||||
|
||||
12
src/fwd_headers/kddockwidgets/DockWidgetBase.h
Normal file
12
src/fwd_headers/kddockwidgets/DockWidgetBase.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 "../../DockWidgetBase.h"
|
||||
12
src/fwd_headers/kddockwidgets/DockWidgetQuick.h
Normal file
12
src/fwd_headers/kddockwidgets/DockWidgetQuick.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 "../../DockWidgetQuick.h"
|
||||
12
src/fwd_headers/kddockwidgets/FocusScope.h
Normal file
12
src/fwd_headers/kddockwidgets/FocusScope.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 "../../FocusScope.h"
|
||||
12
src/fwd_headers/kddockwidgets/MainWindowBase.h
Normal file
12
src/fwd_headers/kddockwidgets/MainWindowBase.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 "../../MainWindowBase.h"
|
||||
12
src/fwd_headers/kddockwidgets/QWidgetAdapter.h
Normal file
12
src/fwd_headers/kddockwidgets/QWidgetAdapter.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 "../../QWidgetAdapter.h"
|
||||
12
src/fwd_headers/kddockwidgets/Qt5Qt6Compat_p.h
Normal file
12
src/fwd_headers/kddockwidgets/Qt5Qt6Compat_p.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 "../../Qt5Qt6Compat_p.h"
|
||||
12
src/fwd_headers/kddockwidgets/docks_export.h
Normal file
12
src/fwd_headers/kddockwidgets/docks_export.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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 "../../docks_export.h"
|
||||
12
src/fwd_headers/kddockwidgets/private/DockRegistry_p.h
Normal file
12
src/fwd_headers/kddockwidgets/private/DockRegistry_p.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 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/DockRegistry_p.h"
|
||||
@@ -4,10 +4,14 @@
|
||||
<file>private/quick/qml/DropArea.qml</file>
|
||||
<file>private/quick/qml/FloatingWindow.qml</file>
|
||||
<file>private/quick/qml/Frame.qml</file>
|
||||
<file>private/quick/qml/RubberBand.qml</file>
|
||||
<file>private/quick/qml/TitleBarBase.qml</file>
|
||||
<file>private/quick/qml/TitleBar.qml</file>
|
||||
<file>private/quick/qml/TitleBarButton.qml</file>
|
||||
<file>private/quick/qml/ClassicIndicatorsOverlay.qml</file>
|
||||
<file>private/quick/qml/ClassicIndicator.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/kddockwidgets/multisplitter/">
|
||||
<file>private/multisplitter/qml/Separator.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -18,10 +18,11 @@
|
||||
#include "Config.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QWindow>
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
@@ -34,8 +35,11 @@ using namespace KDDockWidgets;
|
||||
|
||||
static void initKDDockWidgetResources()
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_STATICLIB
|
||||
Q_INIT_RESOURCE(resources);
|
||||
#if defined(KDDOCKWIDGETS_STATICLIB) || defined(QT_STATIC)
|
||||
Q_INIT_RESOURCE(kddockwidgets_resources);
|
||||
# if defined(KDDOCKWIDGETS_QTQUICK)
|
||||
Q_INIT_RESOURCE(kddockwidgets_qtquick);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -54,6 +58,7 @@ DockRegistry::DockRegistry(QObject *parent)
|
||||
|
||||
#else
|
||||
KDDockWidgets::registerQmlTypes();
|
||||
QQuickWindow::setDefaultAlphaBuffer(true);
|
||||
#endif
|
||||
|
||||
connect(qApp, &QGuiApplication::focusObjectChanged,
|
||||
@@ -74,28 +79,27 @@ void DockRegistry::maybeDelete()
|
||||
|
||||
void DockRegistry::onFocusObjectChanged(QObject *obj)
|
||||
{
|
||||
DockWidgetBase *const unfocusedDW = m_focusedDockWidget.data();
|
||||
DockWidgetBase *newFocusedDockWidget = nullptr;
|
||||
// In this function we reset the focused dock widget.
|
||||
|
||||
// Check if it's inside a dock widget:
|
||||
auto p = qobject_cast<WidgetType*>(obj);
|
||||
while (p) {
|
||||
if (auto dw = qobject_cast<DockWidgetBase*>(p)) {
|
||||
newFocusedDockWidget = dw;
|
||||
break;
|
||||
}
|
||||
|
||||
if (qobject_cast<DockWidgetBase*>(p) || qobject_cast<Frame*>(p))
|
||||
return;
|
||||
p = KDDockWidgets::Private::parentWidget(p);
|
||||
}
|
||||
|
||||
// Nothing changed
|
||||
if (m_focusedDockWidget.data() == newFocusedDockWidget)
|
||||
setFocusedDockWidget(nullptr);
|
||||
}
|
||||
|
||||
void DockRegistry::setFocusedDockWidget(DockWidgetBase *dw)
|
||||
{
|
||||
if (m_focusedDockWidget.data() == dw)
|
||||
return;
|
||||
|
||||
m_focusedDockWidget = newFocusedDockWidget;
|
||||
if (m_focusedDockWidget)
|
||||
Q_EMIT m_focusedDockWidget->isFocusedChanged(false);
|
||||
|
||||
if (unfocusedDW)
|
||||
Q_EMIT unfocusedDW->isFocusedChanged(false);
|
||||
m_focusedDockWidget = dw;
|
||||
|
||||
if (m_focusedDockWidget)
|
||||
Q_EMIT m_focusedDockWidget->isFocusedChanged(true);
|
||||
@@ -328,6 +332,11 @@ void DockRegistry::unregisterFrame(Frame *frame)
|
||||
m_frames.removeOne(frame);
|
||||
}
|
||||
|
||||
bool DockRegistry::containsDockWidget(const QString &uniqueName) const
|
||||
{
|
||||
return dockByName(uniqueName) != nullptr;
|
||||
}
|
||||
|
||||
DockWidgetBase *DockRegistry::dockByName(const QString &name) const
|
||||
{
|
||||
for (auto dock : qAsConst(m_dockWidgets)) {
|
||||
@@ -504,6 +513,37 @@ FloatingWindow *DockRegistry::floatingWindowForHandle(QWindow *windowHandle) con
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FloatingWindow *DockRegistry::floatingWindowForHandle(WId hwnd) const
|
||||
{
|
||||
for (FloatingWindow *fw : m_floatingWindows) {
|
||||
if (fw->windowHandle() && fw->windowHandle()->winId() == hwnd)
|
||||
return fw;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MainWindowBase *DockRegistry::mainWindowForHandle(QWindow *windowHandle) const
|
||||
{
|
||||
for (MainWindowBase *mw : m_mainWindows) {
|
||||
if (mw->windowHandle() == windowHandle)
|
||||
return mw;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidgetOrQuick *DockRegistry::topLevelForHandle(QWindow *windowHandle) const
|
||||
{
|
||||
if (auto fw = floatingWindowForHandle(windowHandle))
|
||||
return fw;
|
||||
|
||||
if (auto mw = mainWindowForHandle(windowHandle))
|
||||
return mw;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVector<QWindow *> DockRegistry::topLevels(bool excludeFloatingDocks) const
|
||||
{
|
||||
QVector<QWindow *> windows;
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
#ifndef KD_DOCKREGISTRY_P_H
|
||||
#define KD_DOCKREGISTRY_P_H
|
||||
|
||||
#include "DockWidgetBase.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "../DockWidgetBase.h"
|
||||
#include "../MainWindowBase.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QObject>
|
||||
@@ -28,7 +27,10 @@
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
|
||||
class FloatingWindow;
|
||||
class Frame;
|
||||
class SideBar;
|
||||
struct WindowBeingDragged;
|
||||
|
||||
class DOCKS_EXPORT DockRegistry : public QObject
|
||||
{
|
||||
@@ -53,6 +55,7 @@ public:
|
||||
|
||||
DockWidgetBase *focusedDockWidget() const;
|
||||
|
||||
bool containsDockWidget(const QString &uniqueName) const;
|
||||
DockWidgetBase *dockByName(const QString &) const;
|
||||
MainWindowBase *mainWindowByName(const QString &) const;
|
||||
|
||||
@@ -80,7 +83,7 @@ public:
|
||||
const QVector<MultiSplitter*> layouts() const;
|
||||
|
||||
///@brief returns a list of all Frame instances
|
||||
const Frame::List frames() const;
|
||||
const QList<Frame*> frames() const;
|
||||
|
||||
///@brief returns all FloatingWindow instances. Not necessarily all floating dock widgets,
|
||||
/// As there might be DockWidgets which weren't morphed yet.
|
||||
@@ -95,6 +98,17 @@ public:
|
||||
///@brief returns the FloatingWindow with handle @p windowHandle
|
||||
FloatingWindow *floatingWindowForHandle(QWindow *windowHandle) const;
|
||||
|
||||
///@brief returns the FloatingWindow with handle @p hwnd
|
||||
FloatingWindow *floatingWindowForHandle(WId hwnd) const;
|
||||
|
||||
///@brief returns the MainWindow with handle @p windowHandle
|
||||
MainWindowBase *mainWindowForHandle(QWindow *windowHandle) const;
|
||||
|
||||
///@brief returns the top level widget associated with the specified QWindow.
|
||||
///For QtWidgets, it returns a QWidget which is either a KDDockWidgets::MainWindow or a FloatingWindow.
|
||||
///For QtQuick ir returns the same, but the type is a QWidgetAdapter (a QQuickItem), not QWidget obviously.
|
||||
QWidgetOrQuick *topLevelForHandle(QWindow *windowHandle) const;
|
||||
|
||||
///@brief Returns the list with all visiblye top-level parents of our FloatingWindow and MainWindow instances.
|
||||
///
|
||||
/// Typically these are the FloatingWindows and MainWindows themselves. However, since a
|
||||
@@ -193,14 +207,17 @@ public:
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
private:
|
||||
friend class FocusScope;
|
||||
explicit DockRegistry(QObject *parent = nullptr);
|
||||
void onDockWidgetPressed(DockWidgetBase *dw);
|
||||
void onFocusObjectChanged(QObject *obj);
|
||||
void maybeDelete();
|
||||
void onFocusObjectChanged(QObject *);
|
||||
void setFocusedDockWidget(DockWidgetBase *);
|
||||
|
||||
bool m_isProcessingAppQuitEvent = false;
|
||||
DockWidgetBase::List m_dockWidgets;
|
||||
MainWindowBase::List m_mainWindows;
|
||||
Frame::List m_frames;
|
||||
QList<Frame*> m_frames;
|
||||
QVector<FloatingWindow*> m_floatingWindows;
|
||||
QVector<MultiSplitter*> m_layouts;
|
||||
QPointer<DockWidgetBase> m_focusedDockWidget;
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
#include "Qt5Qt6Compat_p.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QCursor>
|
||||
#include <QWindow>
|
||||
#include <QDrag>
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
# include <QWindow>
|
||||
@@ -32,7 +34,7 @@
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
///@brief Custom mouse grabber, as platforms like wayland don't support grabbing the mouse
|
||||
///@brief Custom mouse grabber, for platforms that don't support grabbing the mouse
|
||||
class FallbackMouseGrabber : public QObject /// clazy:exclude=missing-qobject-macro
|
||||
{
|
||||
public:
|
||||
@@ -51,6 +53,20 @@ public:
|
||||
|
||||
void releaseMouse()
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
// Ungrab harder if QtQuick.
|
||||
// QtQuick has the habit og grabbing the MouseArea internally, then doesn't ungrab it since
|
||||
// we're consuming the events. So explicitly ungrab if any QQuickWindow::mouseGrabberItem()
|
||||
// is still set.
|
||||
|
||||
QQuickView *view = m_target ? m_target->quickView()
|
||||
: nullptr;
|
||||
QQuickItem *grabber = view ? view->mouseGrabberItem()
|
||||
: nullptr;
|
||||
if (grabber)
|
||||
grabber->ungrabMouse();
|
||||
#endif
|
||||
|
||||
m_target = nullptr;
|
||||
qApp->removeEventFilter(this);
|
||||
}
|
||||
@@ -60,14 +76,9 @@ public:
|
||||
if (m_reentrancyGuard || !m_target)
|
||||
return false;
|
||||
|
||||
if (ev->type() == QEvent::MouseButtonPress ||
|
||||
ev->type() == QEvent::MouseButtonRelease ||
|
||||
ev->type() == QEvent::MouseMove ||
|
||||
ev->type() == QEvent::NonClientAreaMouseButtonPress ||
|
||||
ev->type() == QEvent::NonClientAreaMouseButtonRelease ||
|
||||
ev->type() == QEvent::NonClientAreaMouseMove) {
|
||||
if (QMouseEvent *me = mouseEvent(ev)) {
|
||||
m_reentrancyGuard = true;
|
||||
qApp->sendEvent(m_target, ev);
|
||||
qApp->sendEvent(m_target, me);
|
||||
m_reentrancyGuard = false;
|
||||
return true;
|
||||
}
|
||||
@@ -83,8 +94,51 @@ FallbackMouseGrabber::~FallbackMouseGrabber() {}
|
||||
|
||||
}
|
||||
|
||||
State::State(MinimalStateMachine *parent)
|
||||
: QObject(parent)
|
||||
, m_machine(parent)
|
||||
{
|
||||
}
|
||||
|
||||
State::~State() = default;
|
||||
|
||||
bool State::isCurrentState() const
|
||||
{
|
||||
return m_machine->currentState() == this;
|
||||
}
|
||||
|
||||
MinimalStateMachine::MinimalStateMachine(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Obj, typename Signal>
|
||||
void State::addTransition(Obj *obj, Signal signal, State *dest)
|
||||
{
|
||||
connect(obj, signal, this, [this, dest] {
|
||||
if (isCurrentState()) {
|
||||
m_machine->setCurrentState(dest);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
State *MinimalStateMachine::currentState() const
|
||||
{
|
||||
return m_currentState;
|
||||
}
|
||||
|
||||
void MinimalStateMachine::setCurrentState(State *state)
|
||||
{
|
||||
if (state != m_currentState) {
|
||||
m_currentState = state;
|
||||
if (state)
|
||||
state->onEntry();
|
||||
}
|
||||
}
|
||||
|
||||
StateBase::StateBase(DragController *parent)
|
||||
: QState(parent)
|
||||
: State(parent)
|
||||
, q(parent)
|
||||
{
|
||||
}
|
||||
@@ -101,7 +155,7 @@ StateNone::StateNone(DragController *parent)
|
||||
{
|
||||
}
|
||||
|
||||
void StateNone::onEntry(QEvent *)
|
||||
void StateNone::onEntry()
|
||||
{
|
||||
qCDebug(state) << "StateNone entered";
|
||||
q->m_pressPos = QPoint();
|
||||
@@ -142,7 +196,7 @@ StatePreDrag::StatePreDrag(DragController *parent)
|
||||
|
||||
StatePreDrag::~StatePreDrag() = default;
|
||||
|
||||
void StatePreDrag::onEntry(QEvent *)
|
||||
void StatePreDrag::onEntry()
|
||||
{
|
||||
qCDebug(state) << "StatePreDrag entered";
|
||||
WidgetResizeHandler::s_disableAllHandlers = true; // Disable the resize handler during dragging
|
||||
@@ -163,6 +217,15 @@ bool StatePreDrag::handleMouseButtonRelease(QPoint)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StatePreDrag::handleMouseDoubleClick()
|
||||
{
|
||||
// This is only needed for QtQuick.
|
||||
// With QtQuick, when double clicking, we get: Press, Release, Press, Double-click. and never
|
||||
// receive the last Release event.
|
||||
Q_EMIT q->dragCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
StateDragging::StateDragging(DragController *parent)
|
||||
: StateBase(parent)
|
||||
{
|
||||
@@ -170,7 +233,7 @@ StateDragging::StateDragging(DragController *parent)
|
||||
|
||||
StateDragging::~StateDragging() = default;
|
||||
|
||||
void StateDragging::onEntry(QEvent *)
|
||||
void StateDragging::onEntry()
|
||||
{
|
||||
if (DockWidgetBase *dw = q->m_draggable->singleDockWidget()) {
|
||||
// When we start to drag a floating window which has a single dock widget, we save the position
|
||||
@@ -294,6 +357,14 @@ bool StateDragging::handleMouseMove(QPoint globalPos)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StateDragging::handleMouseDoubleClick()
|
||||
{
|
||||
// See comment in StatePreDrag::handleMouseDoubleClick().
|
||||
// Very unlikely that we're in this state though, due to manhattan length
|
||||
Q_EMIT q->dragCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
StateDraggingWayland::StateDraggingWayland(DragController *parent)
|
||||
: StateDragging(parent)
|
||||
{
|
||||
@@ -303,23 +374,92 @@ StateDraggingWayland::~StateDraggingWayland()
|
||||
{
|
||||
}
|
||||
|
||||
void StateDraggingWayland::onEntry(QEvent *)
|
||||
void StateDraggingWayland::onEntry()
|
||||
{
|
||||
// Create a QDrag here
|
||||
qCDebug(state) << "StateDragging entered";
|
||||
|
||||
if (m_inQDrag) {
|
||||
// Maybe we can exit the state due to the nested event loop of QDrag::Exec();
|
||||
qWarning() << Q_FUNC_INFO << "Impossible!";
|
||||
return;
|
||||
}
|
||||
|
||||
QScopedValueRollback<bool> guard(m_inQDrag, true);
|
||||
q->m_windowBeingDragged = std::unique_ptr<WindowBeingDragged>(new WindowBeingDraggedWayland(q->m_draggable));
|
||||
|
||||
auto mimeData = new WaylandMimeData();
|
||||
QDrag drag(this);
|
||||
drag.setMimeData(mimeData);
|
||||
drag.setPixmap(q->m_windowBeingDragged->pixmap());
|
||||
|
||||
qApp->installEventFilter(q);
|
||||
const Qt::DropAction result = drag.exec();
|
||||
qApp->removeEventFilter(q);
|
||||
if (result == Qt::IgnoreAction)
|
||||
Q_EMIT q->dragCanceled();
|
||||
}
|
||||
|
||||
bool StateDraggingWayland::handleMouseButtonRelease(QPoint /*globalPos*/)
|
||||
{
|
||||
qCDebug(state) << Q_FUNC_INFO;
|
||||
Q_EMIT q->dragCanceled();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StateDraggingWayland::handleMouseMove(QPoint /*globalPos*/)
|
||||
bool StateDraggingWayland::handleDragEnter(QDragEnterEvent *ev, DropArea *dropArea)
|
||||
{
|
||||
auto mimeData = qobject_cast<const WaylandMimeData*>(ev->mimeData());
|
||||
if (!mimeData || !q->m_windowBeingDragged)
|
||||
return false; // Not for us, some other user drag.
|
||||
|
||||
if (q->m_windowBeingDragged->contains(dropArea)) {
|
||||
ev->ignore();
|
||||
return true;
|
||||
}
|
||||
|
||||
dropArea->hover(q->m_windowBeingDragged.get(), dropArea->mapToGlobal(Qt5Qt6Compat::eventPos(ev)));
|
||||
|
||||
ev->accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
DragController::DragController(QObject *)
|
||||
bool StateDraggingWayland::handleDragLeave(DropArea *dropArea)
|
||||
{
|
||||
dropArea->removeHover();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StateDraggingWayland::handleDrop(QDropEvent *ev, DropArea *dropArea)
|
||||
{
|
||||
auto mimeData = qobject_cast<const WaylandMimeData*>(ev->mimeData());
|
||||
if (!mimeData || !q->m_windowBeingDragged)
|
||||
return false; // Not for us, some other user drag.
|
||||
|
||||
if (dropArea->drop(q->m_windowBeingDragged.get(), dropArea->mapToGlobal(Qt5Qt6Compat::eventPos(ev)))) {
|
||||
ev->setDropAction(Qt::MoveAction);
|
||||
ev->accept();
|
||||
Q_EMIT q->dropped();
|
||||
} else {
|
||||
Q_EMIT q->dragCanceled();
|
||||
}
|
||||
|
||||
dropArea->removeHover();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StateDraggingWayland::handleDragMove(QDragMoveEvent *ev, DropArea *dropArea)
|
||||
{
|
||||
auto mimeData = qobject_cast<const WaylandMimeData*>(ev->mimeData());
|
||||
if (!mimeData || !q->m_windowBeingDragged)
|
||||
return false; // Not for us, some other user drag.
|
||||
|
||||
dropArea->hover(q->m_windowBeingDragged.get(), dropArea->mapToGlobal(Qt5Qt6Compat::eventPos(ev)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DragController::DragController(QObject *parent)
|
||||
: MinimalStateMachine(parent)
|
||||
{
|
||||
qCDebug(creation) << "DragController()";
|
||||
|
||||
@@ -334,8 +474,10 @@ DragController::DragController(QObject *)
|
||||
stateDragging->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
stateDragging->addTransition(this, &DragController::dropped, stateNone);
|
||||
|
||||
setInitialState(stateNone);
|
||||
start();
|
||||
if (usesFallbackMouseGrabber())
|
||||
enableFallbackMouseGrabber();
|
||||
|
||||
setCurrentState(stateNone);
|
||||
}
|
||||
|
||||
DragController *DragController::instance()
|
||||
@@ -373,6 +515,9 @@ bool DragController::isInClientDrag() const
|
||||
|
||||
void DragController::grabMouseFor(QWidgetOrQuick *target)
|
||||
{
|
||||
if (isWayland())
|
||||
return; // No grabbing supported on wayland
|
||||
|
||||
if (m_fallbackMouseGrabber) {
|
||||
m_fallbackMouseGrabber->grabMouse(target);
|
||||
} else {
|
||||
@@ -382,6 +527,9 @@ void DragController::grabMouseFor(QWidgetOrQuick *target)
|
||||
|
||||
void DragController::releaseMouse(QWidgetOrQuick *target)
|
||||
{
|
||||
if (isWayland())
|
||||
return; // No grabbing supported on wayland
|
||||
|
||||
if (m_fallbackMouseGrabber) {
|
||||
m_fallbackMouseGrabber->releaseMouse();
|
||||
} else {
|
||||
@@ -406,39 +554,46 @@ WindowBeingDragged *DragController::windowBeingDragged() const
|
||||
return m_windowBeingDragged.get();
|
||||
}
|
||||
|
||||
static QMouseEvent *mouseEvent(QEvent *e)
|
||||
{
|
||||
switch (e->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::NonClientAreaMouseButtonPress:
|
||||
case QEvent::NonClientAreaMouseButtonRelease:
|
||||
case QEvent::NonClientAreaMouseMove:
|
||||
return static_cast<QMouseEvent *>(e);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool DragController::eventFilter(QObject *o, QEvent *e)
|
||||
{
|
||||
if (m_nonClientDrag && e->type() == QEvent::Move) {
|
||||
// On Windows, non-client mouse moves are only sent at the end, so we must fake it:
|
||||
qCDebug(mouseevents) << "DragController::eventFilter e=" << e->type() << "; o=" << o;
|
||||
activeState()->handleMouseMove(QCursor::pos());
|
||||
return QStateMachine::eventFilter(o, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isWayland()) {
|
||||
// Wayland is very different. It uses QDrag for the dragging of a window.
|
||||
if (auto dropArea = qobject_cast<DropArea*>(o)) {
|
||||
switch (int(e->type())) {
|
||||
case QEvent::DragEnter:
|
||||
if (activeState()->handleDragEnter(static_cast<QDragEnterEvent*>(e), dropArea))
|
||||
return true;
|
||||
break;
|
||||
case QEvent::DragLeave:
|
||||
if (activeState()->handleDragLeave(dropArea))
|
||||
return true;
|
||||
break;
|
||||
case QEvent::DragMove:
|
||||
if (activeState()->handleDragMove(static_cast<QDragMoveEvent*>(e), dropArea))
|
||||
return true;
|
||||
break;
|
||||
case QEvent::Drop:
|
||||
if (activeState()->handleDrop(static_cast<QDropEvent*>(e), dropArea))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMouseEvent *me = mouseEvent(e);
|
||||
if (!me)
|
||||
return QStateMachine::eventFilter(o, e);
|
||||
return false;
|
||||
|
||||
auto w = qobject_cast<QWidgetOrQuick*>(o);
|
||||
if (!w)
|
||||
return QStateMachine::eventFilter(o, e);
|
||||
return false;
|
||||
|
||||
qCDebug(mouseevents) << "DragController::eventFilter e=" << e->type() << "; o=" << o
|
||||
<< "; m_nonClientDrag=" << m_nonClientDrag;
|
||||
@@ -451,13 +606,15 @@ bool DragController::eventFilter(QObject *o, QEvent *e)
|
||||
return activeState()->handleMouseButtonPress(draggableForQObject(o), Qt5Qt6Compat::eventGlobalPos(me), me->pos());
|
||||
}
|
||||
}
|
||||
return QStateMachine::eventFilter(o, e);
|
||||
return false;
|
||||
}
|
||||
case QEvent::MouseButtonPress:
|
||||
// For top-level windows that support native dragging all goes through the NonClient* events.
|
||||
// This also forbids dragging a FloatingWindow simply by pressing outside of the title area, in the background
|
||||
if (!KDDockWidgets::usesNativeDraggingAndResizing() || !w->isWindow())
|
||||
if (!KDDockWidgets::usesNativeDraggingAndResizing() || !w->isWindow()) {
|
||||
Q_ASSERT(activeState());
|
||||
return activeState()->handleMouseButtonPress(draggableForQObject(o), Qt5Qt6Compat::eventGlobalPos(me), me->pos());
|
||||
}
|
||||
else break;
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::NonClientAreaMouseButtonRelease:
|
||||
@@ -465,28 +622,28 @@ bool DragController::eventFilter(QObject *o, QEvent *e)
|
||||
case QEvent::NonClientAreaMouseMove:
|
||||
case QEvent::MouseMove:
|
||||
return activeState()->handleMouseMove(Qt5Qt6Compat::eventGlobalPos(me));
|
||||
case QEvent::MouseButtonDblClick:
|
||||
return activeState()->handleMouseDoubleClick();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QStateMachine::eventFilter(o, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
StateBase *DragController::activeState() const
|
||||
{
|
||||
auto set = configuration();
|
||||
if (set.isEmpty())
|
||||
return nullptr;
|
||||
return static_cast<StateBase *>(*(set.begin()));
|
||||
return static_cast<StateBase *>(currentState());
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
static QWidget *qtTopLevelForHWND(HWND hwnd)
|
||||
static QWidgetOrQuick *qtTopLevelForHWND(HWND hwnd)
|
||||
{
|
||||
auto topLevels = qApp->topLevelWidgets();
|
||||
for (auto topLevel : topLevels) {
|
||||
if (hwnd == (HWND)topLevel->winId())
|
||||
return topLevel;
|
||||
const QList<QWindow*> windows = qApp->topLevelWindows();
|
||||
for (QWindow *window : windows) {
|
||||
if (hwnd == (HWND)window->winId()) {
|
||||
return DockRegistry::self()->topLevelForHandle(window);
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(toplevels) << Q_FUNC_INFO << "Couldn't find hwnd for top-level" << hwnd;
|
||||
@@ -520,8 +677,7 @@ WidgetType *DragController::qtTopLevelUnderCursor() const
|
||||
QPoint globalPos = QCursor::pos();
|
||||
|
||||
if (qApp->platformName() == QLatin1String("windows")) { // So -platform offscreen on Windows doesn't use this
|
||||
# if defined(Q_OS_WIN)
|
||||
auto topLevels = qApp->topLevelWidgets();
|
||||
#if defined(Q_OS_WIN)
|
||||
POINT globalNativePos;
|
||||
if (!GetCursorPos(&globalNativePos))
|
||||
return nullptr;
|
||||
@@ -544,7 +700,8 @@ WidgetType *DragController::qtTopLevelUnderCursor() const
|
||||
return tl;
|
||||
}
|
||||
} else {
|
||||
// Maybe it's embedded in a QWinWidget:
|
||||
# ifdef KDDOCKWIDGETS_QTWIDGETS // Maybe it's embedded in a QWinWidget:
|
||||
auto topLevels = qApp->topLevelWidgets();
|
||||
for (auto topLevel : topLevels) {
|
||||
if (QLatin1String(topLevel->metaObject()->className()) == QLatin1String("QWinWidget")) {
|
||||
if (hwnd == GetParent(HWND(topLevel->windowHandle()->winId()))) {
|
||||
@@ -555,13 +712,13 @@ WidgetType *DragController::qtTopLevelUnderCursor() const
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# endif // QtWidgets
|
||||
// A window belonging to another app is below the cursor
|
||||
qCDebug(toplevels) << Q_FUNC_INFO << "Window from another app is under cursor" << hwnd;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif // Q_OS_WIN
|
||||
} else {
|
||||
// !Windows: Linux, macOS, offscreen (offscreen on Windows too), etc.
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
#include "TitleBar_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
#include <QStateMachine>
|
||||
#include <QPoint>
|
||||
#include <QMimeData>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace KDDockWidgets {
|
||||
@@ -27,8 +28,37 @@ class StateBase;
|
||||
class DropArea;
|
||||
class Draggable;
|
||||
class FallbackMouseGrabber;
|
||||
class MinimalStateMachine;
|
||||
|
||||
class DOCKS_EXPORT DragController : public QStateMachine
|
||||
class State : public QObject
|
||||
{
|
||||
public:
|
||||
explicit State(MinimalStateMachine *parent);
|
||||
~State() override;
|
||||
|
||||
template <typename Obj, typename Signal>
|
||||
void addTransition(Obj *, Signal, State *dest);
|
||||
bool isCurrentState() const;
|
||||
|
||||
virtual void onEntry() = 0;
|
||||
private:
|
||||
MinimalStateMachine *const m_machine;
|
||||
};
|
||||
|
||||
class MinimalStateMachine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MinimalStateMachine(QObject *parent = nullptr);
|
||||
|
||||
State *currentState() const;
|
||||
void setCurrentState(State *);
|
||||
|
||||
private:
|
||||
State *m_currentState = nullptr;
|
||||
};
|
||||
|
||||
class DOCKS_EXPORT DragController : public MinimalStateMachine
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -75,6 +105,7 @@ private:
|
||||
friend class StatePreDrag;
|
||||
friend class StateDragging;
|
||||
friend class StateDropped;
|
||||
friend class StateDraggingWayland;
|
||||
|
||||
DragController(QObject * = nullptr);
|
||||
StateBase *activeState() const;
|
||||
@@ -92,7 +123,7 @@ private:
|
||||
FallbackMouseGrabber *m_fallbackMouseGrabber = nullptr;
|
||||
};
|
||||
|
||||
class StateBase : public QState
|
||||
class StateBase : public State
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -103,6 +134,13 @@ public:
|
||||
virtual bool handleMouseButtonPress(Draggable * /*receiver*/, QPoint /*globalPos*/, QPoint /*pos*/) { return false; }
|
||||
virtual bool handleMouseMove(QPoint /*globalPos*/) { return false; }
|
||||
virtual bool handleMouseButtonRelease(QPoint /*globalPos*/) { return false; }
|
||||
virtual bool handleMouseDoubleClick() { return false; }
|
||||
|
||||
// Only interesting for Wayland
|
||||
virtual bool handleDragEnter(QDragEnterEvent *, DropArea *) { return false; }
|
||||
virtual bool handleDragLeave(DropArea *) { return false; }
|
||||
virtual bool handleDragMove(QDragMoveEvent *, DropArea *) { return false; }
|
||||
virtual bool handleDrop(QDropEvent *, DropArea *) { return false; }
|
||||
|
||||
// Returns whether this is the current state
|
||||
bool isActiveState() const;
|
||||
@@ -116,7 +154,7 @@ class StateNone : public StateBase
|
||||
public:
|
||||
explicit StateNone(DragController *parent);
|
||||
~StateNone() override;
|
||||
void onEntry(QEvent *) override;
|
||||
void onEntry() override;
|
||||
bool handleMouseButtonPress(Draggable *draggable, QPoint globalPos, QPoint pos) override;
|
||||
};
|
||||
|
||||
@@ -126,9 +164,10 @@ class StatePreDrag : public StateBase
|
||||
public:
|
||||
explicit StatePreDrag(DragController *parent);
|
||||
~StatePreDrag() override;
|
||||
void onEntry(QEvent *) override;
|
||||
void onEntry() override;
|
||||
bool handleMouseMove(QPoint globalPos) override;
|
||||
bool handleMouseButtonRelease(QPoint) override;
|
||||
bool handleMouseDoubleClick() override;
|
||||
};
|
||||
|
||||
// Used on all platforms except Wayland. @see StateDraggingWayland
|
||||
@@ -138,9 +177,10 @@ class StateDragging : public StateBase
|
||||
public:
|
||||
explicit StateDragging(DragController *parent);
|
||||
~StateDragging() override;
|
||||
void onEntry(QEvent *) override;
|
||||
void onEntry() override;
|
||||
bool handleMouseButtonRelease(QPoint globalPos) override;
|
||||
bool handleMouseMove(QPoint globalPos) override;
|
||||
bool handleMouseDoubleClick() override;
|
||||
};
|
||||
|
||||
// Used on wayland only to use QDrag instead of setting geometry on mouse-move.
|
||||
@@ -150,9 +190,21 @@ class StateDraggingWayland : public StateDragging
|
||||
public:
|
||||
explicit StateDraggingWayland(DragController *parent);
|
||||
~StateDraggingWayland() override;
|
||||
void onEntry(QEvent *) override;
|
||||
void onEntry() override;
|
||||
bool handleMouseButtonRelease(QPoint globalPos) override;
|
||||
bool handleMouseMove(QPoint globalPos) override;
|
||||
bool handleDragEnter(QDragEnterEvent *, DropArea *) override;
|
||||
bool handleDragMove(QDragMoveEvent *, DropArea *) override;
|
||||
bool handleDragLeave(DropArea *) override;
|
||||
bool handleDrop(QDropEvent *, DropArea *) override;
|
||||
bool m_inQDrag = false;
|
||||
};
|
||||
|
||||
// A sub-class just so we don't use QMimeData directly. We'll only accept drops if its mime data
|
||||
// Can be qobject_casted to this class. For safety.
|
||||
class WaylandMimeData : public QMimeData
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include "DragController_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
@@ -54,7 +54,7 @@ QWidgetOrQuick *Draggable::asWidget() const
|
||||
|
||||
bool Draggable::dragCanStart(QPoint pressPos, QPoint globalPos) const
|
||||
{
|
||||
return (globalPos - pressPos).manhattanLength() > QApplication::startDragDistance();
|
||||
return (globalPos - pressPos).manhattanLength() > KDDockWidgets::startDragDistance();
|
||||
}
|
||||
|
||||
WidgetResizeHandler *Draggable::widgetResizeHandler() const
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef KD_DRAGGABLE_P_H
|
||||
#define KD_DRAGGABLE_P_H
|
||||
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
// #include "indicators/AnimatedIndicators_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
@@ -38,6 +39,13 @@ DropArea::DropArea(QWidgetOrQuick *parent)
|
||||
, m_dropIndicatorOverlay(Config::self().frameworkWidgetFactory()->createDropIndicatorOverlay(this))
|
||||
{
|
||||
qCDebug(creation) << "DropArea";
|
||||
if (isWayland()) {
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
setAcceptDrops(true);
|
||||
#else
|
||||
qWarning() << "Dropping not implement for QtQuick on Wayland yet!";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
DropArea::~DropArea()
|
||||
@@ -113,10 +121,10 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location, DockWidgetBa
|
||||
const bool hadSingleFloatingFrame = hasSingleFloatingFrame();
|
||||
|
||||
// Check if the dock widget already exists in the layout
|
||||
if (contains(dw)) {
|
||||
if (containsDockWidget(dw)) {
|
||||
Frame *oldFrame = dw->frame();
|
||||
if (oldFrame->hasSingleDockWidget()) {
|
||||
Q_ASSERT(oldFrame->contains(dw));
|
||||
Q_ASSERT(oldFrame->containsDockWidget(dw));
|
||||
// The frame only has this dock widget, and the frame is already in the layout. So move the frame instead
|
||||
frame = oldFrame;
|
||||
} else {
|
||||
@@ -141,9 +149,9 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location, DockWidgetBa
|
||||
}
|
||||
}
|
||||
|
||||
bool DropArea::contains(DockWidgetBase *dw) const
|
||||
bool DropArea::containsDockWidget(DockWidgetBase *dw) const
|
||||
{
|
||||
return dw->frame() && MultiSplitter::contains(dw->frame());
|
||||
return dw->frame() && MultiSplitter::containsFrame(dw->frame());
|
||||
}
|
||||
|
||||
bool DropArea::hasSingleFloatingFrame() const
|
||||
@@ -174,20 +182,20 @@ void DropArea::layoutParentContainerEqually(DockWidgetBase *dw)
|
||||
layoutEqually(item->parentContainer());
|
||||
}
|
||||
|
||||
void DropArea::hover(WindowBeingDragged *floatingWindow, QPoint globalPos)
|
||||
DropIndicatorOverlayInterface::DropLocation DropArea::hover(WindowBeingDragged *draggedWindow, QPoint globalPos)
|
||||
{
|
||||
if (!validateAffinity(floatingWindow))
|
||||
return;
|
||||
if (!validateAffinity(draggedWindow))
|
||||
return DropIndicatorOverlayInterface::DropLocation_None;
|
||||
|
||||
if (!m_dropIndicatorOverlay) {
|
||||
qWarning() << Q_FUNC_INFO << "The frontend is missing a drop indicator overlay";
|
||||
return;
|
||||
return DropIndicatorOverlayInterface::DropLocation_None;
|
||||
}
|
||||
|
||||
Frame *frame = frameContainingPos(globalPos); // Frame is nullptr if MainWindowOption_HasCentralFrame isn't set
|
||||
m_dropIndicatorOverlay->setWindowBeingDragged(floatingWindow != nullptr);
|
||||
m_dropIndicatorOverlay->setWindowBeingDragged(true);
|
||||
m_dropIndicatorOverlay->setHoveredFrame(frame);
|
||||
m_dropIndicatorOverlay->hover(globalPos);
|
||||
return m_dropIndicatorOverlay->hover(globalPos);
|
||||
}
|
||||
|
||||
static bool isOutterLocation(DropIndicatorOverlayInterface::DropLocation location)
|
||||
@@ -205,8 +213,7 @@ static bool isOutterLocation(DropIndicatorOverlayInterface::DropLocation locatio
|
||||
|
||||
bool DropArea::drop(WindowBeingDragged *droppedWindow, QPoint globalPos)
|
||||
{
|
||||
FloatingWindow *floatingWindow = droppedWindow ? droppedWindow->floatingWindow()
|
||||
: nullptr;
|
||||
FloatingWindow *floatingWindow = droppedWindow->floatingWindow();
|
||||
|
||||
if (floatingWindow == window()) {
|
||||
qWarning() << "Refusing to drop onto itself"; // Doesn't happen
|
||||
@@ -223,17 +230,35 @@ bool DropArea::drop(WindowBeingDragged *droppedWindow, QPoint globalPos)
|
||||
hover(droppedWindow, globalPos);
|
||||
auto droploc = m_dropIndicatorOverlay->currentDropLocation();
|
||||
Frame *acceptingFrame = m_dropIndicatorOverlay->hoveredFrame();
|
||||
if (!(acceptingFrame || isOutterLocation(m_dropIndicatorOverlay->currentDropLocation()))) {
|
||||
qWarning() << "DropArea::drop: asserted with frame=" << acceptingFrame << "; Location=" << m_dropIndicatorOverlay->currentDropLocation();
|
||||
if (!(acceptingFrame || isOutterLocation(droploc))) {
|
||||
qWarning() << "DropArea::drop: asserted with frame=" << acceptingFrame
|
||||
<< "; Location=" << droploc;
|
||||
return false;
|
||||
}
|
||||
|
||||
return drop(floatingWindow, acceptingFrame, droploc);
|
||||
return drop(droppedWindow, acceptingFrame, droploc);
|
||||
}
|
||||
|
||||
bool DropArea::drop(FloatingWindow *droppedWindow, Frame *acceptingFrame,
|
||||
bool DropArea::drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame,
|
||||
DropIndicatorOverlayInterface::DropLocation droploc)
|
||||
{
|
||||
FloatingWindow *droppedWindow = draggedWindow ? draggedWindow->floatingWindow()
|
||||
: nullptr;
|
||||
|
||||
if (isWayland() && !droppedWindow) {
|
||||
// This is the Wayland special case.
|
||||
// With other platforms, when detaching a tab or dock widget we create the FloatingWindow immediately.
|
||||
// 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();
|
||||
if (!droppedWindow) {
|
||||
// Doesn't happen
|
||||
qWarning() << Q_FUNC_INFO << "Wayland: Expected window" << draggedWindow;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
const bool needToFocusNewlyDroppedWidgets = Config::self().flags() & Config::Flag_TitleBarIsFocusable;
|
||||
const DockWidgetBase::List droppedDockWidgets = needToFocusNewlyDroppedWidgets ? droppedWindow->multiSplitter()->dockWidgets()
|
||||
@@ -271,7 +296,7 @@ bool DropArea::drop(FloatingWindow *droppedWindow, Frame *acceptingFrame,
|
||||
|
||||
if (needToFocusNewlyDroppedWidgets) {
|
||||
// Let's also focus the newly dropped dock widget
|
||||
if (droppedDockWidgets.size() > 0) {
|
||||
if (!droppedDockWidgets.isEmpty()) {
|
||||
// If more than 1 was dropped, we only focus the first one
|
||||
Frame *frame = droppedDockWidgets.first()->frame();
|
||||
frame->FocusScope::focus(Qt::MouseFocusReason);
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
#ifndef KD_DROP_AREA_P_H
|
||||
#define KD_DROP_AREA_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "Frame_p.h"
|
||||
#include "KDDockWidgets.h"
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
|
||||
class TestCommon;
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
~DropArea();
|
||||
|
||||
void removeHover();
|
||||
void hover(WindowBeingDragged *floatingWindow, QPoint globalPos);
|
||||
DropIndicatorOverlayInterface::DropLocation hover(WindowBeingDragged *draggedWindow, QPoint globalPos);
|
||||
///@brief Called when a user drops a widget via DND
|
||||
bool drop(WindowBeingDragged *droppedWindow, QPoint globalPos);
|
||||
int numFrames() const;
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
DropIndicatorOverlayInterface *dropIndicatorOverlay() const { return m_dropIndicatorOverlay; }
|
||||
void addDockWidget(DockWidgetBase *, KDDockWidgets::Location location, DockWidgetBase *relativeTo, AddingOption option = {});
|
||||
|
||||
bool contains(DockWidgetBase *) const;
|
||||
bool containsDockWidget(DockWidgetBase *) const;
|
||||
|
||||
/// Returns whether this layout has a single dock widget which is floating
|
||||
/// Implies it's in a FloatingWindow and that it has only one dock widget
|
||||
@@ -65,15 +65,14 @@ public:
|
||||
private:
|
||||
Q_DISABLE_COPY(DropArea)
|
||||
friend class Frame;
|
||||
friend class TestDocks;
|
||||
friend class ::TestCommon;
|
||||
friend class ::TestDocks;
|
||||
friend class DropIndicatorOverlayInterface;
|
||||
friend class AnimatedIndicators;
|
||||
friend class FloatingWindow;
|
||||
|
||||
template <typename T>
|
||||
bool validateAffinity(T *, Frame *acceptingFrame = nullptr) const;
|
||||
bool drop(FloatingWindow *droppedWindow, Frame *acceptingFrame, DropIndicatorOverlayInterface::DropLocation);
|
||||
bool drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame, DropIndicatorOverlayInterface::DropLocation);
|
||||
bool drop(QWidgetOrQuick *droppedwindow, KDDockWidgets::Location location, Frame *relativeTo);
|
||||
Frame *frameContainingPos(QPoint globalPos) const;
|
||||
void updateFloatingActions();
|
||||
|
||||
@@ -118,9 +118,9 @@ void DropIndicatorOverlayInterface::setCurrentDropLocation(DropIndicatorOverlayI
|
||||
}
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::hover(QPoint globalPos)
|
||||
DropIndicatorOverlayInterface::DropLocation DropIndicatorOverlayInterface::hover(QPoint globalPos)
|
||||
{
|
||||
hover_impl(globalPos);
|
||||
return hover_impl(globalPos);
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::setHoveredFrameRect(QRect rect)
|
||||
|
||||
@@ -53,9 +53,11 @@ public:
|
||||
Frame *hoveredFrame() const { return m_hoveredFrame; }
|
||||
void setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation location);
|
||||
|
||||
void hover(QPoint globalPos);
|
||||
KDDockWidgets::DropIndicatorOverlayInterface::DropLocation hover(QPoint globalPos);
|
||||
|
||||
virtual QPoint posForIndicator(DropLocation) const { return {}; }; // Used by unit-tests only
|
||||
/// @brief returns the position of the specified drop location
|
||||
/// The return is in global coordinates
|
||||
virtual QPoint posForIndicator(DropLocation) const = 0;
|
||||
|
||||
static KDDockWidgets::Location multisplitterLocationFor(DropLocation);
|
||||
|
||||
@@ -71,7 +73,7 @@ private:
|
||||
DropLocation m_currentDropLocation = DropLocation_None;
|
||||
|
||||
protected:
|
||||
virtual void hover_impl(QPoint globalPos) = 0;
|
||||
virtual DropIndicatorOverlayInterface::DropLocation hover_impl(QPoint globalPos) = 0;
|
||||
virtual void onHoveredFrameChanged(Frame *);
|
||||
virtual void updateVisibility() {};
|
||||
|
||||
@@ -79,6 +81,7 @@ protected:
|
||||
DropArea *const m_dropArea;
|
||||
bool m_draggedWindowIsHovering = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "MainWindowBase.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "Utils_p.h"
|
||||
@@ -34,10 +33,10 @@
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
|
||||
#if defined(Q_OS_WIN)
|
||||
# ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
namespace KDDockWidgets {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper to rediriect WM_NCHITTEST from child widgets to the top-level widget
|
||||
*
|
||||
@@ -45,12 +44,14 @@ namespace KDDockWidgets {
|
||||
* in FloatingWindow::nativeEvent(). But if the child widgets have a native handle, then
|
||||
* the WM_NCHITTEST will go to them. They have to respond HTTRANSPARENT so the event
|
||||
* is redirected.
|
||||
*
|
||||
* This only affects QtWidgets, since QQuickItems never have native WId.
|
||||
*/
|
||||
class NCHITTESTEventFilter : public QAbstractNativeEventFilter
|
||||
{
|
||||
public:
|
||||
explicit NCHITTESTEventFilter(FloatingWindow *fw) : m_floatingWindow(fw) {}
|
||||
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override
|
||||
bool nativeEventFilter(const QByteArray &eventType, void *message, Qt5Qt6Compat::qintptr *result) override
|
||||
{
|
||||
if (eventType != "windows_generic_MSG" || !m_floatingWindow)
|
||||
return false;
|
||||
@@ -58,11 +59,14 @@ public:
|
||||
auto msg = static_cast<MSG *>(message);
|
||||
if (msg->message != WM_NCHITTEST)
|
||||
return false;
|
||||
QWidget *child = QWidget::find(WId(msg->hwnd));
|
||||
const WId wid = WId(msg->hwnd);
|
||||
|
||||
QWidget *child = QWidget::find(wid);
|
||||
if (!child || child->window() != m_floatingWindow)
|
||||
return false;
|
||||
const bool isThisWindow = child == m_floatingWindow;
|
||||
|
||||
if (child != m_floatingWindow) {
|
||||
if (!isThisWindow) {
|
||||
*result = HTTRANSPARENT;
|
||||
return true;
|
||||
}
|
||||
@@ -73,7 +77,9 @@ public:
|
||||
QPointer<FloatingWindow> m_floatingWindow;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
# endif
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
static Qt::WindowFlags windowFlagsToUse()
|
||||
{
|
||||
@@ -133,32 +139,21 @@ FloatingWindow::FloatingWindow(MainWindowBase *parent)
|
||||
, m_dropArea(new DropArea(this))
|
||||
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
|
||||
{
|
||||
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
|
||||
// On Windows with Qt 5.9 (and maybe earlier), the WM_NCALCSIZE isn't being processed unless we explicitly create the window.
|
||||
// So create it now, otherwise floating dock widgets will show a native title bar until resized.
|
||||
create();
|
||||
|
||||
if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
|
||||
m_nchittestFilter = new NCHITTESTEventFilter(this);
|
||||
qApp->installNativeEventFilter(m_nchittestFilter);
|
||||
|
||||
connect(windowHandle(), &QWindow::screenChanged, this, [this] {
|
||||
// Qt honors our frame hijacking usually... but when screen changes we must give it a nudge.
|
||||
// Otherwise what Qt thinks is the client area is not what Windows knows it is.
|
||||
// SetWindowPos() will trigger an NCCALCSIZE message, which Qt will intercept and take note of the margins we're using.
|
||||
SetWindowPos(HWND(winId()), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
});
|
||||
|
||||
// Show drop-shadow:
|
||||
MARGINS margins = {0, 0, 0, 1}; // arbitrary, just needs to be > 0 it seems
|
||||
DwmExtendFrameIntoClientArea(HWND(winId()), &margins);
|
||||
if (kddwUsesQtWidgets()) {
|
||||
// For QtQuick we do it a bit later, once we have the QQuickWindow
|
||||
setupWindow();
|
||||
}
|
||||
#endif
|
||||
|
||||
DockRegistry::self()->registerFloatingWindow(this);
|
||||
qCDebug(creation) << "FloatingWindow()" << this;
|
||||
|
||||
maybeCreateResizeHandler();
|
||||
if (Config::self().flags() & Config::Flag_KeepAboveIfNotUtilityWindow)
|
||||
setWindowFlag(Qt::WindowStaysOnTopHint, true);
|
||||
|
||||
if (kddwUsesQtWidgets()) {
|
||||
// QtQuick will do it a bit later, once it has a QWindow
|
||||
maybeCreateResizeHandler();
|
||||
}
|
||||
|
||||
updateTitleBarVisibility();
|
||||
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::onFrameCountChanged);
|
||||
@@ -188,8 +183,37 @@ FloatingWindow::~FloatingWindow()
|
||||
qCDebug(creation) << "~FloatingWindow";
|
||||
}
|
||||
|
||||
void FloatingWindow::setupWindow()
|
||||
{
|
||||
// Does some minor setup on our QWindow.
|
||||
// Like adding the drop shadow on Windows and two other workarounds.
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// On Windows with Qt 5.9 (and maybe earlier), the WM_NCALCSIZE isn't being processed unless we explicitly create the window.
|
||||
// So create it now, otherwise floating dock widgets will show a native title bar until resized.
|
||||
create();
|
||||
|
||||
if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
|
||||
# ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
m_nchittestFilter = new NCHITTESTEventFilter(this);
|
||||
qApp->installNativeEventFilter(m_nchittestFilter);
|
||||
#endif
|
||||
connect(windowHandle(), &QWindow::screenChanged, this, [this] {
|
||||
// Qt honors our frame hijacking usually... but when screen changes we must give it a nudge.
|
||||
// Otherwise what Qt thinks is the client area is not what Windows knows it is.
|
||||
// SetWindowPos() will trigger an NCCALCSIZE message, which Qt will intercept and take note of the margins we're using.
|
||||
SetWindowPos(HWND(winId()), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
});
|
||||
|
||||
// Show drop-shadow:
|
||||
MARGINS margins = {0, 0, 0, 1}; // arbitrary, just needs to be > 0 it seems
|
||||
DwmExtendFrameIntoClientArea(HWND(winId()), &margins);
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
|
||||
bool FloatingWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
||||
bool FloatingWindow::nativeEvent(const QByteArray &eventType, void *message, Qt5Qt6Compat::qintptr *result)
|
||||
{
|
||||
if (!m_inDtor && !m_deleteScheduled && KDDockWidgets::usesAeroSnapWithCustomDecos()) {
|
||||
// To enable aero snap we need to tell Windows where's our custom title bar
|
||||
@@ -205,9 +229,7 @@ void FloatingWindow::maybeCreateResizeHandler()
|
||||
{
|
||||
if (!KDDockWidgets::usesNativeDraggingAndResizing()) {
|
||||
setFlag(Qt::FramelessWindowHint, true);
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
setWidgetResizeHandler(new WidgetResizeHandler(this));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +250,11 @@ DockWidgetBase *FloatingWindow::singleDockWidget() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const DockWidgetBase::List FloatingWindow::dockWidgets() const
|
||||
{
|
||||
return m_dropArea->dockWidgets();
|
||||
}
|
||||
|
||||
const Frame::List FloatingWindow::frames() const
|
||||
{
|
||||
Q_ASSERT(m_dropArea);
|
||||
@@ -270,6 +297,14 @@ MultiSplitter *FloatingWindow::multiSplitter() const
|
||||
|
||||
bool FloatingWindow::isInDragArea(QPoint globalPoint) const
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
// A click near the border will still send a Qt::NonClientMousePressEvent. We shouldn't
|
||||
// interpret that as a drag, as it's for a native resize.
|
||||
// Keep track of how we handled the WM_NCHITTEST
|
||||
if (m_lastHitTest != 0 && m_lastHitTest != HTCAPTION)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return dragRect().contains(globalPoint);
|
||||
}
|
||||
|
||||
@@ -308,7 +343,7 @@ bool FloatingWindow::hasSingleDockWidget() const
|
||||
|
||||
bool FloatingWindow::beingDeleted() const
|
||||
{
|
||||
if (m_deleteScheduled)
|
||||
if (m_deleteScheduled || m_inDtor)
|
||||
return true;
|
||||
|
||||
// TODO: Confusing logic
|
||||
@@ -387,10 +422,10 @@ void FloatingWindow::updateTitleAndIcon()
|
||||
m_titleBar->setTitle(title);
|
||||
m_titleBar->setIcon(icon);
|
||||
|
||||
if (KDDockWidgets::usesNativeTitleBar()) {
|
||||
setWindowTitle(title);
|
||||
setWindowIcon(icon);
|
||||
}
|
||||
// Even without a native title bar it's nice to set the window title/icon, so it shows
|
||||
// in the taskbar (when minimization is supported), or Alt-Tab (in supporting Window Managers)
|
||||
setWindowTitle(title);
|
||||
setWindowIcon(icon);
|
||||
}
|
||||
|
||||
void FloatingWindow::onCloseEvent(QCloseEvent *e)
|
||||
@@ -438,6 +473,7 @@ LayoutSaver::FloatingWindow FloatingWindow::serialize() const
|
||||
auto mainWindow = qobject_cast<MainWindowBase*>(parentWidget());
|
||||
fw.parentIndex = mainWindow ? DockRegistry::self()->mainwindows().indexOf(mainWindow)
|
||||
: -1;
|
||||
|
||||
return fw;
|
||||
}
|
||||
|
||||
@@ -465,4 +501,3 @@ bool FloatingWindow::event(QEvent *ev)
|
||||
|
||||
return QWidgetAdapter::event(ev);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
#ifndef KD_FLOATING_WINDOW_P_H
|
||||
#define KD_FLOATING_WINDOW_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "../docks_export.h"
|
||||
#include "../QWidgetAdapter.h"
|
||||
#include "../LayoutSaver_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Draggable_p.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Qt5Qt6Compat_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAbstractNativeEventFilter;
|
||||
@@ -49,9 +51,15 @@ public:
|
||||
std::unique_ptr<WindowBeingDragged> makeWindow() override;
|
||||
DockWidgetBase *singleDockWidget() const override;
|
||||
|
||||
const QVector<DockWidgetBase*> dockWidgets() const;
|
||||
const Frame::List frames() const;
|
||||
DropArea *dropArea() const { return m_dropArea; }
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void setLastHitTest(int hitTest) {
|
||||
m_lastHitTest = hitTest;
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @brief Returns the title bar.
|
||||
*
|
||||
@@ -128,18 +136,20 @@ Q_SIGNALS:
|
||||
void numFramesChanged();
|
||||
void windowStateChanged(QWindowStateChangeEvent *);
|
||||
protected:
|
||||
void setupWindow();
|
||||
void maybeCreateResizeHandler();
|
||||
|
||||
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, Qt5Qt6Compat::qintptr *result) override;
|
||||
#endif
|
||||
|
||||
bool event(QEvent *ev) override;
|
||||
void onCloseEvent(QCloseEvent *) override;
|
||||
|
||||
DropArea *const m_dropArea;
|
||||
QPointer<DropArea> m_dropArea;
|
||||
TitleBar *const m_titleBar;
|
||||
private:
|
||||
Q_DISABLE_COPY(FloatingWindow)
|
||||
void maybeCreateResizeHandler();
|
||||
void onFrameCountChanged(int count);
|
||||
void onVisibleFrameCountChanged(int count);
|
||||
bool m_disableSetVisible = false;
|
||||
@@ -148,6 +158,9 @@ private:
|
||||
bool m_updatingTitleBarVisibility = false;
|
||||
QMetaObject::Connection m_layoutDestroyedConnection;
|
||||
QAbstractNativeEventFilter *m_nchittestFilter = nullptr;
|
||||
#ifdef Q_OS_WIN
|
||||
int m_lastHitTest = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ void Frame::insertWidget(DockWidgetBase *dockWidget, int index, AddingOption add
|
||||
<< "; addingOption=" << addingOption;
|
||||
|
||||
Q_ASSERT(dockWidget);
|
||||
if (contains(dockWidget)) {
|
||||
if (containsDockWidget(dockWidget)) {
|
||||
qWarning() << "Frame::addWidget dockWidget already exists. this=" << this << "; dockWidget=" << dockWidget;
|
||||
return;
|
||||
}
|
||||
@@ -171,11 +171,25 @@ void Frame::removeWidget(DockWidgetBase *dw)
|
||||
removeWidget_impl(dw);
|
||||
}
|
||||
|
||||
void Frame::detachTab(DockWidgetBase *dw)
|
||||
FloatingWindow* Frame::detachTab(DockWidgetBase *dockWidget)
|
||||
{
|
||||
if (m_inCtor || m_inDtor) return;
|
||||
if (m_inCtor || m_inDtor) return nullptr;
|
||||
|
||||
detachTab_impl(dw);
|
||||
QRect r = dockWidget->geometry();
|
||||
removeWidget(dockWidget);
|
||||
|
||||
auto newFrame = Config::self().frameworkWidgetFactory()->createFrame();
|
||||
const QPoint globalPoint = mapToGlobal(QPoint(0, 0));
|
||||
newFrame->addWidget(dockWidget);
|
||||
|
||||
// We're potentially already dead at this point, as frames with 0 tabs auto-destruct. Don't access members from this point.
|
||||
|
||||
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(newFrame);
|
||||
r.moveTopLeft(globalPoint);
|
||||
floatingWindow->setSuggestedGeometry(r);
|
||||
floatingWindow->show();
|
||||
|
||||
return floatingWindow;
|
||||
}
|
||||
|
||||
int Frame::indexOfDockWidget(DockWidgetBase *dw)
|
||||
@@ -347,7 +361,7 @@ const DockWidgetBase::List Frame::dockWidgets() const
|
||||
return dockWidgets;
|
||||
}
|
||||
|
||||
bool Frame::contains(DockWidgetBase *dockWidget) const
|
||||
bool Frame::containsDockWidget(DockWidgetBase *dockWidget) const
|
||||
{
|
||||
const int count = dockWidgetCount();
|
||||
for (int i = 0, e = count; i != e; ++i) {
|
||||
@@ -442,7 +456,7 @@ bool Frame::anyNonDockable() const
|
||||
|
||||
void Frame::onDockWidgetShown(DockWidgetBase *w)
|
||||
{
|
||||
if (hasSingleDockWidget() && contains(w)) { // We have to call contains because it might be being in process of being reparented
|
||||
if (hasSingleDockWidget() && containsDockWidget(w)) { // We have to call contains because it might be being in process of being reparented
|
||||
if (!QWidgetAdapter::isVisible()) {
|
||||
qCDebug(hiding) << "Widget" << w << " was shown, we're=" << "; visible="
|
||||
<< QWidgetAdapter::isVisible();
|
||||
@@ -453,7 +467,7 @@ void Frame::onDockWidgetShown(DockWidgetBase *w)
|
||||
|
||||
void Frame::onDockWidgetHidden(DockWidgetBase *w)
|
||||
{
|
||||
if (hasSingleDockWidget() && contains(w)) { // We have to call contains because it might be being in process of being reparented
|
||||
if (hasSingleDockWidget() && containsDockWidget(w)) { // We have to call contains because it might be being in process of being reparented
|
||||
if (QWidgetAdapter::isVisible()) {
|
||||
qCDebug(hiding) << "Widget" << w << " was hidden, we're="
|
||||
<< "; visible=" << QWidgetAdapter::isVisible()
|
||||
@@ -573,7 +587,6 @@ bool Frame::isInMainWindow() const
|
||||
bool Frame::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::ParentChange) {
|
||||
qCDebug(docking) << "Frame: parent changed to =" << QWidgetAdapter::parentWidget();
|
||||
if (auto dropArea = qobject_cast<DropArea *>(QWidgetAdapter::parentWidget())) {
|
||||
setDropArea(dropArea);
|
||||
} else {
|
||||
@@ -637,7 +650,7 @@ QSize Frame::dockWidgetsMinSize() const
|
||||
{
|
||||
QSize size = Layouting::Item::hardcodedMinimumSize;
|
||||
for (DockWidgetBase *dw : dockWidgets())
|
||||
size = size.expandedTo(Layouting::Widget_qwidget::widgetMinSize(dw));
|
||||
size = size.expandedTo(Layouting::Widget::widgetMinSize(dw));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -19,18 +19,19 @@
|
||||
#ifndef KD_FRAME_P_H
|
||||
#define KD_FRAME_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "multisplitter/Widget_qwidget.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
#include "kddockwidgets/FocusScope.h"
|
||||
#include "../LayoutSaver_p.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "FocusScope.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
#include <QDebug>
|
||||
#include <QPointer>
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class TitleBar;
|
||||
@@ -55,6 +56,7 @@ class DOCKS_EXPORT Frame
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(KDDockWidgets::TitleBar* titleBar READ titleBar CONSTANT)
|
||||
Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentDockWidgetChanged)
|
||||
public:
|
||||
typedef QList<Frame *> List;
|
||||
|
||||
@@ -78,7 +80,7 @@ public:
|
||||
void removeWidget(DockWidgetBase *);
|
||||
|
||||
///@brief detaches this dock widget
|
||||
void detachTab(DockWidgetBase *);
|
||||
FloatingWindow *detachTab(DockWidgetBase *);
|
||||
|
||||
///@brief returns the index of the specified dock widget
|
||||
int indexOfDockWidget(DockWidgetBase *);
|
||||
@@ -165,7 +167,7 @@ public:
|
||||
bool alwaysShowsTabs() const { return m_options & FrameOption_AlwaysShowsTabs; }
|
||||
|
||||
/// @brief returns whether the dockwidget @p w is inside this frame
|
||||
bool contains(DockWidgetBase *w) const;
|
||||
bool containsDockWidget(DockWidgetBase *w) const;
|
||||
|
||||
///@brief returns the FloatingWindow this frame is in, if any
|
||||
FloatingWindow *floatingWindow() const;
|
||||
@@ -268,7 +270,6 @@ protected:
|
||||
void onDockWidgetCountChanged();
|
||||
|
||||
virtual void removeWidget_impl(DockWidgetBase *) = 0;
|
||||
virtual void detachTab_impl(DockWidgetBase *) = 0;
|
||||
virtual int indexOfDockWidget_impl(DockWidgetBase *) = 0;
|
||||
virtual int currentIndex_impl() const = 0;
|
||||
virtual void setCurrentTabIndex_impl(int index) = 0;
|
||||
@@ -277,10 +278,12 @@ protected:
|
||||
virtual DockWidgetBase *dockWidgetAt_impl(int index) const = 0;
|
||||
virtual DockWidgetBase *currentDockWidget_impl() const = 0;
|
||||
virtual int dockWidgetCount_impl() const = 0;
|
||||
virtual int nonContentsHeight() const = 0;
|
||||
|
||||
bool m_inDtor = false;
|
||||
private:
|
||||
Q_DISABLE_COPY(Frame)
|
||||
friend class TestDocks;
|
||||
friend class ::TestDocks;
|
||||
friend class TabWidget;
|
||||
void onCurrentTabChanged(int index);
|
||||
void scheduleDeleteLater();
|
||||
|
||||
@@ -17,17 +17,9 @@ Q_LOGGING_CATEGORY(hovering, "kdab.docks.hovering", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(mouseevents, "kdab.docks.mouseevents", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(state, "kdab.docks.state", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(docking, "kdab.docks.docking", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(globalevents, "kdab.docks.globalevents", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(hiding, "kdab.docks.hiding", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(closing, "kdab.docks.closing", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(overlay, "kdab.docks.overlay", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(dropping, "kdab.docks.dropping", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(restoring, "kdab.docks.restoring", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(title, "kdab.docks.title", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(closebutton, "kdab.docks.closebutton", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(sizing, "kdab.multisplitter.sizing", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(multisplittercreation, "kdab.multisplitter.multisplittercreation", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(addwidget, "kdab.multisplitter.addwidget", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(anchors, "kdab.multisplitter.anchors", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(item, "kdab.multisplitter.item", QtWarningMsg)
|
||||
Q_LOGGING_CATEGORY(placeholder, "kdab.multisplitter.placeholder", QtWarningMsg)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Config.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "multisplitter/Widget_qwidget.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
@@ -46,7 +46,7 @@ MultiSplitter::MultiSplitter(QWidgetOrQuick *parent)
|
||||
|
||||
setLayoutSize(parent->size());
|
||||
|
||||
qCDebug(multisplittercreation()) << "MultiSplitter";
|
||||
qCDebug(creation) << "MultiSplitter";
|
||||
|
||||
// Initialize min size
|
||||
updateSizeConstraints();
|
||||
@@ -56,7 +56,7 @@ MultiSplitter::MultiSplitter(QWidgetOrQuick *parent)
|
||||
|
||||
MultiSplitter::~MultiSplitter()
|
||||
{
|
||||
qCDebug(multisplittercreation) << "~MultiSplitter" << this;
|
||||
qCDebug(creation) << "~MultiSplitter" << this;
|
||||
if (m_rootItem->hostWidget()->asQObject() == this)
|
||||
delete m_rootItem;
|
||||
DockRegistry::self()->unregisterLayout(this);
|
||||
@@ -72,7 +72,7 @@ bool MultiSplitter::onResize(QSize newSize)
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "; new=" << newSize
|
||||
<< "; window=" << window();
|
||||
|
||||
QScopedValueRollback<bool>(m_inResizeEvent, true); // to avoid re-entrancy
|
||||
QScopedValueRollback<bool> resizeGuard(m_inResizeEvent, true); // to avoid re-entrancy
|
||||
|
||||
if (!LayoutSaver::restoreInProgress()) {
|
||||
// don't resize anything while we're restoring the layout
|
||||
@@ -135,7 +135,7 @@ bool MultiSplitter::validateInputs(QWidgetOrQuick *widget,
|
||||
|
||||
Layouting::Item *item = itemForFrame(qobject_cast<Frame*>(widget));
|
||||
|
||||
if (contains(item)) {
|
||||
if (containsItem(item)) {
|
||||
qWarning() << "MultiSplitter::addWidget: Already contains" << widget;
|
||||
return false;
|
||||
}
|
||||
@@ -148,7 +148,7 @@ bool MultiSplitter::validateInputs(QWidgetOrQuick *widget,
|
||||
const bool relativeToThis = relativeToFrame == nullptr;
|
||||
|
||||
Layouting::Item *relativeToItem = itemForFrame(relativeToFrame);
|
||||
if (!relativeToThis && !contains(relativeToItem)) {
|
||||
if (!relativeToThis && !containsItem(relativeToItem)) {
|
||||
qWarning() << "MultiSplitter::addWidget: Doesn't contain relativeTo:"
|
||||
<< "; relativeToFrame=" << relativeToFrame
|
||||
<< "; relativeToItem=" << relativeToItem
|
||||
@@ -242,12 +242,12 @@ void MultiSplitter::removeItem(Layouting::Item *item)
|
||||
item->parentContainer()->removeItem(item);
|
||||
}
|
||||
|
||||
bool MultiSplitter::contains(const Layouting::Item *item) const
|
||||
bool MultiSplitter::containsItem(const Layouting::Item *item) const
|
||||
{
|
||||
return m_rootItem->contains_recursive(item);
|
||||
}
|
||||
|
||||
bool MultiSplitter::contains(const Frame *frame) const
|
||||
bool MultiSplitter::containsFrame(const Frame *frame) const
|
||||
{
|
||||
return itemForFrame(frame) != nullptr;
|
||||
}
|
||||
|
||||
@@ -35,12 +35,14 @@ class Separator;
|
||||
class Widget_qwidget;
|
||||
}
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class MainWindowBase;
|
||||
class FloatingWindow;
|
||||
class Frame;
|
||||
class WindowBeingDragged;
|
||||
struct WindowBeingDragged;
|
||||
|
||||
/**
|
||||
* MultiSplitter is simply a wrapper around Layouting::Item in which the hosted widgets are
|
||||
@@ -87,12 +89,12 @@ public:
|
||||
/**
|
||||
* @brief Returns true if this layout contains the specified item.
|
||||
*/
|
||||
bool contains(const Layouting::Item *) const;
|
||||
bool containsItem(const Layouting::Item *) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if this layout contains the specified frame.
|
||||
*/
|
||||
bool contains(const Frame *) const;
|
||||
bool containsFrame(const Frame *) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of Item objects in this layout.
|
||||
@@ -213,7 +215,7 @@ protected:
|
||||
private:
|
||||
bool m_inResizeEvent = false;
|
||||
|
||||
friend class TestDocks;
|
||||
friend class ::TestDocks;
|
||||
|
||||
/**
|
||||
* @brief returns the frames contained in @p frameOrMultiSplitter
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Position_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -82,7 +83,7 @@ bool Position::containsPlaceholder(Layouting::Item *item) const
|
||||
|
||||
void Position::removePlaceholders()
|
||||
{
|
||||
QScopedValueRollback<bool>(m_clearing, true);
|
||||
QScopedValueRollback<bool> clearGuard(m_clearing, true);
|
||||
m_placeholders.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ void SideBar::removeDockWidget(DockWidgetBase *dw)
|
||||
updateSize();
|
||||
}
|
||||
|
||||
bool SideBar::contains(DockWidgetBase *dw) const
|
||||
bool SideBar::containsDockWidget(DockWidgetBase *dw) const
|
||||
{
|
||||
return m_dockWidgets.contains(dw);
|
||||
}
|
||||
@@ -107,3 +107,19 @@ void SideBar::toggleOverlay(DockWidgetBase *dw)
|
||||
{
|
||||
m_mainWindow->toggleOverlayOnSideBar(dw);
|
||||
}
|
||||
|
||||
QStringList SideBar::serialize() const
|
||||
{
|
||||
QStringList ids;
|
||||
ids.reserve(m_dockWidgets.size());
|
||||
for (DockWidgetBase *dw : m_dockWidgets)
|
||||
ids << dw->uniqueName();
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
void SideBar::clear()
|
||||
{
|
||||
for (DockWidgetBase *dw : qAsConst(m_dockWidgets))
|
||||
removeDockWidget(dw);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
|
||||
void addDockWidget(DockWidgetBase *dw);
|
||||
void removeDockWidget(DockWidgetBase *dw);
|
||||
bool contains(DockWidgetBase *) const;
|
||||
bool containsDockWidget(DockWidgetBase *) const;
|
||||
|
||||
/// @brief Returns this side bar's orientation
|
||||
Qt::Orientation orientation() const;
|
||||
@@ -49,6 +49,13 @@ public:
|
||||
/// @brief Toggles the dock widget overlay. Equivalent to the user clicking on the button.
|
||||
void toggleOverlay(DockWidgetBase *);
|
||||
|
||||
/// @brief returns a serialization of this sidebar's state
|
||||
/// Currently it's just a list of dock widget ids
|
||||
QStringList serialize() const;
|
||||
|
||||
/// @brief clears the sidebar (removes all dock widgets from it)
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
virtual void addDockWidget_Impl(DockWidgetBase *dock) = 0;
|
||||
virtual void removeDockWidget_Impl(DockWidgetBase *dock) = 0;
|
||||
|
||||
@@ -69,6 +69,8 @@ void TitleBar::init()
|
||||
// repaint
|
||||
update();
|
||||
});
|
||||
updateCloseButton();
|
||||
updateFloatButton();
|
||||
}
|
||||
|
||||
TitleBar::~TitleBar()
|
||||
@@ -89,6 +91,16 @@ bool TitleBar::onDoubleClicked()
|
||||
return false;
|
||||
}
|
||||
|
||||
void TitleBar::updateCloseButton()
|
||||
{
|
||||
|
||||
const bool anyNonClosable = frame() ? frame()->anyNonClosable()
|
||||
: (floatingWindow() ? floatingWindow()->anyNonClosable()
|
||||
: false);
|
||||
|
||||
setCloseButtonEnabled(!anyNonClosable);
|
||||
}
|
||||
|
||||
void TitleBar::toggleMaximized()
|
||||
{
|
||||
if (!m_floatingWindow)
|
||||
@@ -116,15 +128,34 @@ bool TitleBar::isOverlayed() const
|
||||
return m_frame && m_frame->isOverlayed();
|
||||
}
|
||||
|
||||
void TitleBar::setCloseButtonEnabled(bool enabled)
|
||||
{
|
||||
if (enabled != m_closeButtonEnabled) {
|
||||
m_closeButtonEnabled = enabled;
|
||||
Q_EMIT closeButtonEnabledChanged(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void TitleBar::setFloatButtonVisible(bool visible)
|
||||
{
|
||||
if (visible != m_floatButtonVisible) {
|
||||
m_floatButtonVisible = visible;
|
||||
Q_EMIT floatButtonVisibleChanged(visible);
|
||||
}
|
||||
}
|
||||
|
||||
void TitleBar::setFloatButtonToolTip(const QString &tip)
|
||||
{
|
||||
if (tip != m_floatButtonToolTip) {
|
||||
m_floatButtonToolTip = tip;
|
||||
Q_EMIT floatButtonToolTipChanged(tip);
|
||||
}
|
||||
}
|
||||
|
||||
void TitleBar::setTitle(const QString &title)
|
||||
{
|
||||
if (title != m_title) {
|
||||
m_title = title;
|
||||
qCDebug(::title) << Q_FUNC_INFO << "\n title=" << title
|
||||
<< "\n this=" << this
|
||||
<< "\n parentWidget=" << parentWidget()
|
||||
<< "\n isVisible=" << isVisible()
|
||||
<< "\nwindow=" << window();
|
||||
update();
|
||||
Q_EMIT titleChanged();
|
||||
}
|
||||
@@ -140,7 +171,7 @@ std::unique_ptr<WindowBeingDragged> TitleBar::makeWindow()
|
||||
{
|
||||
if (!isVisible() && window()->isVisible()) {
|
||||
qWarning() << "TitleBar::makeWindow shouldn't be called on invisible title bar"
|
||||
<< this << window()->isVisible() << parentWidget();
|
||||
<< this << window()->isVisible();
|
||||
|
||||
if (m_floatingWindow) {
|
||||
qWarning() << "Has floating window with titlebar=" << m_floatingWindow->titleBar()
|
||||
@@ -198,6 +229,12 @@ bool TitleBar::supportsFloatingButton() const
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DockWidgetBase *dw = singleDockWidget()) {
|
||||
// Don't show the dock/undock button if the window is not dockable
|
||||
if (dw->options() & DockWidgetBase::Option_NotDockable)
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have a floating window with nested dock widgets we can't re-attach, because we don't
|
||||
// know where to
|
||||
return !m_floatingWindow || m_floatingWindow->hasSingleFrame();
|
||||
@@ -361,3 +398,24 @@ void TitleBar::onAutoHideClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TitleBar::closeButtonEnabled() const
|
||||
{
|
||||
return m_closeButtonEnabled;
|
||||
}
|
||||
|
||||
bool TitleBar::floatButtonVisible() const
|
||||
{
|
||||
return m_floatButtonVisible;
|
||||
}
|
||||
|
||||
QString TitleBar::floatButtonToolTip() const
|
||||
{
|
||||
return m_floatButtonToolTip;
|
||||
}
|
||||
|
||||
void TitleBar::updateFloatButton()
|
||||
{
|
||||
setFloatButtonToolTip(floatingWindow() ? tr("Dock window") : tr("Undock window"));
|
||||
setFloatButtonVisible(supportsFloatingButton());
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
#ifndef KD_TITLEBAR_P_H
|
||||
#define KD_TITLEBAR_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
#include "kddockwidgets/DockWidgetBase.h"
|
||||
#include "Draggable_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QIcon>
|
||||
@@ -27,7 +27,7 @@ class QHBoxLayout;
|
||||
class QLabel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class TestCommon;
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
@@ -41,6 +41,9 @@ class DOCKS_EXPORT TitleBar : public QWidgetAdapter
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
|
||||
Q_PROPERTY(bool hasIcon READ hasIcon NOTIFY iconChanged)
|
||||
Q_PROPERTY(bool closeButtonEnabled READ closeButtonEnabled WRITE setCloseButtonEnabled NOTIFY closeButtonEnabledChanged)
|
||||
Q_PROPERTY(bool floatButtonVisible READ floatButtonVisible WRITE setFloatButtonVisible NOTIFY floatButtonVisibleChanged)
|
||||
Q_PROPERTY(QString floatButtonToolTip READ floatButtonToolTip NOTIFY floatButtonToolTipChanged)
|
||||
public:
|
||||
typedef QVector<TitleBar *> List;
|
||||
|
||||
@@ -87,20 +90,24 @@ public:
|
||||
QIcon icon() const;
|
||||
|
||||
///@brief toggle floating
|
||||
bool onDoubleClicked();
|
||||
Q_INVOKABLE bool onDoubleClicked();
|
||||
|
||||
///@brief getter for m_frame
|
||||
const Frame *frame() const { return m_frame; }
|
||||
Frame *frame() const { return m_frame; }
|
||||
|
||||
///@brief getter for m_floatingWindow
|
||||
const FloatingWindow *floatingWindow() const { return m_floatingWindow; }
|
||||
FloatingWindow *floatingWindow() const { return m_floatingWindow; }
|
||||
|
||||
virtual void updateCloseButton() {}
|
||||
/// @brief updates the close button enabled state
|
||||
void updateCloseButton();
|
||||
|
||||
Q_SIGNALS:
|
||||
void titleChanged();
|
||||
void iconChanged();
|
||||
void isFocusedChanged();
|
||||
void closeButtonEnabledChanged(bool);
|
||||
void floatButtonVisibleChanged(bool);
|
||||
void floatButtonToolTipChanged(const QString &);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -111,25 +118,31 @@ protected:
|
||||
Q_INVOKABLE void toggleMaximized();
|
||||
Q_INVOKABLE void onAutoHideClicked();
|
||||
|
||||
virtual void updateFloatButton() {}
|
||||
bool closeButtonEnabled() const;
|
||||
bool floatButtonVisible() const;
|
||||
QString floatButtonToolTip() const;
|
||||
|
||||
virtual void updateMaximizeButton() {}
|
||||
|
||||
virtual void updateMinimizeButton() {}
|
||||
virtual void updateAutoHideButton() {}
|
||||
|
||||
#ifdef DOCKS_DEVELOPER_MODE
|
||||
// The following are needed for the unit-tests
|
||||
virtual bool isCloseButtonVisible() const { return true; }
|
||||
virtual bool isCloseButtonEnabled() const { return true; }
|
||||
virtual bool isFloatButtonVisible() const { return true; }
|
||||
virtual bool isFloatButtonEnabled() const { return true; }
|
||||
virtual bool isCloseButtonVisible() const = 0;
|
||||
virtual bool isCloseButtonEnabled() const = 0;
|
||||
virtual bool isFloatButtonVisible() const = 0;
|
||||
virtual bool isFloatButtonEnabled() const = 0;
|
||||
#endif
|
||||
|
||||
void focusInEvent(QFocusEvent *event) override;
|
||||
|
||||
bool isOverlayed() const;
|
||||
|
||||
private:
|
||||
friend class TestDocks;
|
||||
friend class ::TestCommon;
|
||||
friend class ::TestDocks;
|
||||
void updateFloatButton();
|
||||
void setCloseButtonEnabled(bool);
|
||||
void setFloatButtonVisible(bool);
|
||||
void setFloatButtonToolTip(const QString &);
|
||||
|
||||
void init();
|
||||
|
||||
@@ -140,6 +153,9 @@ private:
|
||||
Frame *const m_frame;
|
||||
FloatingWindow *const m_floatingWindow;
|
||||
const bool m_supportsAutoHide;
|
||||
bool m_closeButtonEnabled = true;
|
||||
bool m_floatButtonVisible = true;
|
||||
QString m_floatButtonToolTip;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -13,28 +13,58 @@
|
||||
#define KD_UTILS_P_H
|
||||
|
||||
#include "Config.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
#include <QWidget>
|
||||
#include <QWindow>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
# include "private/quick/TitleBarQuick_p.h"
|
||||
|
||||
# include <QQuickItem>
|
||||
# include <QQuickWindow>
|
||||
# include <QQuickView>
|
||||
#else
|
||||
# include <QApplication>
|
||||
# include <QAbstractButton>
|
||||
# include <QLineEdit>
|
||||
#endif
|
||||
|
||||
#ifdef QT_X11EXTRAS_LIB
|
||||
# include <QtX11Extras/QX11Info>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QWidget;
|
||||
class QWindow;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
inline QQuickItem* mouseAreaForPos(QQuickItem *item, QPointF globalPos);
|
||||
#endif
|
||||
|
||||
inline bool isWayland()
|
||||
{
|
||||
return qApp->platformName() == QLatin1String("wayland");
|
||||
}
|
||||
|
||||
inline bool isOffscreen()
|
||||
{
|
||||
return qApp->platformName() == QLatin1String("offscreen");
|
||||
}
|
||||
|
||||
inline bool kddwUsesQtWidgets()
|
||||
{
|
||||
// Returns whether KDDW is built for QtWidgets or QtQuick
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool isLeftButtonPressed()
|
||||
{
|
||||
return qApp->mouseButtons() & Qt::LeftButton;
|
||||
@@ -69,6 +99,24 @@ inline bool usesNativeDraggingAndResizing()
|
||||
return usesNativeTitleBar() || usesAeroSnapWithCustomDecos();
|
||||
}
|
||||
|
||||
inline bool usesFallbackMouseGrabber()
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
// Will use QWidget::grabMouse()
|
||||
return false;
|
||||
#else
|
||||
// For QtQuick we use the global event filter as mouse delivery is flaky
|
||||
// For example, the same QQuickItem that receives the press isn't receiving the mouse moves
|
||||
// when the top-level window moves.
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void activateWindow(QWindow *window)
|
||||
{
|
||||
window->requestActivate();
|
||||
}
|
||||
|
||||
inline bool windowManagerHasTranslucency()
|
||||
{
|
||||
#ifdef QT_X11EXTRAS_LIB
|
||||
@@ -102,6 +150,84 @@ inline int screenNumberForWindow(const QWindow *window)
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline QMouseEvent *mouseEvent(QEvent *e)
|
||||
{
|
||||
switch (e->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::NonClientAreaMouseButtonPress:
|
||||
case QEvent::NonClientAreaMouseButtonRelease:
|
||||
case QEvent::NonClientAreaMouseMove:
|
||||
return static_cast<QMouseEvent *>(e);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline bool isNonClientMouseEvent(const QEvent *e)
|
||||
{
|
||||
switch (e->type()) {
|
||||
case QEvent::NonClientAreaMouseButtonPress:
|
||||
case QEvent::NonClientAreaMouseButtonRelease:
|
||||
case QEvent::NonClientAreaMouseMove:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool isWindow(const QWindow *w)
|
||||
{
|
||||
return w != nullptr;
|
||||
}
|
||||
|
||||
inline int startDragDistance()
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
return QApplication::startDragDistance();
|
||||
#else
|
||||
return 4;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief Returns the QWidget or QtQuickItem at the specified position
|
||||
/// Basically QApplication::widgetAt() but with support for QtQuick
|
||||
inline WidgetType* mouseReceiverAt(QPoint globalPos)
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
return qApp->widgetAt(globalPos);
|
||||
#else
|
||||
auto window = qobject_cast<QQuickWindow*>(qApp->topLevelAt(globalPos));
|
||||
if (!window)
|
||||
return nullptr;
|
||||
|
||||
return mouseAreaForPos(window->contentItem(), globalPos);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Not the entire TitleBar is draggable. For example, the close button won't allow to start a drag from there.
|
||||
/// Returns true if we're over such controls where we shouldn't drag.
|
||||
inline bool inDisallowDragWidget(QPoint globalPos)
|
||||
{
|
||||
WidgetType *widget = mouseReceiverAt(globalPos);
|
||||
if (!widget)
|
||||
return false;
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
// User might have a line edit on the toolbar. TODO: Not so elegant fix, we should make the user's tabbar implement some virtual method...
|
||||
return qobject_cast<QAbstractButton*>(widget) ||
|
||||
qobject_cast<QLineEdit*>(widget);
|
||||
#else
|
||||
return widget->objectName() != QLatin1String("draggableMouseArea");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
inline int screenNumberForWidget(const QWidget *widget)
|
||||
{
|
||||
@@ -113,6 +239,21 @@ inline QSize screenSizeForWidget(const QWidget *widget)
|
||||
return screenSizeForWindow(widget->window()->windowHandle());
|
||||
}
|
||||
|
||||
inline QPoint mapToGlobal(QWidget *w, QPoint p)
|
||||
{
|
||||
return w->mapToGlobal(p);
|
||||
}
|
||||
|
||||
inline void activateWindow(QWidget *widget)
|
||||
{
|
||||
widget->activateWindow();
|
||||
}
|
||||
|
||||
inline bool isWindow(const QWidget *w)
|
||||
{
|
||||
return w && w->isWindow();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline int screenNumberForWidget(const QQuickItem *w)
|
||||
@@ -125,6 +266,34 @@ inline QSize screenSizeForWidget(const QQuickItem *w)
|
||||
return screenSizeForWindow(w->window());
|
||||
}
|
||||
|
||||
inline QPoint mapToGlobal(QQuickItem *item, QPoint p)
|
||||
{
|
||||
return item->mapToGlobal(p).toPoint();
|
||||
}
|
||||
|
||||
inline QQuickItem* mouseAreaForPos(QQuickItem *item, QPointF globalPos)
|
||||
{
|
||||
QRectF rect = item->boundingRect();
|
||||
rect.moveTopLeft(item->mapToGlobal(QPointF(0, 0)));
|
||||
|
||||
// Assumes children are inside its parent. That's fine for KDDW's purposes.
|
||||
if (!rect.contains(globalPos)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const QList<QQuickItem*> children = item->childItems();
|
||||
|
||||
for (auto it = children.rbegin(), end = children.rend(); it != end; ++it) {
|
||||
if (QQuickItem *receiver = mouseAreaForPos(*it, globalPos))
|
||||
return receiver;
|
||||
}
|
||||
|
||||
if (QLatin1String(item->metaObject()->className()) == QLatin1String("QQuickMouseArea"))
|
||||
return item;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
@@ -15,16 +15,14 @@
|
||||
#include "DragController_p.h"
|
||||
#include "Config.h"
|
||||
#include "Qt5Qt6Compat_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QWidget>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
#include <QAbstractButton>
|
||||
#include <QLineEdit>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
# include <QtGui/private/qhighdpiscaling_p.h>
|
||||
@@ -42,7 +40,7 @@ int widgetResizeHandlerMargin = 4; //4 pixel
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
bool WidgetResizeHandler::s_disableAllHandlers = false;
|
||||
WidgetResizeHandler::WidgetResizeHandler(QWidget *target)
|
||||
WidgetResizeHandler::WidgetResizeHandler(QWidgetOrQuick *target)
|
||||
: QObject(target)
|
||||
{
|
||||
setTarget(target);
|
||||
@@ -54,10 +52,11 @@ WidgetResizeHandler::~WidgetResizeHandler()
|
||||
|
||||
bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *e)
|
||||
{
|
||||
if (s_disableAllHandlers || o != mTarget)
|
||||
if (s_disableAllHandlers || o != mTarget) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto widget = qobject_cast<QWidget*>(o);
|
||||
auto widget = qobject_cast<QWidgetOrQuick*>(o);
|
||||
if (!widget || !widget->isTopLevel()) {
|
||||
return false;
|
||||
}
|
||||
@@ -68,7 +67,7 @@ bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *e)
|
||||
break;
|
||||
auto mouseEvent = static_cast<QMouseEvent *>(e);
|
||||
auto cursorPos = cursorPosition(Qt5Qt6Compat::eventGlobalPos(mouseEvent));
|
||||
if (cursorPos == CursorPosition::Undefined)
|
||||
if (cursorPos == CursorPosition_Undefined)
|
||||
return false;
|
||||
|
||||
const QRect widgetRect = mTarget->rect().marginsAdded(QMargins(widgetResizeHandlerMargin, widgetResizeHandlerMargin, widgetResizeHandlerMargin, widgetResizeHandlerMargin));
|
||||
@@ -129,9 +128,9 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
const int minWidth = mTarget->minimumWidth();
|
||||
const int maxWidth = mTarget->maximumWidth();
|
||||
switch (mCursorPos) {
|
||||
case CursorPosition::TopLeft:
|
||||
case CursorPosition::Left:
|
||||
case CursorPosition::BottomLeft: {
|
||||
case CursorPosition_TopLeft:
|
||||
case CursorPosition_Left:
|
||||
case CursorPosition_BottomLeft: {
|
||||
deltaWidth = oldGeometry.left() - globalPos.x();
|
||||
newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
|
||||
deltaWidth = newWidth - mTarget->width();
|
||||
@@ -142,9 +141,9 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
break;
|
||||
}
|
||||
|
||||
case CursorPosition::TopRight:
|
||||
case CursorPosition::Right:
|
||||
case CursorPosition::BottomRight: {
|
||||
case CursorPosition_TopRight:
|
||||
case CursorPosition_Right:
|
||||
case CursorPosition_BottomRight: {
|
||||
deltaWidth = globalPos.x() - newGeometry.right();
|
||||
newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
|
||||
deltaWidth = newWidth - mTarget->width();
|
||||
@@ -164,9 +163,9 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
int deltaHeight = 0;
|
||||
int newHeight = 0;
|
||||
switch (mCursorPos) {
|
||||
case CursorPosition::TopLeft:
|
||||
case CursorPosition::Top:
|
||||
case CursorPosition::TopRight: {
|
||||
case CursorPosition_TopLeft:
|
||||
case CursorPosition_Top:
|
||||
case CursorPosition_TopRight: {
|
||||
deltaHeight = oldGeometry.top() - globalPos.y();
|
||||
newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
|
||||
deltaHeight = newHeight - mTarget->height();
|
||||
@@ -177,9 +176,9 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
break;
|
||||
}
|
||||
|
||||
case CursorPosition::BottomLeft:
|
||||
case CursorPosition::Bottom:
|
||||
case CursorPosition::BottomRight: {
|
||||
case CursorPosition_BottomLeft:
|
||||
case CursorPosition_Bottom:
|
||||
case CursorPosition_BottomRight: {
|
||||
deltaHeight = globalPos.y() - newGeometry.bottom();
|
||||
newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
|
||||
deltaHeight = newHeight - mTarget->height();
|
||||
@@ -201,7 +200,7 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
/// Handler to enable Aero-snap
|
||||
bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByteArray &eventType, void *message, long *result)
|
||||
bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByteArray &eventType, void *message, Qt5Qt6Compat::qintptr *result)
|
||||
{
|
||||
if (eventType != "windows_generic_MSG")
|
||||
return false;
|
||||
@@ -250,18 +249,15 @@ bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByt
|
||||
*result = HTRIGHT;
|
||||
} else {
|
||||
const QPoint globalPosQt = QHighDpi::fromNativePixels(QPoint(xPos, yPos), w->windowHandle());
|
||||
|
||||
const QRect htCaptionRect = w->dragRect(); // The rect on which we allow for Windows to do Ba native drag
|
||||
const QRect htCaptionRect = w->dragRect(); // The rect on which we allow for Windows to do a native drag
|
||||
if (globalPosQt.y() >= htCaptionRect.top() && globalPosQt.y() <= htCaptionRect.bottom() && globalPosQt.x() >= htCaptionRect.left() && globalPosQt.x() <= htCaptionRect.right()) {
|
||||
QWidget *hoveredWidget = qApp->widgetAt(globalPosQt);
|
||||
if (!qobject_cast<QAbstractButton*>(hoveredWidget) &&
|
||||
!qobject_cast<QLineEdit*>(hoveredWidget)) { // User might have a line edit on the toolbar. TODO: Not so elegant fix, we should make the user's tabbar implement some virtual method...
|
||||
// User clicked on the title bar, let's allow it, so we get Aero-Snap.
|
||||
*result = HTCAPTION;
|
||||
if (!KDDockWidgets::inDisallowDragWidget(globalPosQt)) { // Just makes sure the mouse isn't over the close button, we don't allow drag in that case.
|
||||
*result = HTCAPTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w->setLastHitTest(*result);
|
||||
return *result != 0;
|
||||
} else if (msg->message == WM_NCLBUTTONDBLCLK) {
|
||||
if ((Config::self().flags() & Config::Flag_DoubleClickMaximizes)) {
|
||||
@@ -287,7 +283,7 @@ bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByt
|
||||
// and patch the size
|
||||
|
||||
// According to microsoft docs it only works for the primary screen, but extrapolates for the others
|
||||
QScreen *screen = QApplication::primaryScreen();
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
if (!screen || w->windowHandle()->screen() != screen) {
|
||||
return false;
|
||||
}
|
||||
@@ -317,7 +313,7 @@ bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByt
|
||||
|
||||
#endif
|
||||
|
||||
void WidgetResizeHandler::setTarget(QWidget *w)
|
||||
void WidgetResizeHandler::setTarget(QWidgetOrQuick *w)
|
||||
{
|
||||
if (w) {
|
||||
mTarget = w;
|
||||
@@ -330,33 +326,37 @@ void WidgetResizeHandler::setTarget(QWidget *w)
|
||||
|
||||
void WidgetResizeHandler::updateCursor(CursorPosition m)
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
//Need for updating cursor when we change child widget
|
||||
const QObjectList children = mTarget->children();
|
||||
for (int i = 0, total = children.size(); i < total; ++i) {
|
||||
if (auto child = qobject_cast<QWidget*>(children.at(i))) {
|
||||
if (auto child = qobject_cast<WidgetType*>(children.at(i))) {
|
||||
|
||||
if (!child->testAttribute(Qt::WA_SetCursor)) {
|
||||
child->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (m) {
|
||||
case CursorPosition::TopLeft:
|
||||
case CursorPosition::BottomRight:
|
||||
case CursorPosition_TopLeft:
|
||||
case CursorPosition_BottomRight:
|
||||
mTarget->setCursor(Qt::SizeFDiagCursor);
|
||||
break;
|
||||
case CursorPosition::BottomLeft:
|
||||
case CursorPosition::TopRight:
|
||||
case CursorPosition_BottomLeft:
|
||||
case CursorPosition_TopRight:
|
||||
mTarget->setCursor(Qt::SizeBDiagCursor);
|
||||
break;
|
||||
case CursorPosition::Top:
|
||||
case CursorPosition::Bottom:
|
||||
case CursorPosition_Top:
|
||||
case CursorPosition_Bottom:
|
||||
mTarget->setCursor(Qt::SizeVerCursor);
|
||||
break;
|
||||
case CursorPosition::Left:
|
||||
case CursorPosition::Right:
|
||||
case CursorPosition_Left:
|
||||
case CursorPosition_Right:
|
||||
mTarget->setCursor(Qt::SizeHorCursor);
|
||||
break;
|
||||
case CursorPosition::Undefined:
|
||||
case CursorPosition_Undefined:
|
||||
mTarget->setCursor(Qt::ArrowCursor);
|
||||
break;
|
||||
}
|
||||
@@ -365,27 +365,25 @@ void WidgetResizeHandler::updateCursor(CursorPosition m)
|
||||
WidgetResizeHandler::CursorPosition WidgetResizeHandler::cursorPosition(QPoint globalPos) const
|
||||
{
|
||||
if (!mTarget)
|
||||
return CursorPosition::Undefined;
|
||||
return CursorPosition_Undefined;
|
||||
|
||||
QPoint pos = mTarget->mapFromGlobal(globalPos);
|
||||
|
||||
if (pos.y() <= widgetResizeHandlerMargin && pos.x() <= widgetResizeHandlerMargin) {
|
||||
return CursorPosition::TopLeft;
|
||||
} else if (pos.y() >= mTarget->height() - widgetResizeHandlerMargin && pos.x() >= mTarget->width() - widgetResizeHandlerMargin) {
|
||||
return CursorPosition::BottomRight;
|
||||
} else if (pos.y() >= mTarget->height() - widgetResizeHandlerMargin && pos.x() <= widgetResizeHandlerMargin) {
|
||||
return CursorPosition::BottomLeft;
|
||||
} else if (pos.y() <= widgetResizeHandlerMargin && pos.x() >= mTarget->width() - widgetResizeHandlerMargin) {
|
||||
return CursorPosition::TopRight;
|
||||
} else if (pos.y() <= widgetResizeHandlerMargin) {
|
||||
return CursorPosition::Top;
|
||||
} else if (pos.y() >= mTarget->height() - widgetResizeHandlerMargin) {
|
||||
return CursorPosition::Bottom;
|
||||
} else if (pos.x() <= widgetResizeHandlerMargin) {
|
||||
return CursorPosition::Left;
|
||||
} else if ( pos.x() >= mTarget->width() - widgetResizeHandlerMargin) {
|
||||
return CursorPosition::Right;
|
||||
} else {
|
||||
return CursorPosition::Undefined;
|
||||
}
|
||||
int result = CursorPosition_Undefined;
|
||||
|
||||
const int x = pos.x();
|
||||
const int y = pos.y();
|
||||
const int margin = widgetResizeHandlerMargin;
|
||||
|
||||
if (x <= margin)
|
||||
result |= CursorPosition_Left;
|
||||
else if (x >= mTarget->width() - margin)
|
||||
result |= CursorPosition_Right;
|
||||
|
||||
if (y <= margin)
|
||||
result |= CursorPosition_Top;
|
||||
else if (y >= mTarget->height() - margin)
|
||||
result |= CursorPosition_Bottom;
|
||||
|
||||
return static_cast<CursorPosition>(result);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
#ifndef KD_WIDGET_RESIZE_HANDLER_P_H
|
||||
#define KD_WIDGET_RESIZE_HANDLER_P_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "Qt5Qt6Compat_p.h"
|
||||
|
||||
#include <QPoint>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -28,35 +30,37 @@ class WidgetResizeHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WidgetResizeHandler(QWidget *target = nullptr);
|
||||
|
||||
enum CursorPosition {
|
||||
CursorPosition_Undefined = 0,
|
||||
CursorPosition_Left = 1,
|
||||
CursorPosition_Right = 2,
|
||||
CursorPosition_Top = 4,
|
||||
CursorPosition_Bottom = 8,
|
||||
CursorPosition_TopLeft = CursorPosition_Top | CursorPosition_Left,
|
||||
CursorPosition_TopRight = CursorPosition_Top | CursorPosition_Right,
|
||||
CursorPosition_BottomRight = CursorPosition_Bottom | CursorPosition_Right,
|
||||
CursorPosition_BottomLeft = CursorPosition_Bottom | CursorPosition_Left
|
||||
};
|
||||
|
||||
explicit WidgetResizeHandler(QWidgetOrQuick *target = nullptr);
|
||||
~WidgetResizeHandler() override;
|
||||
|
||||
void setTarget(QWidget *w);
|
||||
void setTarget(QWidgetOrQuick *w);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static bool handleWindowsNativeEvent(FloatingWindow *w, const QByteArray &eventType, void *message, long *result);
|
||||
static bool handleWindowsNativeEvent(FloatingWindow *w, const QByteArray &eventType, void *message, Qt5Qt6Compat::qintptr *result);
|
||||
#endif
|
||||
static bool s_disableAllHandlers;
|
||||
protected:
|
||||
bool eventFilter(QObject *o, QEvent *e) override;
|
||||
|
||||
private:
|
||||
enum class CursorPosition {
|
||||
Left,
|
||||
Right,
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomRight,
|
||||
BottomLeft,
|
||||
Top,
|
||||
Bottom,
|
||||
Undefined
|
||||
};
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void updateCursor(CursorPosition m);
|
||||
CursorPosition cursorPosition(QPoint) const;
|
||||
QWidget *mTarget = nullptr;
|
||||
CursorPosition mCursorPos = CursorPosition::Undefined;
|
||||
QWidgetOrQuick *mTarget = nullptr;
|
||||
CursorPosition mCursorPos = CursorPosition_Undefined;
|
||||
QPoint mNewPosition;
|
||||
bool mResizeWidget = false;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,15 @@
|
||||
#include "Logging_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Frame_p.h"
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
# include "widgets/TabBarWidget_p.h"
|
||||
# include "widgets/TabWidgetWidget_p.h"
|
||||
#endif
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
@@ -48,23 +57,36 @@ static Draggable* bestDraggable(Draggable *draggable)
|
||||
|
||||
WindowBeingDragged::WindowBeingDragged(FloatingWindow *fw, Draggable *draggable)
|
||||
: m_floatingWindow(fw)
|
||||
, m_draggable(bestDraggable(draggable)->asWidget())
|
||||
, m_affinities(fw->affinities())
|
||||
, m_draggable(bestDraggable(draggable))
|
||||
, m_draggableWidget(m_draggable ? m_draggable->asWidget() : nullptr)
|
||||
{
|
||||
init();
|
||||
|
||||
// Set opacity while dragging, if needed
|
||||
const qreal opacity = Config::self().draggedWindowOpacity();
|
||||
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
|
||||
fw->setWindowOpacity(opacity);
|
||||
if (!isWayland()) { // Wayland doesn't support setting opacity
|
||||
// Set opacity while dragging, if needed
|
||||
const qreal opacity = Config::self().draggedWindowOpacity();
|
||||
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
|
||||
fw->setWindowOpacity(opacity);
|
||||
}
|
||||
}
|
||||
#if DOCKS_DEVELOPER_MODE
|
||||
|
||||
WindowBeingDragged::WindowBeingDragged(Draggable *draggable)
|
||||
: m_draggable(draggable)
|
||||
, m_draggableWidget(m_draggable->asWidget())
|
||||
{
|
||||
if (!isWayland()) {
|
||||
qWarning() << Q_FUNC_INFO << "Wrong ctor called."; // Doesn't happen
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DOCKS_DEVELOPER_MODE
|
||||
|
||||
// Just used by tests
|
||||
WindowBeingDragged::WindowBeingDragged(FloatingWindow *fw)
|
||||
: m_floatingWindow(fw)
|
||||
, m_draggable(nullptr)
|
||||
, m_affinities(fw->affinities())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -74,10 +96,12 @@ WindowBeingDragged::~WindowBeingDragged()
|
||||
{
|
||||
grabMouse(false);
|
||||
|
||||
// Restore opacity to fully opaque if needed
|
||||
const qreal opacity = Config::self().draggedWindowOpacity();
|
||||
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
|
||||
m_floatingWindow->setWindowOpacity(1);
|
||||
if (!isWayland()) { // Wayland doesn't support setting opacity
|
||||
// Restore opacity to fully opaque if needed
|
||||
const qreal opacity = Config::self().draggedWindowOpacity();
|
||||
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
|
||||
m_floatingWindow->setWindowOpacity(1);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowBeingDragged::init()
|
||||
@@ -89,19 +113,20 @@ void WindowBeingDragged::init()
|
||||
|
||||
void WindowBeingDragged::grabMouse(bool grab)
|
||||
{
|
||||
if (!m_draggable)
|
||||
if (!m_draggableWidget)
|
||||
return;
|
||||
|
||||
qCDebug(hovering) << "WindowBeingDragged: grab " << m_floatingWindow << grab << m_draggable;
|
||||
qCDebug(hovering) << "WindowBeingDragged: grab " << m_floatingWindow << grab << m_draggableWidget;
|
||||
if (grab)
|
||||
DragController::instance()->grabMouseFor(m_draggable);
|
||||
DragController::instance()->grabMouseFor(m_draggableWidget);
|
||||
else
|
||||
DragController::instance()->releaseMouse(m_draggable);
|
||||
DragController::instance()->releaseMouse(m_draggableWidget);
|
||||
}
|
||||
|
||||
QStringList WindowBeingDragged::affinities() const
|
||||
{
|
||||
return m_affinities;
|
||||
return m_floatingWindow ? m_floatingWindow->affinities()
|
||||
: QStringList();
|
||||
}
|
||||
|
||||
QSize WindowBeingDragged::size() const
|
||||
@@ -131,3 +156,153 @@ QSize WindowBeingDragged::maxSize() const
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool WindowBeingDragged::contains(DropArea *dropArea) const
|
||||
{
|
||||
if (!dropArea)
|
||||
return false;
|
||||
|
||||
if (m_floatingWindow)
|
||||
return m_floatingWindow->dropArea() == dropArea;
|
||||
|
||||
if (auto fw = qobject_cast<FloatingWindow*>(m_draggableWidget->window())) {
|
||||
// We're not dragging via the floating window itself, but via the tab bar. Still might represent floating window though.
|
||||
return fw->dropArea() == dropArea && fw->hasSingleFrame();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector<DockWidgetBase *> WindowBeingDragged::dockWidgets() const
|
||||
{
|
||||
if (m_floatingWindow)
|
||||
return m_floatingWindow->dockWidgets();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Draggable *WindowBeingDragged::draggable() const
|
||||
{
|
||||
return m_draggable;
|
||||
}
|
||||
|
||||
WindowBeingDraggedWayland::WindowBeingDraggedWayland(Draggable *draggable)
|
||||
: WindowBeingDragged(draggable)
|
||||
{
|
||||
if (!isWayland()) {
|
||||
// Doesn't happen
|
||||
qWarning() << Q_FUNC_INFO << "This CTOR is only called on Wayland";
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto tb = qobject_cast<TitleBar*>(draggable->asWidget())) {
|
||||
if (auto fw = tb->floatingWindow()) {
|
||||
// case #1: we're dragging the whole floating window by its titlebar
|
||||
m_floatingWindow = fw;
|
||||
} else if (Frame *frame = tb->frame()) {
|
||||
m_frame = frame;
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO <<"Shouldn't happen. TitleBar of what ?";
|
||||
}
|
||||
} else if (auto fw = qobject_cast<FloatingWindow*>(draggable->asWidget())) {
|
||||
// case #2: the floating window itself is the draggable, happens on platforms that support
|
||||
// native dragging. Not the case for Wayland. But adding this case for completeness.
|
||||
m_floatingWindow = fw;
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
} else if (auto tbw = qobject_cast<TabBarWidget*>(draggable->asWidget())) {
|
||||
m_dockWidget = tbw->currentDockWidget();
|
||||
} else if (auto tw = qobject_cast<TabWidgetWidget*>(draggable->asWidget())) {
|
||||
m_frame = tw->frame();
|
||||
#endif
|
||||
} else {
|
||||
qWarning() << "Unknown draggable" << draggable->asWidget()
|
||||
<< "please fix";
|
||||
}
|
||||
}
|
||||
|
||||
WindowBeingDraggedWayland::~WindowBeingDraggedWayland()
|
||||
{
|
||||
}
|
||||
|
||||
QPixmap WindowBeingDraggedWayland::pixmap() const
|
||||
{
|
||||
QPixmap pixmap(size());
|
||||
QPainter p(&pixmap);
|
||||
p.setOpacity(0.7);
|
||||
|
||||
if (m_floatingWindow) {
|
||||
m_floatingWindow->render(&p);
|
||||
} else if (m_frame) {
|
||||
m_frame->render(&p);
|
||||
} else if (m_dockWidget) {
|
||||
m_dockWidget->render(&p);
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QStringList WindowBeingDraggedWayland::affinities() const
|
||||
{
|
||||
if (m_floatingWindow)
|
||||
return WindowBeingDragged::affinities();
|
||||
else if (m_frame)
|
||||
return m_frame->affinities();
|
||||
else if (m_dockWidget)
|
||||
return { m_dockWidget->affinities() };
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QVector<DockWidgetBase *> WindowBeingDraggedWayland::dockWidgets() const
|
||||
{
|
||||
if (m_floatingWindow)
|
||||
return WindowBeingDragged::dockWidgets();
|
||||
else if (m_frame)
|
||||
return m_frame->dockWidgets();
|
||||
else if (m_dockWidget)
|
||||
return { m_dockWidget };
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QSize WindowBeingDraggedWayland::size() const
|
||||
{
|
||||
if (m_floatingWindow)
|
||||
return WindowBeingDragged::size();
|
||||
else if (m_frame)
|
||||
return m_frame->QWidgetAdapter::size();
|
||||
else if (m_dockWidget)
|
||||
return m_dockWidget->size();
|
||||
|
||||
qWarning() << Q_FUNC_INFO << "Unknown size, shouldn't happen";
|
||||
return QSize();
|
||||
}
|
||||
|
||||
QSize WindowBeingDraggedWayland::minSize() const
|
||||
{
|
||||
if (m_floatingWindow) {
|
||||
return WindowBeingDragged::minSize();
|
||||
} else if (m_frame) {
|
||||
return m_frame->minSize();
|
||||
} else if (m_dockWidget) {
|
||||
return Layouting::Widget::widgetMinSize(m_dockWidget.data());
|
||||
}
|
||||
|
||||
qWarning() << Q_FUNC_INFO << "Unknown minSize, shouldn't happen";
|
||||
return {};
|
||||
}
|
||||
|
||||
QSize WindowBeingDraggedWayland::maxSize() const
|
||||
{
|
||||
if (m_floatingWindow) {
|
||||
return WindowBeingDragged::maxSize();
|
||||
} else if (m_frame) {
|
||||
return m_frame->maxSizeHint();
|
||||
} else if (m_dockWidget) {
|
||||
return Layouting::Widget::widgetMaxSize(m_dockWidget.data());
|
||||
}
|
||||
|
||||
qWarning() << Q_FUNC_INFO << "Unknown maxSize, shouldn't happen";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -17,21 +17,27 @@
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPixmap;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class FloatingWindow;
|
||||
class Draggable;
|
||||
class DropArea;
|
||||
|
||||
struct DOCKS_EXPORT_FOR_UNIT_TESTS WindowBeingDragged
|
||||
{
|
||||
public:
|
||||
explicit WindowBeingDragged(FloatingWindow *fw, Draggable *draggable);
|
||||
#if DOCKS_DEVELOPER_MODE
|
||||
|
||||
#ifdef DOCKS_DEVELOPER_MODE
|
||||
// For tests.
|
||||
explicit WindowBeingDragged(FloatingWindow *fw);
|
||||
#endif
|
||||
|
||||
~WindowBeingDragged();
|
||||
virtual ~WindowBeingDragged();
|
||||
void init();
|
||||
|
||||
FloatingWindow *floatingWindow() const { return m_floatingWindow; }
|
||||
@@ -39,24 +45,58 @@ public:
|
||||
///@brief grabs or releases the mouse
|
||||
void grabMouse(bool grab);
|
||||
|
||||
/// @brief returns whether this window being dragged contains the specified drop area
|
||||
/// useful since we don't want to drop onto outselves.
|
||||
bool contains(DropArea *) const;
|
||||
|
||||
///@brief returns the affinities of the window being dragged
|
||||
QStringList affinities() const;
|
||||
virtual QStringList affinities() const;
|
||||
|
||||
///@brief size of the window being dragged contents
|
||||
QSize size() const;
|
||||
virtual QSize size() const;
|
||||
|
||||
/// @brief returns the min-size of the window being dragged contents
|
||||
QSize minSize() const;
|
||||
virtual QSize minSize() const;
|
||||
|
||||
/// @brief returns the max-size of the window being dragged contents
|
||||
QSize maxSize() const;
|
||||
virtual QSize maxSize() const;
|
||||
|
||||
private:
|
||||
/// @brief Returns a pixmap representing this Window. For purposes of QDrag. Wayland only.
|
||||
virtual QPixmap pixmap() const { return {}; }
|
||||
|
||||
/// @brief Returns the list of dock widgets being dragged
|
||||
virtual QVector<DockWidgetBase*> dockWidgets() const;
|
||||
|
||||
/// @brief Returns the draggable
|
||||
Draggable *draggable() const;
|
||||
protected:
|
||||
explicit WindowBeingDragged(Draggable *);
|
||||
Q_DISABLE_COPY(WindowBeingDragged)
|
||||
QPointer<FloatingWindow> m_floatingWindow;
|
||||
QPointer<QWidgetOrQuick> m_draggable;
|
||||
const QStringList m_affinities;
|
||||
Draggable *const m_draggable;
|
||||
QPointer<QWidgetOrQuick> m_draggableWidget; // Just to have a QPointer on it
|
||||
};
|
||||
|
||||
struct WindowBeingDraggedWayland : public WindowBeingDragged
|
||||
{
|
||||
public:
|
||||
explicit WindowBeingDraggedWayland(Draggable *draggable);
|
||||
~WindowBeingDraggedWayland() override;
|
||||
|
||||
QSize size() const override;
|
||||
QSize minSize() const override;
|
||||
QSize maxSize() const override;
|
||||
QPixmap pixmap() const override;
|
||||
QStringList affinities() const override;
|
||||
QVector<DockWidgetBase*> dockWidgets() const override;
|
||||
|
||||
// These two are set for Wayland only, where we can't make the floating window immediately (no way to position it)
|
||||
// So we're dragging either a frame with multiple dock widgets or a single tab, keep them here.
|
||||
// It's important to know what we're dragging, so drop rubber band respect min/max sizes.
|
||||
QPointer<Frame> m_frame;
|
||||
QPointer<DockWidgetBase> m_dockWidget;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QState>
|
||||
#include <QStateMachine>
|
||||
|
||||
#define RUBBERBAND_LENGTH 11
|
||||
#define RUBBERBAND_SPACING 2
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "DockRegistry_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "ClassicIndicatorsWindow_p.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
@@ -40,9 +41,9 @@ ClassicIndicators::~ClassicIndicators()
|
||||
delete m_indicatorWindow;
|
||||
}
|
||||
|
||||
void ClassicIndicators::hover_impl(QPoint globalPos)
|
||||
DropIndicatorOverlayInterface::DropLocation ClassicIndicators::hover_impl(QPoint globalPos)
|
||||
{
|
||||
m_indicatorWindow->hover(globalPos);
|
||||
return m_indicatorWindow->hover(globalPos);
|
||||
}
|
||||
|
||||
QPoint ClassicIndicators::posForIndicator(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
@@ -101,8 +102,14 @@ void ClassicIndicators::updateIndicatorsVisibility(bool visible)
|
||||
|
||||
|
||||
// Only allow to dock to center if the affinities match
|
||||
auto tabbingAllowedFunc = Config::self().tabbingAllowedFunc();
|
||||
m_tabIndicatorVisible = m_innerIndicatorsVisible && windowBeingDragged &&
|
||||
DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities());
|
||||
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();
|
||||
@@ -139,7 +146,6 @@ KDDockWidgets::Location locationToMultisplitterLocation(ClassicIndicators::DropL
|
||||
|
||||
void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location)
|
||||
{
|
||||
qCDebug(overlay) << "ClassicIndicators::setCurrentDropLocation" << location;
|
||||
setCurrentDropLocation(location);
|
||||
|
||||
if (location == DropLocation_None) {
|
||||
@@ -191,7 +197,10 @@ void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location
|
||||
void ClassicIndicators::updateWindowPosition()
|
||||
{
|
||||
QRect rect = this->rect();
|
||||
QPoint pos = mapToGlobal(QPoint(0, 0));
|
||||
rect.moveTo(pos);
|
||||
if (KDDockWidgets::isWindow(m_indicatorWindow)) {
|
||||
// On all non-wayland platforms it's a top-level.
|
||||
QPoint pos = mapToGlobal(QPoint(0, 0));
|
||||
rect.moveTo(pos);
|
||||
}
|
||||
m_indicatorWindow->setGeometry(rect);
|
||||
}
|
||||
|
||||
@@ -101,8 +101,22 @@ QString Indicator::iconFileName(bool active) const
|
||||
: QStringLiteral(":/img/classic_indicators/opaque/%1.png").arg(name);
|
||||
}
|
||||
|
||||
static QWidgetAdapter* parentForIndicatorWindow(ClassicIndicators *classicIndicators_)
|
||||
{
|
||||
// On Wayland it can't be a top-level, as we have no way of positioning it
|
||||
|
||||
return isWayland() ? classicIndicators_
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
static Qt::WindowFlags flagsForIndicatorWindow()
|
||||
{
|
||||
return isWayland() ? Qt::Widget
|
||||
: (Qt::Tool | Qt::BypassWindowManagerHint);
|
||||
}
|
||||
|
||||
IndicatorWindow::IndicatorWindow(ClassicIndicators *classicIndicators_)
|
||||
: QWidget(nullptr, Qt::Tool | Qt::BypassWindowManagerHint)
|
||||
: 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))
|
||||
@@ -193,12 +207,20 @@ QPoint IndicatorWindow::posForIndicator(DropIndicatorOverlayInterface::DropLocat
|
||||
return indicator->mapToGlobal(indicator->rect().center());
|
||||
}
|
||||
|
||||
void IndicatorWindow::hover(QPoint globalPos)
|
||||
DropIndicatorOverlayInterface::DropLocation IndicatorWindow::hover(QPoint globalPos)
|
||||
{
|
||||
DropIndicatorOverlayInterface::DropLocation loc = DropIndicatorOverlayInterface::DropLocation_None;
|
||||
|
||||
for (Indicator *indicator : qAsConst(m_indicators)) {
|
||||
if (indicator->isVisible())
|
||||
indicator->setHovered(indicator->rect().contains(indicator->mapFromGlobal(globalPos)));
|
||||
if (indicator->isVisible()) {
|
||||
const bool hovered = indicator->rect().contains(indicator->mapFromGlobal(globalPos));
|
||||
indicator->setHovered(hovered);
|
||||
if (hovered)
|
||||
loc = indicator->m_dropLocation;
|
||||
}
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
void IndicatorWindow::updatePositions()
|
||||
@@ -246,17 +268,26 @@ IndicatorWindow::IndicatorWindow(KDDockWidgets::ClassicIndicators *classicIndica
|
||||
|
||||
rootContext()->setContextProperty(QStringLiteral("_window"), QVariant::fromValue<QObject*>(this));
|
||||
setSource(QUrl(QStringLiteral("qrc:/kddockwidgets/private/quick/qml/ClassicIndicatorsOverlay.qml")));
|
||||
|
||||
{
|
||||
// Small hack to avoid flickering when we drag over a window the first time
|
||||
// Not sure why a simply create() doesn't work instead
|
||||
// Not if offscreen though, as that QPA is flaky with window activation/focus
|
||||
if (!KDDockWidgets::isOffscreen()) {
|
||||
resize(QSize(1, 1));
|
||||
show();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IndicatorWindow::hover(QPoint pt)
|
||||
DropIndicatorOverlayInterface::DropLocation IndicatorWindow::hover(QPoint pt)
|
||||
{
|
||||
QQuickItem *item = indicatorForPos(pt);
|
||||
if (item) {
|
||||
const auto loc = DropIndicatorOverlayInterface::DropLocation(item->property("indicatorType").toInt());
|
||||
classicIndicators()->setDropLocation(loc);
|
||||
} else {
|
||||
classicIndicators()->setDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
|
||||
}
|
||||
const DropIndicatorOverlayInterface::DropLocation loc = item ? locationForIndicator(item)
|
||||
: DropIndicatorOverlayInterface::DropLocation_None;
|
||||
classicIndicators()->setDropLocation(loc);
|
||||
return loc;
|
||||
}
|
||||
|
||||
QQuickItem *IndicatorWindow::indicatorForPos(QPoint pt) const
|
||||
@@ -265,10 +296,13 @@ QQuickItem *IndicatorWindow::indicatorForPos(QPoint pt) const
|
||||
Q_ASSERT(indicators.size() == 9);
|
||||
|
||||
for (QQuickItem *item : indicators) {
|
||||
QRect rect(0, 0, int(item->width()), int(item->height()));
|
||||
rect.moveTopLeft(item->mapToGlobal(QPointF(0, 0)).toPoint());
|
||||
if (rect.contains(pt))
|
||||
return item;
|
||||
if (item->isVisible()) {
|
||||
QRect rect(0, 0, int(item->width()), int(item->height()));
|
||||
rect.moveTopLeft(item->mapToGlobal(QPointF(0, 0)).toPoint());
|
||||
if (rect.contains(pt)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -279,10 +313,10 @@ void IndicatorWindow::updatePositions()
|
||||
// Not needed to implement, the Indicators use QML anchors
|
||||
}
|
||||
|
||||
QPoint IndicatorWindow::posForIndicator(KDDockWidgets::DropIndicatorOverlayInterface::DropLocation) const
|
||||
QPoint IndicatorWindow::posForIndicator(KDDockWidgets::DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
return {};
|
||||
QQuickItem *indicator = IndicatorWindow::indicatorForLocation(loc);
|
||||
return indicator->mapToGlobal(indicator->boundingRect().center()).toPoint();
|
||||
}
|
||||
|
||||
QString IndicatorWindow::iconName(int loc, bool active) const
|
||||
@@ -295,6 +329,25 @@ ClassicIndicators *IndicatorWindow::classicIndicators() const
|
||||
return m_classicIndicators;
|
||||
}
|
||||
|
||||
QQuickItem *IndicatorWindow::indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const
|
||||
{
|
||||
const QVector<QQuickItem *> indicators = indicatorItems();
|
||||
Q_ASSERT(indicators.size() == 9);
|
||||
|
||||
for (QQuickItem *item : indicators) {
|
||||
if (locationForIndicator(item) == loc)
|
||||
return item;
|
||||
}
|
||||
|
||||
qWarning() << Q_FUNC_INFO << "Couldn't find indicator for location" << loc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation IndicatorWindow::locationForIndicator(const QQuickItem *item) const
|
||||
{
|
||||
return DropIndicatorOverlayInterface::DropLocation(item->property("indicatorType").toInt());
|
||||
}
|
||||
|
||||
QVector<QQuickItem *> IndicatorWindow::indicatorItems() const
|
||||
{
|
||||
QVector<QQuickItem *> indicators;
|
||||
|
||||
@@ -30,7 +30,7 @@ class IndicatorWindow : public QWidget
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IndicatorWindow(ClassicIndicators *classicIndicators);
|
||||
void hover(QPoint globalPos);
|
||||
DropIndicatorOverlayInterface::DropLocation hover(QPoint globalPos);
|
||||
void updatePositions();
|
||||
QPoint posForIndicator(DropIndicatorOverlayInterface::DropLocation) const;
|
||||
private:
|
||||
@@ -91,12 +91,14 @@ class IndicatorWindow : public QQuickView
|
||||
Q_PROPERTY(KDDockWidgets::ClassicIndicators* classicIndicators READ classicIndicators CONSTANT)
|
||||
public:
|
||||
explicit IndicatorWindow(ClassicIndicators *);
|
||||
void hover(QPoint);
|
||||
DropIndicatorOverlayInterface::DropLocation hover(QPoint);
|
||||
void updatePositions();
|
||||
QPoint posForIndicator(DropIndicatorOverlayInterface::DropLocation) const;
|
||||
Q_INVOKABLE QString iconName(int loc, bool active) const;
|
||||
KDDockWidgets::ClassicIndicators* classicIndicators() const;
|
||||
QQuickItem* indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const;
|
||||
private:
|
||||
DropIndicatorOverlayInterface::DropLocation locationForIndicator(const QQuickItem *) const;
|
||||
QQuickItem *indicatorForPos(QPoint) const;
|
||||
QVector<QQuickItem*> indicatorItems() const;
|
||||
ClassicIndicators *const m_classicIndicators;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user