Compare commits
401 Commits
fix-python
...
fix-virtua
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a2ffa030b | ||
|
|
dd8f46880f | ||
|
|
e9159a08bd | ||
|
|
cf89891e4f | ||
|
|
1cc8824f84 | ||
|
|
b73c526c57 | ||
|
|
add577c46f | ||
|
|
9ddd65ea71 | ||
|
|
b15afa9231 | ||
|
|
f8dfde2784 | ||
|
|
6e0898a31e | ||
|
|
8b98dafba2 | ||
|
|
a123437d03 | ||
|
|
616c871da7 | ||
|
|
925c9725b3 | ||
|
|
1a173a7c72 | ||
|
|
a959da46db | ||
|
|
a9c70d086c | ||
|
|
48bacb2811 | ||
|
|
6b846fcdff | ||
|
|
fdc97fecaf | ||
|
|
86983d58f5 | ||
|
|
58f7edb0bc | ||
|
|
302bbeceb0 | ||
|
|
cd9e16398c | ||
|
|
1e1ea8db34 | ||
|
|
7ac3ea1fcf | ||
|
|
3f661d0322 | ||
|
|
8dad079df5 | ||
|
|
1727e50489 | ||
|
|
1ab9688f58 | ||
|
|
613b1b8524 | ||
|
|
ae5edc9ebf | ||
|
|
d0c15b5da2 | ||
|
|
ccbd15c922 | ||
|
|
7b9673e4e2 | ||
|
|
7fbcbbacdf | ||
|
|
d1f48b0685 | ||
|
|
9ee6b91f61 | ||
|
|
e6c89c0564 | ||
|
|
8b97088c70 | ||
|
|
e5809c06c7 | ||
|
|
23b69d4e9e | ||
|
|
0f468033fb | ||
|
|
468074cda8 | ||
|
|
7acbe0c62e | ||
|
|
2c1a70280a | ||
|
|
d2fa5efafe | ||
|
|
a437bc5d07 | ||
|
|
2447bb12c8 | ||
|
|
1082d5e8e1 | ||
|
|
3b1ac9a2d0 | ||
|
|
4635405fb5 | ||
|
|
c481875e55 | ||
|
|
62f50f9458 | ||
|
|
c86252665c | ||
|
|
d141863ffb | ||
|
|
e99b9678e4 | ||
|
|
e0a034748d | ||
|
|
c3377431cc | ||
|
|
2fb70009cc | ||
|
|
289ddffbe2 | ||
|
|
54738bbea2 | ||
|
|
5c6eb352d6 | ||
|
|
f657399ef8 | ||
|
|
be0f72ca25 | ||
|
|
31598d8334 | ||
|
|
5e64463a8c | ||
|
|
27ffb64eb4 | ||
|
|
c4ffe10e12 | ||
|
|
efcad6d2be | ||
|
|
c7dc7bdb3d | ||
|
|
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 1)
|
||||
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
|
||||
set(${PROJECT_NAME}_SOVERSION "1.2")
|
||||
set(${PROJECT_NAME}_SOVERSION "1.3")
|
||||
|
||||
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)
|
||||
@@ -122,8 +147,8 @@ macro(set_compiler_flags targetName)
|
||||
endmacro()
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
find_package(Qt5Quick)
|
||||
find_package(Qt5QuickControls2)
|
||||
find_package(Qt${QT_MAJOR_VERSION}Quick)
|
||||
find_package(Qt${QT_MAJOR_VERSION}QuickControls2)
|
||||
add_definitions(-DKDDOCKWIDGETS_QTQUICK)
|
||||
else()
|
||||
add_definitions(-DKDDOCKWIDGETS_QTWIDGETS)
|
||||
@@ -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()
|
||||
|
||||
103
CMakePresets.json
Normal file
103
CMakePresets.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"version": 1,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "dev-qtwidgets",
|
||||
"displayName": "dev-qtwidgets",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-dev-qtwidgets",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qtwidgets",
|
||||
"displayName": "qtwidgets",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-qtwidgets",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qtquick",
|
||||
"displayName": "qtquick",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-qtquick",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_QTQUICK": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dev-qtquick",
|
||||
"displayName": "dev-qtquick",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-dev-qtquick",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_QTQUICK": "ON",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "python",
|
||||
"displayName": "python",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-python",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_PYTHON_BINDINGS": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "static-qtwidgets",
|
||||
"displayName": "static-qtwidgets",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-static-qtwidgets",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_STATIC": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "static-qtquick",
|
||||
"displayName": "static-qtquick",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-static-qtquick",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_STATIC": "ON",
|
||||
"KDDockWidgets_QTQUICK": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qtwidgets6",
|
||||
"displayName": "qtwidgets6",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-qtwidgets6",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_QT6": "ON"
|
||||
},
|
||||
"environment": {
|
||||
"PATH": "$env{HOME}/Qt/6.0.0/gcc_64/bin:$penv{PATH}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qtquick6",
|
||||
"displayName": "qtquick6",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-qtquick6",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_QTQUICK": "ON",
|
||||
"KDDockWidgets_QT6": "ON"
|
||||
},
|
||||
"environment": {
|
||||
"PATH": "$env{HOME}/Qt/6.0.0/gcc_64/bin:$penv{PATH}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
27
Changelog
27
Changelog
@@ -1,7 +1,22 @@
|
||||
* v1.2.0 (unreleased)
|
||||
- QtQuick support
|
||||
* v1.3.0 (unreleased)
|
||||
- [TODO] QtQuick support
|
||||
|
||||
* v1.1.0 (unreleased)
|
||||
* v1.2.1 (unreleased)
|
||||
- Support for resizing dock widgets when they are in overlay/popup mode (autohide/sidebar feature)
|
||||
|
||||
* 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 +27,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 +36,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.
|
||||
3
README-troubleshooting
Normal file
3
README-troubleshooting
Normal file
@@ -0,0 +1,3 @@
|
||||
# PySide: `ImportError: DLL load failed while importing KDDockWidgets`
|
||||
|
||||
If you're getting this error with Python see issue #114 and the proposed solution there.
|
||||
20
README.md
20
README.md
@@ -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
|
||||
@@ -98,6 +100,17 @@ The installation directory defaults to `c:\KDAB\KDDockWidgets-<version>` on Wind
|
||||
and `/usr/local/KDAB/KDDockWidgets-<version>` on non-Windows. You can change this
|
||||
location by passing the option `-DCMAKE_INSTALL_PREFIX=/install/path` to cmake.
|
||||
|
||||
== Using ==
|
||||
From your CMake project, add
|
||||
|
||||
find_package(KDDockWidgets CONFIG)
|
||||
|
||||
and link to the imported target KDAB::kddockwidgets.
|
||||
That's all you need to do (the imported target also brings in the include directories)
|
||||
|
||||
You may also need to point the CMAKE_MODULE_PATH environment variable depending
|
||||
on where you installed KDDockWidgets.
|
||||
|
||||
|
||||
Python Bindings
|
||||
================
|
||||
@@ -136,6 +149,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 +184,9 @@ 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)
|
||||
* [KDAB on Twitter](https://twitter.com/KDABQt)
|
||||
|
||||
@@ -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
|
||||
|
||||
161
dev-scripts/build-all.dart
Normal file
161
dev-scripts/build-all.dart
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is an helper script which simply reads CMakePresets.json and builds those
|
||||
* presets. It's just for quickly checking that every supported setup builds
|
||||
* without having to wait for CI (or in case you don't have access to KDAB CI)
|
||||
*
|
||||
* Usage:
|
||||
* $ dart build-all.dart <kddw-source-directory>
|
||||
*/
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
|
||||
String s_sourceDirectory = "";
|
||||
bool s_testUnityVariations = false;
|
||||
bool s_runTests = true;
|
||||
|
||||
class Preset {
|
||||
final String name;
|
||||
final String buildDir;
|
||||
String cmakeVariables = "";
|
||||
Preset.fromJson(var jsonData)
|
||||
: name = jsonData['name'],
|
||||
buildDir = jsonData['binaryDir'] {
|
||||
final varsData = jsonData['cacheVariables'];
|
||||
varsData.forEach((k, v) => cmakeVariables += ' -D' + k + '=' + v);
|
||||
}
|
||||
|
||||
String buildDirectory() {
|
||||
return buildDir.replaceAll("\${sourceDir}", s_sourceDirectory);
|
||||
}
|
||||
|
||||
List<String> cmakeConfigArguments(bool isUnityBuild) {
|
||||
return [
|
||||
"-G",
|
||||
"Ninja",
|
||||
cmakeVariables,
|
||||
"-B",
|
||||
buildDirectory(),
|
||||
"-S",
|
||||
s_sourceDirectory,
|
||||
"--preset=" + name,
|
||||
'-DKDDockWidgets_UNITY_BUILD=${isUnityBuild ? "ON" : "OFF"}'
|
||||
];
|
||||
}
|
||||
|
||||
List<String> cmakeBuildArguments() {
|
||||
return ["--build", buildDirectory()];
|
||||
}
|
||||
|
||||
// Builds twice. One with unity build and one without.
|
||||
Future<bool> build() async {
|
||||
if (!await buildSingle(true)) return false;
|
||||
if (s_testUnityVariations) if (!await buildSingle(false)) return false;
|
||||
if (s_runTests && !await runTests()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<bool> buildSingle(bool isUnityBuild) async {
|
||||
if (!await runCMake(cmakeConfigArguments(isUnityBuild))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!await runCMake(cmakeBuildArguments())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<bool> runTests() async {
|
||||
print("Running: ctest");
|
||||
|
||||
final savedCwd = Directory.current;
|
||||
Directory.current = buildDirectory();
|
||||
ProcessResult result = await Process.run('ctest', ["-j8"]);
|
||||
Directory.current = savedCwd;
|
||||
|
||||
if (result.exitCode != 0) {
|
||||
print(result.stdout);
|
||||
print(result.stderr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contents of the CMakePresets.json file
|
||||
String cmakePresetsJson(presetsFile) {
|
||||
var file = File(presetsFile);
|
||||
if (!file.existsSync()) {
|
||||
throw Exception('Not existent file');
|
||||
}
|
||||
return file.readAsStringSync();
|
||||
}
|
||||
|
||||
List<Preset> readPresets(var presetsFile) {
|
||||
var presets = List<Preset>();
|
||||
|
||||
final jsonData = jsonDecode(cmakePresetsJson(presetsFile));
|
||||
for (var presetData in jsonData['configurePresets']) {
|
||||
presets.add(Preset.fromJson(presetData));
|
||||
}
|
||||
return presets;
|
||||
}
|
||||
|
||||
Future<bool> runCMake(var cmd) async {
|
||||
print("Running: cmake " + cmd.join(' '));
|
||||
ProcessResult result = await Process.run('cmake', cmd);
|
||||
if (result.exitCode != 0) {
|
||||
print(result.stdout);
|
||||
print(result.stderr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<int> main(List<String> arguments) async {
|
||||
if (arguments.length == 0) {
|
||||
print("Usage: build-all.dart <src-directory> [--unity]");
|
||||
return 1;
|
||||
}
|
||||
|
||||
s_sourceDirectory = arguments[0];
|
||||
s_testUnityVariations = arguments.contains("--unity");
|
||||
s_runTests = arguments.contains("--tests");
|
||||
final presetsFile = s_sourceDirectory + '/CMakePresets.json';
|
||||
|
||||
if (FileSystemEntity.typeSync(presetsFile) == FileSystemEntityType.notFound) {
|
||||
print('ERROR: CMakePresets.json file not found in the source directory');
|
||||
return 1;
|
||||
}
|
||||
|
||||
var presets = readPresets(presetsFile);
|
||||
for (var preset in presets) {
|
||||
if (preset.name == 'python')
|
||||
continue; // TODO: blacklisted as it's not building on my setup yet
|
||||
|
||||
if (!await preset.build()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
print("Success!!");
|
||||
return 0;
|
||||
}
|
||||
@@ -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,68 @@ 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/TabWidget.cpp
|
||||
private/TabWidget_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 +93,7 @@ set(DOCKS_INSTALLABLE_INCLUDES
|
||||
FrameworkWidgetFactory.h
|
||||
DockWidgetBase.h
|
||||
KDDockWidgets.h
|
||||
Qt5Qt6Compat_p.h
|
||||
FocusScope.h
|
||||
QWidgetAdapter.h
|
||||
LayoutSaver.h
|
||||
@@ -70,6 +109,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
|
||||
@@ -80,38 +120,74 @@ set(DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES
|
||||
private/widgets/FrameWidget_p.h
|
||||
private/widgets/TabBarWidget_p.h
|
||||
private/widgets/TabWidgetWidget_p.h
|
||||
private/widgets/TabWidget_p.h
|
||||
private/TabWidget_p.h
|
||||
)
|
||||
|
||||
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/TabWidgetQuick.cpp
|
||||
private/quick/TabWidgetQuick_p.h
|
||||
private/quick/TabBarQuick.cpp
|
||||
private/quick/TabBarQuick_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
|
||||
private/widgets/TabWidget.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/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 +203,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 +212,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 +241,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 +285,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 +314,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,47 @@ 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;
|
||||
}
|
||||
|
||||
void Config::setAbsoluteWidgetMinSize(QSize size)
|
||||
{
|
||||
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/ false)) {
|
||||
qWarning() << Q_FUNC_INFO << "Only use this function at startup before creating any DockWidget or MainWindow";
|
||||
return;
|
||||
}
|
||||
|
||||
Layouting::Item::hardcodedMinimumSize = size;
|
||||
}
|
||||
|
||||
QSize Config::absoluteWidgetMinSize() const
|
||||
{
|
||||
return Layouting::Item::hardcodedMinimumSize;
|
||||
}
|
||||
|
||||
void Config::setAbsoluteWidgetMaxSize(QSize size)
|
||||
{
|
||||
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/ false)) {
|
||||
qWarning() << Q_FUNC_INFO << "Only use this function at startup before creating any DockWidget or MainWindow";
|
||||
return;
|
||||
}
|
||||
|
||||
Layouting::Item::hardcodedMaximumSize = size;
|
||||
}
|
||||
|
||||
QSize Config::absoluteWidgetMaxSize() const
|
||||
{
|
||||
return Layouting::Item::hardcodedMaximumSize;
|
||||
}
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
void Config::setQmlEngine(QQmlEngine *qmlEngine)
|
||||
{
|
||||
if (d->m_qmlEngine) {
|
||||
@@ -164,13 +210,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 +261,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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
90
src/Config.h
90
src/Config.h
@@ -23,6 +23,7 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQmlEngine;
|
||||
class QSize;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace KDDockWidgets
|
||||
@@ -35,6 +36,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 +62,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 +161,50 @@ 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;
|
||||
|
||||
///@brief Sets the minimum size a dock widget can have.
|
||||
/// Widgets can still provide their own min-size and it will be respected, however it can never be
|
||||
/// smaller than this one.
|
||||
void setAbsoluteWidgetMinSize(QSize size);
|
||||
QSize absoluteWidgetMinSize() const;
|
||||
|
||||
///@brief Sets the maximum size a dock widget can have.
|
||||
/// Widgets can still provide their own max-size and it will be respected, however it can never be
|
||||
/// bigger than this one.
|
||||
void setAbsoluteWidgetMaxSize(QSize size);
|
||||
QSize absoluteWidgetMaxSize() 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)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "Utils_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "Config.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
@@ -24,7 +23,6 @@
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "SideBar_p.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QEvent>
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
@@ -134,6 +132,7 @@ public:
|
||||
bool m_updatingToggleAction = false;
|
||||
bool m_updatingFloatAction = false;
|
||||
bool m_isForceClosing = false;
|
||||
QSize m_lastOverlayedSize = QSize(0, 0);
|
||||
};
|
||||
|
||||
DockWidgetBase::DockWidgetBase(const QString &name, Options options)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -515,6 +517,11 @@ bool DockWidgetBase::hasPreviousDockedLocation() const
|
||||
return d->m_lastPositions.isValid();
|
||||
}
|
||||
|
||||
QSize DockWidgetBase::lastOverlayedSize() const
|
||||
{
|
||||
return d->m_lastOverlayedSize;
|
||||
}
|
||||
|
||||
FloatingWindow *DockWidgetBase::morphIntoFloatingWindow()
|
||||
{
|
||||
qCDebug(creation) << "DockWidget::morphIntoFloatingWindow() this=" << this
|
||||
@@ -528,7 +535,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 +601,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 +670,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()
|
||||
@@ -786,6 +801,19 @@ void DockWidgetBase::onHidden(bool spontaneous)
|
||||
}
|
||||
}
|
||||
|
||||
bool DockWidgetBase::onResize(QSize newSize)
|
||||
{
|
||||
if (isOverlayed()) {
|
||||
if (auto frame = this->frame()) {
|
||||
d->m_lastOverlayedSize = frame->QWidgetAdapter::size();
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Overlayed dock widget without frame shouldn't happen";
|
||||
}
|
||||
}
|
||||
|
||||
return QWidgetAdapter::onResize(newSize);
|
||||
}
|
||||
|
||||
void DockWidgetBase::onCloseEvent(QCloseEvent *e)
|
||||
{
|
||||
e->accept(); // By default we accept, means DockWidget closes
|
||||
|
||||
@@ -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
|
||||
@@ -368,6 +440,10 @@ public:
|
||||
/// When you call dockWidget->setFloating(false) it will only dock if it knows where to.
|
||||
bool hasPreviousDockedLocation() const;
|
||||
|
||||
/// @brief returns the last size the widget has when overlayed
|
||||
/// Empty otherwise
|
||||
QSize lastOverlayedSize() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
///@brief signal emitted when the parent changed
|
||||
void parentChanged();
|
||||
@@ -407,12 +483,22 @@ 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);
|
||||
void onHidden(bool spontaneous);
|
||||
|
||||
#ifndef PYTHON_BINDINGS //Pyside bug: https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1327
|
||||
void onCloseEvent(QCloseEvent *e) override;
|
||||
bool onResize(QSize newSize) override;
|
||||
#endif
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
@@ -439,7 +525,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 +533,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 +565,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,24 +105,30 @@ 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();
|
||||
/* Q_EMIT */ q->isFocusedChangedCallback();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
Q_EMIT q->focusedWidgetChanged();
|
||||
setIsFocused(is);
|
||||
/* Q_EMIT */ q->focusedWidgetChangedCallback();
|
||||
} 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
|
||||
@@ -48,9 +48,10 @@ public:
|
||||
void focus(Qt::FocusReason = Qt::OtherFocusReason);
|
||||
|
||||
/*Q_SIGNALS:*/
|
||||
protected:
|
||||
///@brief reimplement in the 1st QObject derived class
|
||||
virtual void isFocusedChanged() = 0;
|
||||
virtual void focusedWidgetChanged() = 0;
|
||||
virtual void isFocusedChangedCallback() = 0;
|
||||
virtual void focusedWidgetChangedCallback() = 0;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Config.h"
|
||||
#include "indicators/ClassicIndicators_p.h"
|
||||
#include "indicators/NullIndicators_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "TabWidget_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"
|
||||
# include "widgets/TabBarWidget_p.h"
|
||||
@@ -32,10 +33,13 @@
|
||||
# include <QRubberBand>
|
||||
# include <QToolButton>
|
||||
#else
|
||||
# include "DockWidgetQuick.h"
|
||||
# include "quick/FrameQuick_p.h"
|
||||
# include "quick/DockWidgetQuick.h"
|
||||
# include "quick/TitleBarQuick_p.h"
|
||||
# include "quick/TabWidgetQuick_p.h"
|
||||
# include "quick/TabBarQuick_p.h"
|
||||
# include "quick/FloatingWindowQuick_p.h"
|
||||
# include "quick/RubberBandQuick.h"
|
||||
# include "multisplitter/Separator_quick.h"
|
||||
#endif
|
||||
|
||||
@@ -90,11 +94,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,21 +168,27 @@ 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);
|
||||
}
|
||||
|
||||
TabBar *DefaultWidgetFactory::createTabBar(TabWidget *parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
Q_ASSERT(false);
|
||||
return nullptr;
|
||||
return new TabBarQuick(parent);
|
||||
}
|
||||
|
||||
TabWidget *DefaultWidgetFactory::createTabWidget(Frame *parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
Q_ASSERT(false);
|
||||
return nullptr;
|
||||
return new TabWidgetQuick(parent);
|
||||
}
|
||||
|
||||
Layouting::Separator *DefaultWidgetFactory::createSeparator(Layouting::Widget *parent) const
|
||||
@@ -181,7 +198,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 +210,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 +255,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
|
||||
|
||||
@@ -43,6 +43,7 @@ class Frame;
|
||||
class DropArea;
|
||||
class SideBar;
|
||||
class TabBar;
|
||||
class TabWidgetQuick;
|
||||
|
||||
/**
|
||||
* @brief A factory class for allowing the user to customize some internal widgets.
|
||||
@@ -61,7 +62,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;
|
||||
|
||||
@@ -89,16 +95,16 @@ public:
|
||||
///@param floatingWindow Just forward to TitleBar's constructor.
|
||||
virtual TitleBar* createTitleBar(FloatingWindow *floatingWindow) const = 0;
|
||||
|
||||
///@brief Called internally by the framework to create a TabBar
|
||||
/// Override to provide your own TabBar sub-class.
|
||||
///@param parent Just forward to TabBar's's constructor.
|
||||
virtual TabBar* createTabBar(TabWidget *parent = nullptr) const = 0;
|
||||
|
||||
///@brief Called internally by the framework to create a TabWidget
|
||||
/// Override to provide your own TabWidget sub-class.
|
||||
///@param parent Just forward to TabWidget's constructor.
|
||||
virtual TabWidget* createTabWidget(Frame *parent) const = 0;
|
||||
|
||||
///@brief Called internally by the framework to create a TabBar
|
||||
/// Override to provide your own TabBar sub-class.
|
||||
///@param parent Just forward to TabBar's's constructor.
|
||||
virtual TabBar* createTabBar(TabWidget *parent = nullptr) const = 0;
|
||||
|
||||
///@brief Called internally by the framework to create a Separator
|
||||
/// Override to provide your own Separator sub-class. The Separator allows
|
||||
/// the user to resize nested dock widgets.
|
||||
@@ -134,10 +140,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
|
||||
@@ -157,8 +163,8 @@ public:
|
||||
Frame *createFrame(QWidgetOrQuick *parent, FrameOptions) const override;
|
||||
TitleBar *createTitleBar(Frame *) const override;
|
||||
TitleBar *createTitleBar(FloatingWindow *) const override;
|
||||
TabBar *createTabBar(TabWidget *parent) const override;
|
||||
TabWidget *createTabWidget(Frame *parent) const override;
|
||||
TabBar *createTabBar(TabWidget *parent) const override;
|
||||
Layouting::Separator *createSeparator(Layouting::Widget *parent = nullptr) const override;
|
||||
FloatingWindow *createFloatingWindow(MainWindowBase *parent = nullptr) const override;
|
||||
FloatingWindow *createFloatingWindow(Frame *frame, MainWindowBase *parent = nullptr) const override;
|
||||
@@ -168,6 +174,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);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,13 @@
|
||||
#include "Logging_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Position_p.h"
|
||||
#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 +699,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 +725,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()
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "Utils_p.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Item_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
|
||||
@@ -45,9 +45,12 @@ public:
|
||||
return m_options & MainWindowOption_HasCentralFrame;
|
||||
}
|
||||
|
||||
WidgetResizeHandler::CursorPositions allowedResizeSides(SideBarLocation loc) const;
|
||||
|
||||
QRect rectForOverlay(Frame *, SideBarLocation) const;
|
||||
SideBarLocation preferredSideBar(DockWidgetBase *) const;
|
||||
void updateOverlayGeometry();
|
||||
void updateOverlayGeometry(bool reusePreviousSize = false);
|
||||
void clearSideBars();
|
||||
|
||||
QString name;
|
||||
QStringList affinities;
|
||||
@@ -157,6 +160,27 @@ void MainWindowBase::layoutParentContainerEqually(DockWidgetBase *dockWidget)
|
||||
dropArea()->layoutParentContainerEqually(dockWidget);
|
||||
}
|
||||
|
||||
WidgetResizeHandler::CursorPositions MainWindowBase::Private::allowedResizeSides(SideBarLocation loc) const
|
||||
{
|
||||
// When a sidebar is on top, you can only resize its bottom.
|
||||
// and so forth...
|
||||
|
||||
switch (loc) {
|
||||
case SideBarLocation::North:
|
||||
return WidgetResizeHandler::CursorPosition_Bottom;
|
||||
case SideBarLocation::East:
|
||||
return WidgetResizeHandler::CursorPosition_Left;
|
||||
case SideBarLocation::West:
|
||||
return WidgetResizeHandler::CursorPosition_Right;
|
||||
case SideBarLocation::South:
|
||||
return WidgetResizeHandler::CursorPosition_Top;
|
||||
case SideBarLocation::None:
|
||||
return WidgetResizeHandler::CursorPosition_Undefined;
|
||||
}
|
||||
|
||||
return WidgetResizeHandler::CursorPosition_Undefined;
|
||||
}
|
||||
|
||||
QRect MainWindowBase::Private::rectForOverlay(Frame *frame, SideBarLocation location) const
|
||||
{
|
||||
SideBar *sb = q->sideBar(location);
|
||||
@@ -323,7 +347,7 @@ SideBarLocation MainWindowBase::Private::preferredSideBar(DockWidgetBase *dw) co
|
||||
: SideBarLocation::West;
|
||||
}
|
||||
|
||||
void MainWindowBase::Private::updateOverlayGeometry()
|
||||
void MainWindowBase::Private::updateOverlayGeometry(bool reusePreviousSize)
|
||||
{
|
||||
if (!m_overlayedDockWidget)
|
||||
return;
|
||||
@@ -334,7 +358,55 @@ void MainWindowBase::Private::updateOverlayGeometry()
|
||||
return;
|
||||
}
|
||||
|
||||
m_overlayedDockWidget->frame()->QWidgetAdapter::setGeometry(rectForOverlay(m_overlayedDockWidget->frame(), sb->location()));
|
||||
const QRect defaultGeometry = rectForOverlay(m_overlayedDockWidget->frame(), sb->location());
|
||||
QRect newGeometry = defaultGeometry;
|
||||
|
||||
Frame *frame = m_overlayedDockWidget->frame();
|
||||
|
||||
if (reusePreviousSize) {
|
||||
// Let's try to honour the previous overlay size
|
||||
switch (sb->location()) {
|
||||
case SideBarLocation::North: {
|
||||
const int maxHeight = q->height() - frame->pos().y() - 10; // gap
|
||||
newGeometry.setHeight(qMin(frame->height(), maxHeight));
|
||||
break;
|
||||
}
|
||||
case SideBarLocation::South: {
|
||||
const int maxHeight = sb->pos().y() - m_dropArea->pos().y() - 10; // gap
|
||||
const int bottom = newGeometry.bottom();
|
||||
newGeometry.setHeight(qMin(frame->height(), maxHeight));
|
||||
newGeometry.moveBottom(bottom);
|
||||
break;
|
||||
}
|
||||
case SideBarLocation::East: {
|
||||
const int maxWidth = sb->pos().x() - m_dropArea->pos().x() - 10; // gap
|
||||
const int right = newGeometry.right();
|
||||
newGeometry.setWidth(qMin(frame->width(), maxWidth));
|
||||
newGeometry.moveRight(right);
|
||||
break;
|
||||
}
|
||||
case SideBarLocation::West: {
|
||||
const int maxWidth = q->width() - frame->pos().x() - 10; // gap
|
||||
newGeometry.setWidth(qMin(frame->height(), maxWidth));
|
||||
break;
|
||||
}
|
||||
case SideBarLocation::None:
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected sidebar value";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_overlayedDockWidget->frame()->QWidgetAdapter::setGeometry(newGeometry);
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -376,7 +448,7 @@ void MainWindowBase::overlayOnSideBar(DockWidgetBase *dw)
|
||||
return;
|
||||
|
||||
const SideBar *sb = sideBarForDockWidget(dw);
|
||||
if (sb == nullptr) {
|
||||
if (!sb) {
|
||||
qWarning() << Q_FUNC_INFO << "You need to add the dock widget to the sidebar before you can overlay it";
|
||||
return;
|
||||
}
|
||||
@@ -392,7 +464,12 @@ void MainWindowBase::overlayOnSideBar(DockWidgetBase *dw)
|
||||
auto frame = Config::self().frameworkWidgetFactory()->createFrame(this, FrameOption_IsOverlayed);
|
||||
d->m_overlayedDockWidget = dw;
|
||||
frame->addWidget(dw);
|
||||
d->updateOverlayGeometry();
|
||||
d->updateOverlayGeometry(/*reusePreviousSize=*/ false);
|
||||
|
||||
// Uncomment once I'm happy with the resizing
|
||||
auto resizeHandler = new WidgetResizeHandler(true, frame);
|
||||
resizeHandler->setAllowedResizeSides(d->allowedResizeSides(sb->location()));
|
||||
|
||||
frame->QWidgetAdapter::show();
|
||||
|
||||
Q_EMIT dw->isOverlayedChanged(true);
|
||||
@@ -401,7 +478,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 +502,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 +517,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;
|
||||
}
|
||||
@@ -463,7 +552,7 @@ void MainWindowBase::setUniqueName(const QString &uniqueName)
|
||||
void MainWindowBase::onResized(QResizeEvent *)
|
||||
{
|
||||
if (d->m_overlayedDockWidget)
|
||||
d->updateOverlayGeometry();
|
||||
d->updateOverlayGeometry(/*reusePreviousSize=*/ true);
|
||||
}
|
||||
|
||||
bool MainWindowBase::deserialize(const LayoutSaver::MainWindow &mw)
|
||||
@@ -481,7 +570,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 +613,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,42 @@
|
||||
#define KDDOCKWIDGETS_QT5QT6_COMPAT_P_H
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QDropEvent>
|
||||
|
||||
namespace KDDockWidgets {
|
||||
namespace Qt5Qt6Compat {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
|
||||
#define QQUICKITEMgeometryChanged geometryChange
|
||||
|
||||
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
|
||||
#else // Qt 5:
|
||||
|
||||
#define QQUICKITEMgeometryChanged geometryChanged
|
||||
|
||||
using QEnterEvent = QEvent;
|
||||
using qintptr = long;
|
||||
using qhashtype = uint;
|
||||
|
||||
inline QPoint eventPos(QDropEvent *ev)
|
||||
{
|
||||
return ev->pos();
|
||||
}
|
||||
|
||||
// Qt 5:
|
||||
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"
|
||||
@@ -9,4 +9,4 @@
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../../../../private/widgets/TabWidget_p.h"
|
||||
#include "../../../private/TabWidget_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;
|
||||
@@ -555,7 +595,7 @@ void DockRegistry::clear(const DockWidgetBase::List &dockWidgets,
|
||||
|
||||
for (auto mw : qAsConst(mainWindows)) {
|
||||
if (affinities.isEmpty() || affinitiesMatch(affinities, mw->affinities())) {
|
||||
mw->multiSplitter()->rootItem()->clear();
|
||||
mw->multiSplitter()->clearLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -587,12 +627,15 @@ bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
|
||||
if (!(Config::self().flags() & Config::Flag_AutoHideSupport))
|
||||
return false;
|
||||
|
||||
if (qobject_cast<Frame*>(watched)) {
|
||||
// break recursion
|
||||
return false;
|
||||
}
|
||||
|
||||
auto p = watched;
|
||||
while (p) {
|
||||
if (auto dw = qobject_cast<DockWidgetBase*>(p)) {
|
||||
onDockWidgetPressed(dw);
|
||||
return false;
|
||||
}
|
||||
if (auto dw = qobject_cast<DockWidgetBase*>(p))
|
||||
return onDockWidgetPressed(dw, static_cast<QMouseEvent*>(event));
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
@@ -601,17 +644,29 @@ bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
|
||||
return false;
|
||||
}
|
||||
|
||||
void DockRegistry::onDockWidgetPressed(DockWidgetBase *dw)
|
||||
bool DockRegistry::onDockWidgetPressed(DockWidgetBase *dw, QMouseEvent *ev)
|
||||
{
|
||||
// Here we implement "auto-hide". If there's a overlayed dock widget, we hide it if some other
|
||||
// dock widget is clicked.
|
||||
|
||||
MainWindowBase *mainWindow = dw->mainWindow();
|
||||
if (!mainWindow) // Only docked widgets are interesting
|
||||
return;
|
||||
return false;
|
||||
|
||||
DockWidgetBase *overlayedDockWidget = mainWindow->overlayedDockWidget();
|
||||
if (overlayedDockWidget && dw != overlayedDockWidget) {
|
||||
mainWindow->clearSideBarOverlay();
|
||||
if (DockWidgetBase *overlayedDockWidget = mainWindow->overlayedDockWidget()) {
|
||||
ev->ignore();
|
||||
qApp->sendEvent(overlayedDockWidget->frame(), ev);
|
||||
|
||||
if (ev->isAccepted()) {
|
||||
// The Frame accepted it. It means the user is resizing it. We allow for 4px outside for better resize.
|
||||
return true; // don't propagate the event further
|
||||
}
|
||||
if (dw != overlayedDockWidget) {
|
||||
// User clicked outside if the overlay, then we close the overlay.
|
||||
mainWindow->clearSideBarOverlay();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
bool onDockWidgetPressed(DockWidgetBase *dw, QMouseEvent *);
|
||||
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;
|
||||
@@ -496,7 +653,7 @@ static QWidget *qtTopLevelForHWND(HWND hwnd)
|
||||
template <typename T>
|
||||
static WidgetType* qtTopLevelUnderCursor_impl(QPoint globalPos, const QVector<QWindow*> &windows, T windowBeingDragged)
|
||||
{
|
||||
for (int i = windows.size() -1; i >= 0; --i) {
|
||||
for (auto i = windows.size() -1; i >= 0; --i) {
|
||||
QWindow *window = windows.at(i);
|
||||
auto tl = KDDockWidgets::Private::widgetForWindow(window);
|
||||
|
||||
@@ -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,12 +54,7 @@ QWidgetOrQuick *Draggable::asWidget() const
|
||||
|
||||
bool Draggable::dragCanStart(QPoint pressPos, QPoint globalPos) const
|
||||
{
|
||||
return (globalPos - pressPos).manhattanLength() > QApplication::startDragDistance();
|
||||
}
|
||||
|
||||
WidgetResizeHandler *Draggable::widgetResizeHandler() const
|
||||
{
|
||||
return d->widgetResizeHandler;
|
||||
return (globalPos - pressPos).manhattanLength() > KDDockWidgets::startDragDistance();
|
||||
}
|
||||
|
||||
void Draggable::setWidgetResizeHandler(WidgetResizeHandler *w)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef KD_DRAGGABLE_P_H
|
||||
#define KD_DRAGGABLE_P_H
|
||||
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
|
||||
#include <QVector>
|
||||
|
||||
@@ -62,10 +62,11 @@ public:
|
||||
*/
|
||||
virtual bool dragCanStart(QPoint pressPos, QPoint globalPos) const;
|
||||
|
||||
WidgetResizeHandler *widgetResizeHandler() const;
|
||||
/**
|
||||
* @brief Sets a widget resize handler
|
||||
*/
|
||||
void setWidgetResizeHandler(WidgetResizeHandler *w);
|
||||
|
||||
|
||||
/**
|
||||
* @brief If this draggable contains a single dock widget, then it's returned.
|
||||
* nullptr otherwise.
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "MainWindowBase.h"
|
||||
#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 +38,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 +120,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 +148,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 +181,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 +212,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 +229,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 +295,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
|
||||
setWidgetResizeHandler(new WidgetResizeHandler(false, this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Config.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "TabWidget_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
@@ -49,6 +50,7 @@ static FrameOptions actualOptions(FrameOptions options)
|
||||
Frame::Frame(QWidgetOrQuick *parent, FrameOptions options)
|
||||
: LayoutGuestWidget(parent)
|
||||
, FocusScope(this)
|
||||
, m_tabWidget(Config::self().frameworkWidgetFactory()->createTabWidget(this))
|
||||
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
|
||||
, m_options(actualOptions(options))
|
||||
{
|
||||
@@ -57,6 +59,10 @@ Frame::Frame(QWidgetOrQuick *parent, FrameOptions options)
|
||||
qCDebug(creation) << "Frame" << ((void*)this) << s_dbg_numFrames;
|
||||
|
||||
connect(this, &Frame::currentDockWidgetChanged, this, &Frame::updateTitleAndIcon);
|
||||
|
||||
connect(m_tabWidget->asWidget(), SIGNAL(currentTabChanged(int)),
|
||||
this, SLOT(onCurrentTabChanged(int)));
|
||||
|
||||
setDropArea(qobject_cast<DropArea *>(QWidgetAdapter::parentWidget()));
|
||||
m_inCtor = false;
|
||||
}
|
||||
@@ -135,7 +141,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 +177,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)
|
||||
@@ -231,7 +251,7 @@ int Frame::dockWidgetCount() const
|
||||
{
|
||||
if (m_inCtor || m_inDtor) return 0;
|
||||
|
||||
return dockWidgetCount_impl();
|
||||
return m_tabWidget->numDockWidgets();
|
||||
}
|
||||
|
||||
void Frame::onDockWidgetCountChanged()
|
||||
@@ -265,6 +285,16 @@ void Frame::onCurrentTabChanged(int index)
|
||||
}
|
||||
}
|
||||
|
||||
void Frame::isFocusedChangedCallback()
|
||||
{
|
||||
Q_EMIT isFocusedChanged();
|
||||
}
|
||||
|
||||
void Frame::focusedWidgetChangedCallback()
|
||||
{
|
||||
Q_EMIT focusedWidgetChanged();
|
||||
}
|
||||
|
||||
void Frame::updateTitleBarVisibility()
|
||||
{
|
||||
if (m_updatingTitleBar || m_beingDeleted) {
|
||||
@@ -347,7 +377,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 +472,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 +483,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 +603,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 +666,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;
|
||||
}
|
||||
@@ -687,3 +716,8 @@ MainWindowBase *Frame::mainWindow() const
|
||||
return m_dropArea ? m_dropArea->mainWindow()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
TabWidget *Frame::tabWidget() const
|
||||
{
|
||||
return m_tabWidget;
|
||||
}
|
||||
|
||||
@@ -19,21 +19,22 @@
|
||||
#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 "multisplitter/Item_p.h"
|
||||
#include "FocusScope.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
#include "kddockwidgets/FocusScope.h"
|
||||
#include "../LayoutSaver_p.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVector>
|
||||
#include <QDebug>
|
||||
#include <QPointer>
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class TitleBar;
|
||||
class TabWidget;
|
||||
class DropArea;
|
||||
class DockWidgetBase;
|
||||
class FloatingWindow;
|
||||
@@ -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 *);
|
||||
@@ -104,6 +106,9 @@ public:
|
||||
/// @brief returns the number of dock widgets inside the frame
|
||||
int dockWidgetCount() const;
|
||||
|
||||
/// @brief returns the tab widget
|
||||
TabWidget *tabWidget() const;
|
||||
|
||||
void updateTitleAndIcon();
|
||||
void onDockWidgetTitleChanged();
|
||||
void updateTitleBarVisibility();
|
||||
@@ -165,7 +170,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;
|
||||
@@ -240,9 +245,16 @@ Q_SIGNALS:
|
||||
void hasTabsVisibleChanged();
|
||||
void layoutInvalidated();
|
||||
void isInMainWindowChanged();
|
||||
void isFocusedChanged() override; // override from non-QObject
|
||||
void focusedWidgetChanged() override;
|
||||
void isFocusedChanged();
|
||||
void focusedWidgetChanged();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onDockWidgetCountChanged();
|
||||
void onCurrentTabChanged(int index);
|
||||
|
||||
protected:
|
||||
void isFocusedChangedCallback() final;
|
||||
void focusedWidgetChangedCallback() final;
|
||||
|
||||
virtual void renameTab(int index, const QString &) = 0;
|
||||
|
||||
@@ -265,10 +277,8 @@ protected:
|
||||
* Any widget having 16777215x16777215 is ignored (represents not having a max-size, QWIDGETSIZE_MAX)
|
||||
*/
|
||||
QSize biggestDockWidgetMaxSize() const;
|
||||
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;
|
||||
@@ -276,17 +286,21 @@ protected:
|
||||
virtual void insertDockWidget_impl(DockWidgetBase *, int index) = 0;
|
||||
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;
|
||||
|
||||
TabWidget *const m_tabWidget;
|
||||
TitleBar *const m_titleBar;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Frame)
|
||||
friend class TestDocks;
|
||||
friend class ::TestDocks;
|
||||
friend class TabWidget;
|
||||
void onCurrentTabChanged(int index);
|
||||
|
||||
void scheduleDeleteLater();
|
||||
bool event(QEvent *) override;
|
||||
bool m_inCtor = true;
|
||||
TitleBar *const m_titleBar;
|
||||
DropArea *m_dropArea = nullptr;
|
||||
const FrameOptions m_options;
|
||||
QPointer<Layouting::Item> m_layoutItem;
|
||||
|
||||
@@ -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
|
||||
@@ -202,7 +202,7 @@ void MultiSplitter::addWidget(QWidgetOrQuick *w, Location location,
|
||||
newItem->setGuestWidget(frame);
|
||||
frame->addWidget(dw, option);
|
||||
} else if (auto ms = qobject_cast<MultiSplitter*>(w)) {
|
||||
newItem = ms->rootItem();
|
||||
newItem = ms->m_rootItem;
|
||||
newItem->setHostWidget(this);
|
||||
|
||||
if (FloatingWindow *fw = ms->floatingWindow()) {
|
||||
@@ -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;
|
||||
}
|
||||
@@ -267,7 +267,7 @@ int MultiSplitter::placeholderCount() const
|
||||
return count() - visibleCount();
|
||||
}
|
||||
|
||||
Layouting::Separator::List MultiSplitter::separators() const
|
||||
QVector<Layouting::Separator*> MultiSplitter::separators() const
|
||||
{
|
||||
return m_rootItem->separators_recursive();
|
||||
}
|
||||
@@ -371,6 +371,11 @@ void MultiSplitter::layoutEqually(Layouting::ItemContainer *container)
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSplitter::clearLayout()
|
||||
{
|
||||
m_rootItem->clear();
|
||||
}
|
||||
|
||||
bool MultiSplitter::checkSanity() const
|
||||
{
|
||||
return m_rootItem->checkSanity();
|
||||
@@ -404,6 +409,11 @@ QSize MultiSplitter::layoutMinimumSize() const
|
||||
return m_rootItem->minSize();
|
||||
}
|
||||
|
||||
QSize MultiSplitter::layoutMaximumSizeHint() const
|
||||
{
|
||||
return m_rootItem->maxSizeHint();
|
||||
}
|
||||
|
||||
QSize MultiSplitter::size() const { return m_rootItem->size(); }
|
||||
|
||||
void MultiSplitter::setLayoutMinimumSize(QSize sz)
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#define KDDOCKWIDGETS_MULTISPLITTER_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "multisplitter/Separator_p.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "KDDockWidgets.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
@@ -35,12 +34,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 +88,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.
|
||||
@@ -120,10 +121,6 @@ public:
|
||||
*/
|
||||
const QVector<Layouting::Item*> items() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the root container item
|
||||
*/
|
||||
Layouting::ItemContainer *rootItem() const;
|
||||
|
||||
/**
|
||||
* Called by the indicators, so they draw the drop rubber band at the correct place.
|
||||
@@ -171,6 +168,11 @@ public:
|
||||
*/
|
||||
QSize layoutMinimumSize() const;
|
||||
|
||||
/**
|
||||
* @brief returns the layout's maximum size hint
|
||||
*/
|
||||
QSize layoutMaximumSizeHint() const;
|
||||
|
||||
/**
|
||||
* @brief getter for the size
|
||||
*/
|
||||
@@ -204,6 +206,9 @@ public:
|
||||
/// @brief overload that just resizes widgets within a sub-tree
|
||||
void layoutEqually(Layouting::ItemContainer *);
|
||||
|
||||
/// @brief clears the layout
|
||||
void clearLayout();
|
||||
|
||||
Q_SIGNALS:
|
||||
void visibleWidgetCountChanged(int count);
|
||||
|
||||
@@ -213,7 +218,7 @@ protected:
|
||||
private:
|
||||
bool m_inResizeEvent = false;
|
||||
|
||||
friend class TestDocks;
|
||||
friend class ::TestDocks;
|
||||
|
||||
/**
|
||||
* @brief returns the frames contained in @p frameOrMultiSplitter
|
||||
@@ -222,6 +227,7 @@ private:
|
||||
*/
|
||||
QList<Frame*> framesFrom(QWidgetOrQuick *frameOrMultiSplitter) const;
|
||||
|
||||
Layouting::ItemContainer *rootItem() const;
|
||||
|
||||
// For debug/hardening
|
||||
bool validateInputs(QWidgetOrQuick *widget, KDDockWidgets::Location location,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -162,7 +163,7 @@ LayoutSaver::Position Position::serialize() const
|
||||
|
||||
Layouting::Item *item = itemRef->item;
|
||||
MultiSplitter *layout = DockRegistry::self()->layoutForItem(item);
|
||||
const int itemIndex = layout->items().indexOf(item);
|
||||
const auto itemIndex = layout->items().indexOf(item);
|
||||
|
||||
auto fw = layout->floatingWindow();
|
||||
auto mainWindow = layout->mainWindow();
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "docks_export.h"
|
||||
#include "Logging_p.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "multisplitter/Item_p.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -84,42 +84,36 @@ std::unique_ptr<WindowBeingDragged> TabBar::makeWindow()
|
||||
if (!dock)
|
||||
return {};
|
||||
|
||||
FloatingWindow *floatingWindow = detachTab(dock);
|
||||
FloatingWindow *floatingWindow = frame()->detachTab(dock);
|
||||
if (!floatingWindow)
|
||||
return {};
|
||||
|
||||
auto draggable = KDDockWidgets::usesNativeTitleBar() ? static_cast<Draggable*>(floatingWindow)
|
||||
: static_cast<Draggable*>(this);
|
||||
return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(floatingWindow, draggable));
|
||||
}
|
||||
|
||||
FloatingWindow * TabBar::detachTab(DockWidgetBase *dockWidget)
|
||||
{
|
||||
QRect r = dockWidget->geometry();
|
||||
m_tabWidget->removeDockWidget(dockWidget);
|
||||
|
||||
auto newFrame = Config::self().frameworkWidgetFactory()->createFrame();
|
||||
const QPoint globalPoint = m_thisWidget->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;
|
||||
}
|
||||
|
||||
void TabBar::onMousePress(QPoint localPos)
|
||||
{
|
||||
m_lastPressedDockWidget = dockWidgetAt(localPos);
|
||||
}
|
||||
|
||||
void TabBar::onMouseDoubleClick(QPoint localPos)
|
||||
{
|
||||
if (DockWidgetBase *dw = dockWidgetAt(localPos))
|
||||
dw->setFloating(true);
|
||||
}
|
||||
|
||||
bool TabBar::hasSingleDockWidget() const
|
||||
{
|
||||
return numDockWidgets() == 1;
|
||||
}
|
||||
|
||||
int TabBar::numDockWidgets() const
|
||||
{
|
||||
return m_tabWidget->numDockWidgets();
|
||||
}
|
||||
|
||||
QWidgetOrQuick *TabBar::asWidget() const
|
||||
{
|
||||
return m_thisWidget;
|
||||
@@ -140,15 +134,6 @@ TabWidget::TabWidget(QWidgetOrQuick *thisWidget, Frame *frame)
|
||||
, m_frame(frame)
|
||||
, m_thisWidget(thisWidget)
|
||||
{
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
// Little ifdefery, as this is not so easy to abstract
|
||||
QObject::connect(static_cast<QTabWidget*>(thisWidget), &QTabWidget::currentChanged,
|
||||
frame, &Frame::onCurrentTabChanged);
|
||||
#else
|
||||
qWarning() << Q_FUNC_INFO << "Implement me";
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void TabWidget::setCurrentDockWidget(DockWidgetBase *dw)
|
||||
@@ -156,12 +141,17 @@ void TabWidget::setCurrentDockWidget(DockWidgetBase *dw)
|
||||
setCurrentDockWidget(indexOfDockWidget(dw));
|
||||
}
|
||||
|
||||
DockWidgetBase *TabWidget::currentDockWidget() const
|
||||
{
|
||||
return dockwidgetAt(currentIndex());
|
||||
}
|
||||
|
||||
void TabWidget::addDockWidget(DockWidgetBase *dock)
|
||||
{
|
||||
insertDockWidget(dock, numDockWidgets());
|
||||
}
|
||||
|
||||
void TabWidget::insertDockWidget(DockWidgetBase *dock, int index)
|
||||
bool TabWidget::insertDockWidget(DockWidgetBase *dock, int index)
|
||||
{
|
||||
Q_ASSERT(dock);
|
||||
qCDebug(addwidget) << Q_FUNC_INFO << dock << "; count before=" << numDockWidgets();
|
||||
@@ -173,7 +163,7 @@ void TabWidget::insertDockWidget(DockWidgetBase *dock, int index)
|
||||
|
||||
if (contains(dock)) {
|
||||
qWarning() << Q_FUNC_INFO << "Refusing to add already existing widget";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
QPointer<Frame> oldFrame = dock->frame();
|
||||
@@ -191,6 +181,8 @@ void TabWidget::insertDockWidget(DockWidgetBase *dock, int index)
|
||||
|
||||
delete oldFrame;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TabWidget::contains(DockWidgetBase *dw) const
|
||||
@@ -213,7 +205,6 @@ std::unique_ptr<WindowBeingDragged> TabWidget::makeWindow()
|
||||
// This is called when using Flag_HideTitleBarWhenTabsVisible
|
||||
// For detaching individual tabs, TabBar::makeWindow() is called.
|
||||
if (auto floatingWindow = qobject_cast<FloatingWindow*>(asWidget()->window())) {
|
||||
|
||||
if (floatingWindow->hasSingleFrame()) {
|
||||
// We're already in a floating window, and it only has 1 dock widget.
|
||||
// So there's no detachment to be made, we just move the window.
|
||||
@@ -221,7 +212,7 @@ std::unique_ptr<WindowBeingDragged> TabWidget::makeWindow()
|
||||
}
|
||||
}
|
||||
|
||||
QRect r = m_frame->QWidget::geometry();
|
||||
QRect r = m_frame->QWidgetAdapter::geometry();
|
||||
|
||||
const QPoint globalPoint = m_thisWidget->mapToGlobal(QPoint(0, 0));
|
||||
|
||||
@@ -255,3 +246,26 @@ void TabWidget::onCurrentTabChanged(int index)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
}
|
||||
|
||||
bool TabWidget::onMouseDoubleClick(QPoint localPos)
|
||||
{
|
||||
// User clicked the empty space of the tab widget and we don't have title bar
|
||||
// We float the entire frame.
|
||||
|
||||
if (!(Config::self().flags() & Config::Flag_HideTitleBarWhenTabsVisible) || tabBar()->dockWidgetAt(localPos))
|
||||
return false;
|
||||
|
||||
Frame *frame = this->frame();
|
||||
|
||||
if (FloatingWindow *fw = frame->floatingWindow()) {
|
||||
if (!fw->hasSingleFrame()) {
|
||||
makeWindow();
|
||||
return true;
|
||||
}
|
||||
} else if (frame->isInMainWindow()) {
|
||||
makeWindow();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -20,12 +20,12 @@
|
||||
#ifndef KD_TAB_WIDGET_P_H
|
||||
#define KD_TAB_WIDGET_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "../Draggable_p.h"
|
||||
#include "../Frame_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "kddockwidgets/DockWidgetBase.h"
|
||||
|
||||
#include "Draggable_p.h"
|
||||
#include "Frame_p.h"
|
||||
|
||||
#include <QTabBar>
|
||||
#include <QVector>
|
||||
|
||||
#include <memory>
|
||||
@@ -58,23 +58,15 @@ public:
|
||||
// Draggable
|
||||
std::unique_ptr<WindowBeingDragged> makeWindow() override;
|
||||
|
||||
/**
|
||||
* @brief detaches a dock widget and shows it as a floating dock widget
|
||||
* The dock widget is morphed into a FloatingWindow for convenience.
|
||||
* @param dockWidget the dock widget to detach
|
||||
* @returns the created FloatingWindow
|
||||
*/
|
||||
FloatingWindow *detachTab(DockWidgetBase *dockWidget);
|
||||
|
||||
void onMousePress(QPoint localPos);
|
||||
void onMouseDoubleClick(QPoint localPos);
|
||||
|
||||
///@brief returns whether there's only 1 tab
|
||||
bool hasSingleDockWidget() const;
|
||||
|
||||
virtual int numDockWidgets() const = 0;
|
||||
int numDockWidgets() const;
|
||||
virtual int tabAt(QPoint localPos) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns this class as a QWidget (if using QtWidgets) or QQuickItem
|
||||
*/
|
||||
@@ -119,7 +111,10 @@ public:
|
||||
virtual void setCurrentDockWidget(int index) = 0;
|
||||
void setCurrentDockWidget(DockWidgetBase *);
|
||||
|
||||
virtual void insertDockWidget(int index, DockWidgetBase *, const QIcon&, const QString &title) = 0;
|
||||
/// @brief Returns the current dock widget
|
||||
DockWidgetBase *currentDockWidget() const;
|
||||
|
||||
virtual bool insertDockWidget(int index, DockWidgetBase *, const QIcon&, const QString &title) = 0;
|
||||
|
||||
virtual void setTabBarAutoHide(bool) = 0;
|
||||
|
||||
@@ -139,18 +134,12 @@ public:
|
||||
*/
|
||||
virtual DockWidgetBase *dockwidgetAt(int index) const = 0;
|
||||
|
||||
/**
|
||||
* @brief detaches a dock widget and shows it as a floating dock widget
|
||||
* @param dockWidget the dock widget to detach
|
||||
*/
|
||||
virtual void detachTab(DockWidgetBase *dockWidget) = 0;
|
||||
|
||||
/**
|
||||
* @brief inserts @p dockwidget into the TabWidget, at @p index
|
||||
* @param dockwidget the dockwidget to insert
|
||||
* @param index The index to where to put it
|
||||
*/
|
||||
void insertDockWidget(DockWidgetBase *dockwidget, int index);
|
||||
bool insertDockWidget(DockWidgetBase *dockwidget, int index);
|
||||
|
||||
/**
|
||||
* @brief Returns whether dockwidget @p dw is contained in this tab widget
|
||||
@@ -175,10 +164,16 @@ public:
|
||||
std::unique_ptr<WindowBeingDragged> makeWindow() override;
|
||||
DockWidgetBase *singleDockWidget() const override;
|
||||
|
||||
//Q_SIGNALS: // Not a OQbject
|
||||
virtual void currentTabChanged(int index) = 0;
|
||||
virtual void currentDockWidgetChanged(KDDockWidgets::DockWidgetBase *) = 0;
|
||||
virtual void countChanged() {};
|
||||
|
||||
protected:
|
||||
void onTabInserted();
|
||||
void onTabRemoved();
|
||||
void onCurrentTabChanged(int index);
|
||||
bool onMouseDoubleClick(QPoint localPos);
|
||||
|
||||
private:
|
||||
Frame *const m_frame;
|
||||
@@ -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,8 +266,46 @@ 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
|
||||
|
||||
|
||||
/// @brief Returns the widget's geometry, but always in global space.
|
||||
inline QRect globalGeometry(QWidgetOrQuick *w)
|
||||
{
|
||||
QRect geo = w->geometry();
|
||||
if (!w->isTopLevel())
|
||||
geo.moveTopLeft(w->mapToGlobal(QPoint(0, 0)));
|
||||
return geo;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#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>
|
||||
@@ -35,15 +33,12 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
int widgetResizeHandlerMargin = 4; //4 pixel
|
||||
}
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
bool WidgetResizeHandler::s_disableAllHandlers = false;
|
||||
WidgetResizeHandler::WidgetResizeHandler(QWidget *target)
|
||||
WidgetResizeHandler::WidgetResizeHandler(bool filterIsGlobal, QWidgetOrQuick *target)
|
||||
: QObject(target)
|
||||
, mFilterIsGlobal(filterIsGlobal)
|
||||
{
|
||||
setTarget(target);
|
||||
}
|
||||
@@ -52,15 +47,32 @@ WidgetResizeHandler::~WidgetResizeHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void WidgetResizeHandler::setAllowedResizeSides(CursorPositions sides)
|
||||
{
|
||||
mAllowedResizeSides = sides;
|
||||
}
|
||||
|
||||
void WidgetResizeHandler::setResizeGap(int gap)
|
||||
{
|
||||
m_resizeGap = gap;
|
||||
}
|
||||
|
||||
int WidgetResizeHandler::widgetResizeHandlerMargin()
|
||||
{
|
||||
return 4; // pixels
|
||||
}
|
||||
|
||||
bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *e)
|
||||
{
|
||||
if (s_disableAllHandlers || o != mTarget)
|
||||
if (s_disableAllHandlers)
|
||||
return false;
|
||||
|
||||
auto widget = qobject_cast<QWidget*>(o);
|
||||
if (!widget || !widget->isTopLevel()) {
|
||||
auto widget = qobject_cast<QWidgetOrQuick*>(o);
|
||||
if (!widget)
|
||||
return false;
|
||||
|
||||
if (!mFilterIsGlobal && (!widget->isTopLevel() || o != mTarget))
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (e->type()) {
|
||||
case QEvent::MouseButtonPress: {
|
||||
@@ -68,31 +80,32 @@ 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));
|
||||
const int m = widgetResizeHandlerMargin();
|
||||
const QRect widgetRect = mTarget->rect().marginsAdded(QMargins(m, m, m, m));
|
||||
const QPoint cursorPoint = mTarget->mapFromGlobal(Qt5Qt6Compat::eventGlobalPos(mouseEvent));
|
||||
if (!widgetRect.contains(cursorPoint))
|
||||
if (!widgetRect.contains(cursorPoint) || mouseEvent->button() != Qt::LeftButton)
|
||||
return false;
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
mResizeWidget = true;
|
||||
}
|
||||
|
||||
mResizeWidget = true;
|
||||
mNewPosition = Qt5Qt6Compat::eventGlobalPos(mouseEvent);
|
||||
mCursorPos = cursorPos;
|
||||
|
||||
return true;
|
||||
}
|
||||
case QEvent::MouseButtonRelease: {
|
||||
if (mTarget->isMaximized())
|
||||
break;
|
||||
mResizeWidget = false;
|
||||
auto mouseEvent = static_cast<QMouseEvent *>(e);
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
mResizeWidget = false;
|
||||
mTarget->releaseMouse();
|
||||
mTarget->releaseKeyboard();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mTarget->isMaximized() || !mResizeWidget || mouseEvent->button() != Qt::LeftButton)
|
||||
break;
|
||||
|
||||
mTarget->releaseMouse();
|
||||
mTarget->releaseKeyboard();
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove: {
|
||||
@@ -101,10 +114,11 @@ bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *e)
|
||||
auto mouseEvent = static_cast<QMouseEvent *>(e);
|
||||
mResizeWidget = mResizeWidget && (mouseEvent->buttons() & Qt::LeftButton);
|
||||
const bool state = mResizeWidget;
|
||||
mResizeWidget = ((o == mTarget) && mResizeWidget);
|
||||
mouseMoveEvent(mouseEvent);
|
||||
if (!mFilterIsGlobal)
|
||||
mResizeWidget = ((o == mTarget) && mResizeWidget);
|
||||
const bool consumed = mouseMoveEvent(mouseEvent);
|
||||
mResizeWidget = state;
|
||||
return true;
|
||||
return consumed;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -112,26 +126,34 @@ bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *e)
|
||||
return false;
|
||||
}
|
||||
|
||||
void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
bool WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
const QPoint globalPos = Qt5Qt6Compat::eventGlobalPos(e);
|
||||
if (!mResizeWidget) {
|
||||
updateCursor(cursorPosition(globalPos));
|
||||
return;
|
||||
const CursorPosition pos = cursorPosition(globalPos);
|
||||
updateCursor(pos);
|
||||
return pos != CursorPosition_Undefined;
|
||||
}
|
||||
|
||||
const QRect oldGeometry = mTarget->geometry();
|
||||
const QRect oldGeometry = KDDockWidgets::globalGeometry(mTarget);
|
||||
QRect newGeometry = oldGeometry;
|
||||
|
||||
QRect parentGeometry;
|
||||
if (!mTarget->isTopLevel())
|
||||
parentGeometry = KDDockWidgets::Private::parentGeometry(mTarget);
|
||||
|
||||
|
||||
{
|
||||
int deltaWidth = 0;
|
||||
int newWidth = 0;
|
||||
const int minWidth = mTarget->minimumWidth();
|
||||
const int maxWidth = mTarget->maximumWidth();
|
||||
const int maxWidth = Layouting::Widget::widgetMaxSize(mTarget).width();
|
||||
const int minWidth = Layouting::Widget::widgetMinSize(mTarget).width();
|
||||
|
||||
switch (mCursorPos) {
|
||||
case CursorPosition::TopLeft:
|
||||
case CursorPosition::Left:
|
||||
case CursorPosition::BottomLeft: {
|
||||
case CursorPosition_TopLeft:
|
||||
case CursorPosition_Left:
|
||||
case CursorPosition_BottomLeft: {
|
||||
parentGeometry = parentGeometry.adjusted(0, m_resizeGap, 0, 0);
|
||||
deltaWidth = oldGeometry.left() - globalPos.x();
|
||||
newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
|
||||
deltaWidth = newWidth - mTarget->width();
|
||||
@@ -142,9 +164,10 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
break;
|
||||
}
|
||||
|
||||
case CursorPosition::TopRight:
|
||||
case CursorPosition::Right:
|
||||
case CursorPosition::BottomRight: {
|
||||
case CursorPosition_TopRight:
|
||||
case CursorPosition_Right:
|
||||
case CursorPosition_BottomRight: {
|
||||
parentGeometry = parentGeometry.adjusted(0, 0, -m_resizeGap, 0);
|
||||
deltaWidth = globalPos.x() - newGeometry.right();
|
||||
newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
|
||||
deltaWidth = newWidth - mTarget->width();
|
||||
@@ -159,14 +182,15 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
}
|
||||
|
||||
{
|
||||
const int maxHeight = mTarget->maximumHeight();
|
||||
const int minHeight = mTarget->minimumHeight();
|
||||
const int maxHeight = Layouting::Widget::widgetMaxSize(mTarget).height();
|
||||
const int minHeight = Layouting::Widget::widgetMinSize(mTarget).height();
|
||||
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: {
|
||||
parentGeometry = parentGeometry.adjusted(0, m_resizeGap, 0, 0);
|
||||
deltaHeight = oldGeometry.top() - globalPos.y();
|
||||
newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
|
||||
deltaHeight = newHeight - mTarget->height();
|
||||
@@ -177,9 +201,10 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
break;
|
||||
}
|
||||
|
||||
case CursorPosition::BottomLeft:
|
||||
case CursorPosition::Bottom:
|
||||
case CursorPosition::BottomRight: {
|
||||
case CursorPosition_BottomLeft:
|
||||
case CursorPosition_Bottom:
|
||||
case CursorPosition_BottomRight: {
|
||||
parentGeometry = parentGeometry.adjusted(0, 0, 0, -m_resizeGap);
|
||||
deltaHeight = globalPos.y() - newGeometry.bottom();
|
||||
newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
|
||||
deltaHeight = newHeight - mTarget->height();
|
||||
@@ -193,15 +218,26 @@ void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
|
||||
}
|
||||
}
|
||||
|
||||
if (newGeometry != mTarget->geometry())
|
||||
mTarget->setGeometry(newGeometry);
|
||||
}
|
||||
if (newGeometry != mTarget->geometry()) {
|
||||
if (!mTarget->isTopLevel()) {
|
||||
|
||||
// Clip to parent's geometry.
|
||||
newGeometry = newGeometry.intersected(parentGeometry);
|
||||
|
||||
// Back to local.
|
||||
newGeometry.moveTopLeft(mTarget->mapFromGlobal(newGeometry.topLeft()) + mTarget->pos());
|
||||
}
|
||||
|
||||
mTarget->setGeometry(newGeometry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#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 +286,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 +320,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,12 +350,16 @@ bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByt
|
||||
|
||||
#endif
|
||||
|
||||
void WidgetResizeHandler::setTarget(QWidget *w)
|
||||
void WidgetResizeHandler::setTarget(QWidgetOrQuick *w)
|
||||
{
|
||||
if (w) {
|
||||
mTarget = w;
|
||||
mTarget->setMouseTracking(true);
|
||||
mTarget->installEventFilter(this);
|
||||
if (mFilterIsGlobal) {
|
||||
qApp->installEventFilter(this);
|
||||
} else {
|
||||
mTarget->installEventFilter(this);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Target widget is null!";
|
||||
}
|
||||
@@ -330,62 +367,85 @@ 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:
|
||||
mTarget->setCursor(Qt::SizeFDiagCursor);
|
||||
case CursorPosition_TopLeft:
|
||||
case CursorPosition_BottomRight:
|
||||
setMouseCursor(Qt::SizeFDiagCursor);
|
||||
break;
|
||||
case CursorPosition::BottomLeft:
|
||||
case CursorPosition::TopRight:
|
||||
mTarget->setCursor(Qt::SizeBDiagCursor);
|
||||
case CursorPosition_BottomLeft:
|
||||
case CursorPosition_TopRight:
|
||||
setMouseCursor(Qt::SizeBDiagCursor);
|
||||
break;
|
||||
case CursorPosition::Top:
|
||||
case CursorPosition::Bottom:
|
||||
mTarget->setCursor(Qt::SizeVerCursor);
|
||||
case CursorPosition_Top:
|
||||
case CursorPosition_Bottom:
|
||||
setMouseCursor(Qt::SizeVerCursor);
|
||||
break;
|
||||
case CursorPosition::Left:
|
||||
case CursorPosition::Right:
|
||||
mTarget->setCursor(Qt::SizeHorCursor);
|
||||
case CursorPosition_Left:
|
||||
case CursorPosition_Right:
|
||||
setMouseCursor(Qt::SizeHorCursor);
|
||||
break;
|
||||
case CursorPosition::Undefined:
|
||||
mTarget->setCursor(Qt::ArrowCursor);
|
||||
case CursorPosition_Undefined:
|
||||
restoreMouseCursor();
|
||||
break;
|
||||
case CursorPosition_All:
|
||||
// Doesn't happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WidgetResizeHandler::setMouseCursor(Qt::CursorShape cursor)
|
||||
{
|
||||
if (mFilterIsGlobal)
|
||||
qApp->setOverrideCursor(cursor);
|
||||
else
|
||||
mTarget->setCursor(cursor);
|
||||
}
|
||||
|
||||
void WidgetResizeHandler::restoreMouseCursor()
|
||||
{
|
||||
if (mFilterIsGlobal)
|
||||
qApp->restoreOverrideCursor();
|
||||
else
|
||||
mTarget->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
const int x = pos.x();
|
||||
const int y = pos.y();
|
||||
const int margin = widgetResizeHandlerMargin();
|
||||
|
||||
int result = CursorPosition_Undefined;
|
||||
if (qAbs(x) <= margin)
|
||||
result |= CursorPosition_Left;
|
||||
else if (qAbs(x - (mTarget->width() - margin)) <= margin)
|
||||
result |= CursorPosition_Right;
|
||||
|
||||
if (qAbs(y) <= margin)
|
||||
result |= CursorPosition_Top;
|
||||
else if (qAbs(y - (mTarget->height() - margin)) <= margin)
|
||||
result |= CursorPosition_Bottom;
|
||||
|
||||
// Filter out sides we don't allow
|
||||
result = result & mAllowedResizeSides;
|
||||
|
||||
return static_cast<CursorPosition>(result);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user