Compare commits
392 Commits
python6
...
fix_white_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f674aa27a9 | ||
|
|
5f78110025 | ||
|
|
ca3c49f32d | ||
|
|
def6a0a6b2 | ||
|
|
b0cb983830 | ||
|
|
02515d8956 | ||
|
|
447b4337dd | ||
|
|
633daf124e | ||
|
|
446560931b | ||
|
|
9fe11a7ad5 | ||
|
|
b099994ac5 | ||
|
|
a8d56ef4e6 | ||
|
|
1f8d212dee | ||
|
|
64ea87f4cc | ||
|
|
e6fef433d5 | ||
|
|
2f212031b3 | ||
|
|
586ab710f6 | ||
|
|
d263ae649e | ||
|
|
c81ca45e41 | ||
|
|
9ce50fa305 | ||
|
|
f0240deaeb | ||
|
|
017f06dcfb | ||
|
|
54f17cb546 | ||
|
|
f174ab6ebc | ||
|
|
263f936690 | ||
|
|
bd903a0353 | ||
|
|
5040d3a6b6 | ||
|
|
3684da776d | ||
|
|
bc17c8e5b3 | ||
|
|
778c647782 | ||
|
|
2a91f6279b | ||
|
|
4ef2ddbfec | ||
|
|
ff06f0cc73 | ||
|
|
a37ab34fae | ||
|
|
cb2ffe66af | ||
|
|
16b0770d72 | ||
|
|
3fe44ee735 | ||
|
|
40d1a72300 | ||
|
|
4d428d42f6 | ||
|
|
7e9896263b | ||
|
|
cf0665c9b6 | ||
|
|
93c011c69d | ||
|
|
f50c0b9d06 | ||
|
|
6fc79d942b | ||
|
|
d01228d9ff | ||
|
|
b58d766d54 | ||
|
|
79cbb96a38 | ||
|
|
aabaeacb81 | ||
|
|
3ab3e6d41b | ||
|
|
f2f4afd0bb | ||
|
|
0d62c43b9e | ||
|
|
1614d5702c | ||
|
|
610b9542e9 | ||
|
|
946f32a274 | ||
|
|
c7a6bc015e | ||
|
|
19fd1635e6 | ||
|
|
74b034a195 | ||
|
|
581139d099 | ||
|
|
e5492ea906 | ||
|
|
623133a0dc | ||
|
|
6baa8f2dbb | ||
|
|
d2739d7218 | ||
|
|
5702101935 | ||
|
|
35d45a7523 | ||
|
|
e37c1f0e8c | ||
|
|
ac0d35ef12 | ||
|
|
15e63381a9 | ||
|
|
aa49ddacd5 | ||
|
|
f68e876bcb | ||
|
|
6b82ded399 | ||
|
|
000e67a09e | ||
|
|
1b6aa4c3d1 | ||
|
|
8912a2c842 | ||
|
|
4de50db68c | ||
|
|
6b95e4aac9 | ||
|
|
c27658822e | ||
|
|
8ec980c1e8 | ||
|
|
a952c5829a | ||
|
|
20e1b55a8a | ||
|
|
a2605868db | ||
|
|
67be35b9f8 | ||
|
|
b15eb1e62f | ||
|
|
d2e3ec0448 | ||
|
|
828c403fe5 | ||
|
|
53d3bc86ea | ||
|
|
6ed8742cc1 | ||
|
|
7bd047f6e6 | ||
|
|
482757b1cc | ||
|
|
c143f832c6 | ||
|
|
67a173ef53 | ||
|
|
c2c37488a3 | ||
|
|
8c1840b9cf | ||
|
|
1088e37cd4 | ||
|
|
4d6c3dac3d | ||
|
|
adf29873ef | ||
|
|
772afe29ea | ||
|
|
9c78953800 | ||
|
|
ff67b9bcbc | ||
|
|
103de4f910 | ||
|
|
7c3f06f98f | ||
|
|
6ac77a7662 | ||
|
|
610b85d01a | ||
|
|
d4d222ebd3 | ||
|
|
5cbed1d34b | ||
|
|
ba4a2eef5c | ||
|
|
acdf03fc84 | ||
|
|
a6f19e07c4 | ||
|
|
f07301bb1e | ||
|
|
2116e3741b | ||
|
|
1f11c732ed | ||
|
|
e42bee27a4 | ||
|
|
b36dcf1325 | ||
|
|
421746c943 | ||
|
|
f544ac58e6 | ||
|
|
6047275cfa | ||
|
|
630d832f50 | ||
|
|
e0a34465d8 | ||
|
|
443a4049c3 | ||
|
|
54980e7585 | ||
|
|
14ff8bb26b | ||
|
|
615bb0ee3f | ||
|
|
986fd8c13b | ||
|
|
ec1cc27815 | ||
|
|
3874e2d886 | ||
|
|
1afcf21529 | ||
|
|
4c0f3bd7cb | ||
|
|
9aafa2a662 | ||
|
|
029ba1202e | ||
|
|
b5043b2b87 | ||
|
|
52ce80fd97 | ||
|
|
cd19c5eb38 | ||
|
|
0d101d779f | ||
|
|
1ff6f43eac | ||
|
|
98d892f643 | ||
|
|
cc80afff7d | ||
|
|
91ad74e3ad | ||
|
|
b128d25fbe | ||
|
|
8b23769ccc | ||
|
|
13f84ab518 | ||
|
|
feadc1ff9e | ||
|
|
f75c3a123e | ||
|
|
12dfe49d9b | ||
|
|
545618964d | ||
|
|
a6f3f21b70 | ||
|
|
e6135f49fb | ||
|
|
cd3a1c869e | ||
|
|
8bb21b12aa | ||
|
|
f500791ba3 | ||
|
|
4ebc4e9546 | ||
|
|
94ee2e55fd | ||
|
|
e3c370eb6b | ||
|
|
6fea5af585 | ||
|
|
e9e149d55e | ||
|
|
bb5d98164f | ||
|
|
8941f41d1c | ||
|
|
d45e17b603 | ||
|
|
c2b3e6b36e | ||
|
|
b8405c01f1 | ||
|
|
3d191da07e | ||
|
|
aeb61993a4 | ||
|
|
3679e1da3a | ||
|
|
52aefd23f0 | ||
|
|
76a2b84925 | ||
|
|
a89b2c7ed1 | ||
|
|
5dd4eb2d20 | ||
|
|
600661a570 | ||
|
|
92f6453d26 | ||
|
|
8bf3aa9b4d | ||
|
|
c52db1945b | ||
|
|
09a10cd791 | ||
|
|
07fd577894 | ||
|
|
ed900b8531 | ||
|
|
fa010357b3 | ||
|
|
da6ffc85ef | ||
|
|
b7c23087e1 | ||
|
|
656f482cad | ||
|
|
5e03003b94 | ||
|
|
48b5b27d42 | ||
|
|
fccb815d5a | ||
|
|
544d3b026a | ||
|
|
15ff882919 | ||
|
|
18d405bdfb | ||
|
|
4379e7c544 | ||
|
|
51e2be9b7b | ||
|
|
f2b21d04b3 | ||
|
|
a73f35af22 | ||
|
|
7b3ef03924 | ||
|
|
a4d03c1514 | ||
|
|
eccdee0081 | ||
|
|
48f3390d71 | ||
|
|
df6f1e6c8f | ||
|
|
3c95081aee | ||
|
|
329a980510 | ||
|
|
d8605e9ce3 | ||
|
|
7dcc6dc114 | ||
|
|
64db52fd17 | ||
|
|
c0957024ec | ||
|
|
649571a2eb | ||
|
|
60adb0d50b | ||
|
|
f751d7c24e | ||
|
|
5ec5ade62f | ||
|
|
788c497cbb | ||
|
|
f6c274b82f | ||
|
|
5a6b4a6fdd | ||
|
|
ef212b8c0f | ||
|
|
aa2f46fd00 | ||
|
|
a30808e6b7 | ||
|
|
f23c55dfec | ||
|
|
583d3188ca | ||
|
|
ae81f64d07 | ||
|
|
8dca2e346c | ||
|
|
b995986318 | ||
|
|
0579b6dcd3 | ||
|
|
4d147c7ff3 | ||
|
|
baf5f088dc | ||
|
|
2adaacb922 | ||
|
|
bc6870f4ee | ||
|
|
c6abaf22c1 | ||
|
|
e04e066177 | ||
|
|
6ad01f4994 | ||
|
|
f6ad75e214 | ||
|
|
a76864450e | ||
|
|
3fe9994322 | ||
|
|
3bcfcc40c0 | ||
|
|
92b54f949b | ||
|
|
a73746fe8b | ||
|
|
da1fddffe1 | ||
|
|
e3b0feb967 | ||
|
|
4e6811cfdc | ||
|
|
cc47e46e1f | ||
|
|
4246d99b93 | ||
|
|
ba38e3c1aa | ||
|
|
83aa64928d | ||
|
|
5fbff7211b | ||
|
|
eb67f19e3e | ||
|
|
2130a31dfd | ||
|
|
f3ce208ec1 | ||
|
|
146478eb5e | ||
|
|
05413d5a99 | ||
|
|
eac726fcb8 | ||
|
|
b25af85234 | ||
|
|
02167a0788 | ||
|
|
54cce9aa41 | ||
|
|
73cdc7136c | ||
|
|
1567a2b847 | ||
|
|
9fe795f8dd | ||
|
|
0d6cfd183d | ||
|
|
bba36d041b | ||
|
|
710716f658 | ||
|
|
b39798ac24 | ||
|
|
1f8fbb8518 | ||
|
|
51dc666181 | ||
|
|
2a6e716e07 | ||
|
|
01d68f30e4 | ||
|
|
1b73d01de8 | ||
|
|
a421cb0b01 | ||
|
|
2177336d65 | ||
|
|
059a8cc38f | ||
|
|
4c33cd6409 | ||
|
|
ea48d52447 | ||
|
|
85f4be750a | ||
|
|
0ba37a347b | ||
|
|
6ee1900331 | ||
|
|
44bf1ef322 | ||
|
|
863691c313 | ||
|
|
97d7cbf657 | ||
|
|
3089535de6 | ||
|
|
36818093c6 | ||
|
|
e5857df439 | ||
|
|
42d25dc1a5 | ||
|
|
3b5e78bfba | ||
|
|
639dce7c53 | ||
|
|
882f54647c | ||
|
|
38443048b8 | ||
|
|
621c3dbeca | ||
|
|
f1e4f7ecda | ||
|
|
249d1b6790 | ||
|
|
894e0fd03a | ||
|
|
ec1f009914 | ||
|
|
697417b906 | ||
|
|
dadf57c184 | ||
|
|
7caa83be19 | ||
|
|
e745d38b1e | ||
|
|
6d389315bf | ||
|
|
024d56505a | ||
|
|
daec97ad66 | ||
|
|
a98daead1d | ||
|
|
2c5cf77cf2 | ||
|
|
a6b9a82e9c | ||
|
|
02cf9d1cd2 | ||
|
|
cde814b216 | ||
|
|
5f435cd8c7 | ||
|
|
6ccd98ca01 | ||
|
|
799f2a81a7 | ||
|
|
eb9fa6f567 | ||
|
|
9ebd595202 | ||
|
|
b50d301f44 | ||
|
|
b01b8908ea | ||
|
|
78c2cdddc4 | ||
|
|
1eaac74fb0 | ||
|
|
ee759a5459 | ||
|
|
e9d19805d7 | ||
|
|
1f74ba43f0 | ||
|
|
bc1e686455 | ||
|
|
5cc0552c57 | ||
|
|
6c06bc6af8 | ||
|
|
2193c131a8 | ||
|
|
9a38626af5 | ||
|
|
f0c243f6d1 | ||
|
|
f0441f1a08 | ||
|
|
8a9d9f9fce | ||
|
|
db06c496cf | ||
|
|
2aa97e6565 | ||
|
|
68597cac22 | ||
|
|
afa543ec79 | ||
|
|
d1df6e910b | ||
|
|
74ae567ced | ||
|
|
8d657c5b18 | ||
|
|
802bdc102f | ||
|
|
218d18793d | ||
|
|
723c29e33b | ||
|
|
2e248c6658 | ||
|
|
7fbd66d54c | ||
|
|
4bede063ae | ||
|
|
cbc5fec119 | ||
|
|
81927b088b | ||
|
|
5556edd83b | ||
|
|
2834532b5f | ||
|
|
17638bc29f | ||
|
|
67b48cc417 | ||
|
|
451996016a | ||
|
|
52b9a9223d | ||
|
|
d5b80b0bbd | ||
|
|
ae14e49338 | ||
|
|
c23bce9829 | ||
|
|
40a549ca29 | ||
|
|
cac435a2a5 | ||
|
|
b81f50402a | ||
|
|
44587cb947 | ||
|
|
54314273a0 | ||
|
|
de068dc6ff | ||
|
|
64f537ad1e | ||
|
|
312c89f884 | ||
|
|
d9fd7eb3a5 | ||
|
|
af9206f350 | ||
|
|
7c99bb084e | ||
|
|
1a2757b00a | ||
|
|
1e7a2110b1 | ||
|
|
243146fe49 | ||
|
|
370d139dfc | ||
|
|
c4e7db34a4 | ||
|
|
a4f6b72157 | ||
|
|
de3ca6dba5 | ||
|
|
bdfcfdd0fe | ||
|
|
dbf357ce66 | ||
|
|
e950cf7fc3 | ||
|
|
8dfad1c910 | ||
|
|
107d4e973c | ||
|
|
e33766a4fa | ||
|
|
6a550c6c4a | ||
|
|
a0fc2a8ce7 | ||
|
|
ab257b3468 | ||
|
|
e6bdb28484 | ||
|
|
c52446f3b0 | ||
|
|
9cadfb26d9 | ||
|
|
7d5ea8f908 | ||
|
|
161b33370e | ||
|
|
8dd7a90b34 | ||
|
|
7ff865a36f | ||
|
|
d0b8ee606a | ||
|
|
c6c3b16fd2 | ||
|
|
64a6cbb2e4 | ||
|
|
e1cf532437 | ||
|
|
67f2127710 | ||
|
|
9111b424a1 | ||
|
|
772b51216f | ||
|
|
a79a2f5ecb | ||
|
|
585c0d64ed | ||
|
|
7ddb95a417 | ||
|
|
02648eb54e | ||
|
|
54a1050fbb | ||
|
|
f997b2d2f0 | ||
|
|
8f61e57b57 | ||
|
|
cfcff6f2d7 | ||
|
|
44d7cc0588 | ||
|
|
c91275d091 | ||
|
|
69c88919c0 | ||
|
|
e0e6f55868 | ||
|
|
7698584ee0 | ||
|
|
d034722ba9 | ||
|
|
e1e07c95ba | ||
|
|
b81c32b1c9 |
72
.clang-format
Normal file
72
.clang-format
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
BasedOnStyle: WebKit
|
||||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
|
||||
IndentWidth: 4
|
||||
SpacesBeforeTrailingComments: 1
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
ContinuationIndentWidth: 4
|
||||
MaxEmptyLinesToKeep: 3
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
|
||||
ForEachMacros:
|
||||
- forever # avoids { wrapped to next line
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
|
||||
AccessModifierOffset: -4
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false # requires clang-format 11
|
||||
AlignAfterOpenBracket: true
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackParameters: true
|
||||
ColumnLimit: 100
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerBinding: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
IndentCaseLabels: false
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 60
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerBindsToType: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
IndentFunctionDeclarationAfterType: false
|
||||
SpaceAfterControlStatementKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: true
|
||||
SpacesInParentheses: false
|
||||
...
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -58,3 +58,9 @@ kddockwidgets_minimal_example
|
||||
/CMakeDoxygenDefaults.cmake
|
||||
/Testing
|
||||
/layout_tst*
|
||||
/x64
|
||||
/src/kddockwidgets_version.h
|
||||
*.vcxproj*
|
||||
*.sln
|
||||
*.dir
|
||||
.vscode
|
||||
|
||||
2
.krazy
2
.krazy
@@ -7,7 +7,7 @@ EXTRA kdabcopyright-reuse,kdabcontactus,fosslicense-reuse
|
||||
#EXTRA defines,null
|
||||
|
||||
#exclude checks now being done by clazy or clang-tools
|
||||
EXCLUDE strings,explicit,normalize,passbyvalue,operators,nullstrcompare,nullstrassign,doublequote_chars,qobject,sigsandslots,staticobjects,dpointer,inline
|
||||
EXCLUDE strings,explicit,normalize,passbyvalue,operators,nullstrcompare,nullstrassign,doublequote_chars,qobject,sigsandslots,staticobjects,dpointer,inline,postfixop
|
||||
#exclude more checks
|
||||
EXCLUDE style
|
||||
|
||||
|
||||
68
.vscode/launch.json
vendored
68
.vscode/launch.json
vendored
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) QtWidgets example",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/bin/kddockwidgets_example",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "(gdb) QtQuick example",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/bin/kddockwidgets_example_quick",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "(vs) kddockwidgets_example",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/bin/kddockwidgets_example.exe",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"sourceFileMap" : {
|
||||
"C:\\Users\\qt\\work\\qt\\qtbase\\src" : "D:\\Qt\\5.14.2\\Src\\qtbase\\src"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "(vs) tst_docks",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/build/bin/tst_docks.exe",
|
||||
"args": ["tst_moreTitleBarCornerCases", "-platform", "windows"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false
|
||||
}
|
||||
]
|
||||
}
|
||||
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"C_Cpp.default.configurationProvider": "vector-of-bool.cmake-tools",
|
||||
"files.associations": {
|
||||
"qevent": "cpp"
|
||||
},
|
||||
"cmake.configureSettings": {
|
||||
"KDDockWidgets_DEVELOPER_MODE" : "ON",
|
||||
"KDDockWidgets_QTQUICK" : true
|
||||
}
|
||||
}
|
||||
140
CMakeLists.txt
140
CMakeLists.txt
@@ -19,6 +19,11 @@
|
||||
# Build static versions of the libraries
|
||||
# Default=false
|
||||
#
|
||||
# -DKDDockWidgets_UNINSTALL=[true|false]
|
||||
# Setup the uninstall target.
|
||||
# You may want to disable the uninstall target that's added by default when you are including
|
||||
# KDDockWidgets as a submodule directly and have a custom uninstall target of your own.
|
||||
#
|
||||
# -DKDDockWidgets_TESTS=[true|false]
|
||||
# Build the test harness.
|
||||
# Currently does nothing unless you also set KDDockWidgets_DEVELOPER_MODE=True
|
||||
@@ -29,7 +34,7 @@
|
||||
# Default=true
|
||||
#
|
||||
# -DKDDockWidgets_DOCS=[true|false]
|
||||
# Build the API documentation.
|
||||
# Build the API documentation. Enables the 'docs' build target.
|
||||
# Default=false
|
||||
#
|
||||
# -DKDDockWidgets_DEVELOPER_MODE=[true|false]
|
||||
@@ -49,11 +54,6 @@
|
||||
# -DKDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX=[path]
|
||||
# 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)
|
||||
@@ -81,10 +81,10 @@ else()
|
||||
endif()
|
||||
|
||||
set(${PROJECT_NAME}_VERSION_MAJOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 2)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 1)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 4)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 0)
|
||||
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
|
||||
set(${PROJECT_NAME}_SOVERSION "1.3")
|
||||
set(${PROJECT_NAME}_SOVERSION "1.4")
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
@@ -92,15 +92,11 @@ 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}_UNINSTALL "Enable the uninstall target" ON)
|
||||
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)
|
||||
@@ -114,14 +110,16 @@ endif()
|
||||
|
||||
#option(${PROJECT_NAME}_QTQUICK "Build for QtQuick instead of QtWidgets" OFF)
|
||||
|
||||
if (${PROJECT_NAME}_QT6)
|
||||
if(${PROJECT_NAME}_QT6)
|
||||
find_package(Qt6Widgets REQUIRED)
|
||||
find_package(Qt6Test REQUIRED)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
set(KDDockWidgets_LIBRARY_QTID "-qt6")
|
||||
else()
|
||||
find_package(Qt5Widgets 5.9 REQUIRED)
|
||||
find_package(Qt5Test 5.9 REQUIRED)
|
||||
set(QT_MAJOR_VERSION 5)
|
||||
set(KDDockWidgets_LIBRARY_QTID "")
|
||||
endif()
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
@@ -156,14 +154,21 @@ macro(set_compiler_flags targetName)
|
||||
|
||||
endmacro()
|
||||
|
||||
set(${PROJECT_NAME}_DEPS "widgets")
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
find_package(Qt${QT_MAJOR_VERSION}Quick)
|
||||
find_package(Qt${QT_MAJOR_VERSION}QuickControls2)
|
||||
add_definitions(-DKDDOCKWIDGETS_QTQUICK)
|
||||
set(${PROJECT_NAME}_DEPS "${${PROJECT_NAME}_DEPS} quick quickcontrols2")
|
||||
else()
|
||||
add_definitions(-DKDDOCKWIDGETS_QTWIDGETS)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT ${PROJECT_NAME}_QT6)
|
||||
set(${PROJECT_NAME}_DEPS "${${PROJECT_NAME}_DEPS} x11extras")
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_STATIC)
|
||||
set(${PROJECT_NAME}_LIBRARY_MODE "STATIC")
|
||||
else()
|
||||
@@ -178,31 +183,38 @@ if(USE_DEFAULT_INSTALL_LOCATION)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate .pri file for qmake users
|
||||
include(ECMGeneratePriFile)
|
||||
set(PROJECT_VERSION_STRING ${${PROJECT_NAME}_VERSION})
|
||||
ecm_generate_pri_file(BASE_NAME KDDockWidgets
|
||||
LIB_NAME kddockwidgets
|
||||
FILENAME_VAR pri_filename
|
||||
)
|
||||
install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
||||
|
||||
install(FILES LICENSE.txt README.md DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(DIRECTORY LICENSES DESTINATION ${INSTALL_DOC_DIR})
|
||||
|
||||
add_subdirectory(src)
|
||||
if(${PROJECT_NAME}_PYTHON_BINDINGS)
|
||||
add_subdirectory(python)
|
||||
endif()
|
||||
|
||||
# Generate .pri file for qmake users
|
||||
if(CMAKE_VERSION VERSION_GREATER "3.11.99" AND NOT CMAKE_CONFIGURATION_TYPES) # Not working with VS generator or older cmake versions
|
||||
include(ECMGeneratePriFile)
|
||||
set(PROJECT_VERSION_STRING ${${PROJECT_NAME}_VERSION})
|
||||
ecm_generate_pri_file(BASE_NAME KDDockWidgets
|
||||
LIB_NAME kddockwidgets
|
||||
DEPS ${${PROJECT_NAME}_DEPS}
|
||||
FILENAME_VAR pri_filename
|
||||
INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
||||
else()
|
||||
message(WARNING "Unable to generate the pri file for qmake users. Try updating CMake.")
|
||||
endif()
|
||||
|
||||
install(FILES LICENSE.txt README.md DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(DIRECTORY LICENSES DESTINATION ${INSTALL_DOC_DIR})
|
||||
|
||||
if(${PROJECT_NAME}_EXAMPLES)
|
||||
if (${PROJECT_NAME}_QTQUICK)
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
add_subdirectory(examples/qtquick)
|
||||
else()
|
||||
add_subdirectory(examples/dockwidgets)
|
||||
add_subdirectory(examples/minimal)
|
||||
set_compiler_flags(kddockwidgets_example)
|
||||
set_compiler_flags(kddockwidgets_minimal_example)
|
||||
add_subdirectory(examples/dockwidgets)
|
||||
add_subdirectory(examples/minimal)
|
||||
add_subdirectory(examples/minimal-mdi)
|
||||
set_compiler_flags(kddockwidgets_example)
|
||||
set_compiler_flags(kddockwidgets_minimal_example)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -213,34 +225,34 @@ if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
add_subdirectory(tests)
|
||||
|
||||
# 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)
|
||||
add_test(NAME tst_docks3 COMMAND tests_launcher 3 5)
|
||||
add_test(NAME tst_docks4 COMMAND tests_launcher 4 5)
|
||||
add_test(NAME tst_docks5 COMMAND tests_launcher 5 5)
|
||||
add_test(NAME tst_docks6 COMMAND tests_launcher 6 5)
|
||||
add_test(NAME tst_docks7 COMMAND tests_launcher 7 5)
|
||||
add_test(NAME tst_docks8 COMMAND tests_launcher 8 5)
|
||||
add_test(NAME tst_docks9 COMMAND tests_launcher 9 5)
|
||||
add_test(NAME tst_docks10 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks11 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks12 COMMAND tests_launcher 11 5)
|
||||
add_test(NAME tst_docks13 COMMAND tests_launcher 12 5)
|
||||
add_test(NAME tst_docks14 COMMAND tests_launcher 13 5)
|
||||
add_test(NAME tst_docks15 COMMAND tests_launcher 14 5)
|
||||
add_test(NAME tst_docks16 COMMAND tests_launcher 15 5)
|
||||
add_test(NAME tst_docks17 COMMAND tests_launcher 16 5)
|
||||
add_test(NAME tst_docks18 COMMAND tests_launcher 17 5)
|
||||
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
|
||||
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)
|
||||
add_test(NAME tst_docks3 COMMAND tests_launcher 3 5)
|
||||
add_test(NAME tst_docks4 COMMAND tests_launcher 4 5)
|
||||
add_test(NAME tst_docks5 COMMAND tests_launcher 5 5)
|
||||
add_test(NAME tst_docks6 COMMAND tests_launcher 6 5)
|
||||
add_test(NAME tst_docks7 COMMAND tests_launcher 7 5)
|
||||
add_test(NAME tst_docks8 COMMAND tests_launcher 8 5)
|
||||
add_test(NAME tst_docks9 COMMAND tests_launcher 9 5)
|
||||
add_test(NAME tst_docks10 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks11 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks12 COMMAND tests_launcher 11 5)
|
||||
add_test(NAME tst_docks13 COMMAND tests_launcher 12 5)
|
||||
add_test(NAME tst_docks14 COMMAND tests_launcher 13 5)
|
||||
add_test(NAME tst_docks15 COMMAND tests_launcher 14 5)
|
||||
add_test(NAME tst_docks16 COMMAND tests_launcher 15 5)
|
||||
add_test(NAME tst_docks17 COMMAND tests_launcher 16 5)
|
||||
add_test(NAME tst_docks18 COMMAND tests_launcher 17 5)
|
||||
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()
|
||||
if (NOT ${PROJECT_NAME}_QTQUICK)
|
||||
# tst_multisplitter depends on QWidget
|
||||
add_test(NAME tst_multisplitter COMMAND tst_multisplitter)
|
||||
if(NOT ${PROJECT_NAME}_QTQUICK)
|
||||
# tst_multisplitter depends on QWidget
|
||||
add_test(NAME tst_multisplitter COMMAND tst_multisplitter)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
@@ -248,8 +260,14 @@ endif()
|
||||
|
||||
if(${PROJECT_NAME}_DOCS)
|
||||
add_subdirectory(docs) # needs to go last, in case there are build source files
|
||||
#don't create the dummy docs target as it can conflict when used as a submodule
|
||||
#else()
|
||||
# add_custom_target(docs
|
||||
# COMMAND ${CMAKE_COMMAND} -E echo "Sorry, there is no docs target since KDDockWidgets_DOCS=OFF."
|
||||
# "Re-run cmake with the -DKDDockWidgets_DOCS=True option if you want to generate the documentation.")
|
||||
endif()
|
||||
|
||||
if (${PROJECT_NAME}_UNITY_BUILD)
|
||||
set_target_properties(kddockwidgets PROPERTIES UNITY_BUILD ON)
|
||||
if(${PROJECT_NAME}_UNINSTALL)
|
||||
# Add uninstall target
|
||||
include(ECMUninstallTarget)
|
||||
endif()
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'"
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"KDDockWidgets_FUZZER" : "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -31,7 +33,8 @@
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-qtwidgets",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -41,7 +44,8 @@
|
||||
"binaryDir": "${sourceDir}/build-qtquick",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_QTQUICK": "ON"
|
||||
"KDDockWidgets_QTQUICK": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -53,7 +57,9 @@
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_QTQUICK": "ON",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'"
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"KDDockWidgets_FUZZER" : "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -63,7 +69,8 @@
|
||||
"binaryDir": "${sourceDir}/build-python",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_PYTHON_BINDINGS": "ON"
|
||||
"KDDockWidgets_PYTHON_BINDINGS": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -73,7 +80,8 @@
|
||||
"binaryDir": "${sourceDir}/build-static-qtwidgets",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_STATIC": "ON"
|
||||
"KDDockWidgets_STATIC": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -84,7 +92,8 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_STATIC": "ON",
|
||||
"KDDockWidgets_QTQUICK": "ON"
|
||||
"KDDockWidgets_QTQUICK": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -94,10 +103,11 @@
|
||||
"binaryDir": "${sourceDir}/build-qtwidgets6",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_QT6": "ON"
|
||||
"KDDockWidgets_QT6": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON"
|
||||
},
|
||||
"environment": {
|
||||
"PATH": "$env{HOME}/Qt/6.0.0/gcc_64/bin:$penv{PATH}"
|
||||
"PATH": "$env{QT6_DIR}/bin:$penv{PATH}"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -109,10 +119,12 @@
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"KDDockWidgets_QT6": "ON",
|
||||
"KDDockWidgets_DEVELOPER_MODE": "ON",
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'"
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON",
|
||||
"ECM_ENABLE_SANITIZERS" : "'address;undefined'",
|
||||
"KDDockWidgets_FUZZER" : "OFF"
|
||||
},
|
||||
"environment": {
|
||||
"PATH": "$env{HOME}/Qt/6.0.0/gcc_64/bin:$penv{PATH}"
|
||||
"PATH": "$env{QT6_DIR}/bin:$penv{PATH}"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -123,10 +135,11 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"KDDockWidgets_QTQUICK": "ON",
|
||||
"KDDockWidgets_QT6": "ON"
|
||||
"KDDockWidgets_QT6": "ON",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS" : "ON"
|
||||
},
|
||||
"environment": {
|
||||
"PATH": "$env{HOME}/Qt/6.0.0/gcc_64/bin:$penv{PATH}"
|
||||
"PATH": "$env{QT6_DIR}/bin:$penv{PATH}"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
3
CONTRIBUTORS.txt
Normal file
3
CONTRIBUTORS.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Christian Riggenbach <criggenbach@magahugu.ch>
|
||||
Jacob Young <amazingjacob@gmail.com>
|
||||
Matthew Waltz <matthewwaltzis@gmail.com>
|
||||
42
Changelog
42
Changelog
@@ -1,12 +1,48 @@
|
||||
* v1.3.0 (unreleased)
|
||||
- [TODO] QtQuick support
|
||||
* v1.4.0 (unreleased)
|
||||
- Experimental MDI support. By using MainWindowMDI you can now have "docked" dock widgets
|
||||
which are free to be arbitrarily positioned and even overlapped inside the main window.
|
||||
- TitleBar's height is now controlled by sizeHint() instead of hardcoded.
|
||||
If you haven't overridden TitleBar or just inheriting from TitleBarWidget then there's nothing to do,
|
||||
as TitleBarWidget already reimplements sizeHint. If you're inheriting directly from TitleBar then make
|
||||
sure to provide a sizeHint.
|
||||
|
||||
* v1.3.1 (unreleased)
|
||||
- Improve restoring layout when RestoreOption_RelativeToMainWindow is used (#171)
|
||||
- Improved dragging windows across screens in mixed hdpi setups
|
||||
- Fixed Flag_NativeTitleBar not hidding the client title bars when restoring (#170)
|
||||
- Double clicking a native title bar of a Qt::Tool window will now redock the window (#173)
|
||||
- Size of FloatingWindow now accounts for the fact that it's using Flag_NativeTitleBar and
|
||||
resizes its content accordingly (#174)
|
||||
- Fixed popups on overlayed dock widgets not working
|
||||
|
||||
* v1.3.0 (8 February 2021)
|
||||
- Experimental QtQuick support (#49)
|
||||
- Added static DockWidgetBase::byName() (#126)
|
||||
- The enum KDDockWidgets::AddingOption has been deprecated, use
|
||||
KDDockWidgets::InitialVisibilityOption instead
|
||||
- You can now pass a preferred initial size to MainWindow::addDockWidget() (#95)
|
||||
- Added DockWidgetBase::Option_DeleteOnClose
|
||||
- Added Config::Flag_CloseOnlyCurrentTab
|
||||
- PySide6 support
|
||||
- Layout restorer now restores maximzied/minimized state too (#81)
|
||||
- Fixed dock indicators sometimes not appearing on Windows (#103)
|
||||
- Fixed Flag_NativeTitleBar not working
|
||||
- Fixed drag offset when dragging too fast with mouse
|
||||
- Fixed bug where last tab index position wouldn't be remembered in case user
|
||||
had manually reordered tabs (#154)
|
||||
- Fixed crash when hosting a QQuickWidget (#150)
|
||||
- Fixed CMake Visual Studio generator not working
|
||||
- Sidebar overlays now maintain their size when toggled (#155)
|
||||
- Added DockWidget::setFloatingGeometry() (#144)
|
||||
|
||||
* v1.2.1 (unreleased)
|
||||
* v1.2.1 (6 February 2021)
|
||||
- Support for resizing dock widgets when they are in overlay/popup mode (autohide/sidebar feature)
|
||||
- Fixed title bar close button enabled state not being restored with Layout saver (#137)
|
||||
- Installs a version header (kddockwidgets_version.h) that defines a version string and other useful versioning macros (#138)
|
||||
- DockWidgetBase::eventFilter() is protected instead of private (regression vs v1.1) (#148)
|
||||
It's recommended that you rebuild your application when updating KDDW, as MSVC encodes private/protected in the name mangling.
|
||||
- Fixed WASM build on Windows (#163)
|
||||
- Fixed sidebar overlay not getting hidden when clicking on the main window docking area (#157)
|
||||
|
||||
* v1.2.0 (17 December 2020)
|
||||
- Wayland support
|
||||
|
||||
62
README.md
62
README.md
@@ -29,7 +29,7 @@ however that this demo isn't fully featured, as it's running on Qt for WebAssemb
|
||||
|
||||
Features
|
||||
========
|
||||
- Provide advanced docking that QDockWidgets doesn't support
|
||||
- Provide advanced docking that QDockWidget doesn't support
|
||||
- Native window resize on Windows (allowing for Aero-snap even with custom title bar decorations)
|
||||
- Arrow drop indicators for great drop precision
|
||||
- Allow for totally different, user provided, drop indicator types
|
||||
@@ -46,13 +46,13 @@ Features
|
||||
- Customize title bars
|
||||
- Customize window frames
|
||||
- Custom widget separators
|
||||
- Crossplatform (macOS, Linux, Windows, WebAssembly, Wayland, X11/XCB, EGLFS are working)
|
||||
- Cross-platform (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
|
||||
- Not mixing GUI with state with logic with animations
|
||||
- Great test coverage, even the gui and DnD operations are tested. 200 tests currently.
|
||||
- Great test coverage, even the GUI and DnD operations are tested. 200 tests currently.
|
||||
- Fuzzer for doing random testing and finding bugs
|
||||
- Lazy separator resize
|
||||
- Reordering tabs with mouse
|
||||
@@ -75,10 +75,10 @@ Roadmap
|
||||
|
||||
Trying out the examples
|
||||
=======================
|
||||
A full demo lives in `examples/dockwidgets/`, it showcasts most of the features.
|
||||
A simpler example lives in `examples/minimal/`, which might be more indicated
|
||||
to learn the API, as it's less overwelming than the full demo.
|
||||
A full demo that showcases most of the features lives in [examples/dockwidgets](examples/dockwidgets).
|
||||
|
||||
A simpler example can be found in [examples/minimal](examples/minimal),
|
||||
which might be more indicated to learn the API, as it's less overwhelming than the full demo.
|
||||
|
||||
Open a terminal capable of building Qt5 applications.
|
||||
Make sure you have cmake, ninja, compiler, Qt, etc in PATH.
|
||||
@@ -93,23 +93,26 @@ $ cmake --build . --target install
|
||||
```
|
||||
|
||||
Now build and run the example:
|
||||
|
||||
```
|
||||
$ cd path/to/kddockwidgets/examples/dockwidgets/
|
||||
$ cmake -G Ninja -DCMAKE_PREFIX_PATH=/path/where/to/install
|
||||
$ cmake --build .
|
||||
$ ./kddockwidgets_example
|
||||
|
||||
```
|
||||
|
||||
The installation directory defaults to `c:\KDAB\KDDockWidgets-<version>` on Windows
|
||||
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.
|
||||
and `/usr/local/KDAB/KDDockWidgets-<version>` on non-Windows.
|
||||
|
||||
You can change the installation 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)
|
||||
@@ -120,7 +123,7 @@ on where you installed KDDockWidgets.
|
||||
|
||||
Python Bindings
|
||||
================
|
||||
Make sure you have pyside2, shiboken2 and shiboken2-generator installed.
|
||||
Make sure you have PySide2, shiboken2 and shiboken2-generator installed.
|
||||
As this time, you cannot get shiboken2-generator because the wheels are not on PyPi.
|
||||
To use the wheels do this:
|
||||
|
||||
@@ -133,8 +136,8 @@ To use the wheels do this:
|
||||
|
||||
For more info visit https://doc.qt.io/qtforpython/shiboken2/gettingstarted.html
|
||||
|
||||
Once QtForPython is installed you are ready to generate the PySide bindings
|
||||
for KDDockwWidgets.
|
||||
Once QtForPython is installed you are ready to generate the PySide2 bindings
|
||||
for KDDockWidgets.
|
||||
|
||||
Next pass `-DKDDockWidgets_PYTHON_BINDINGS=ON` to CMake, followed by the
|
||||
make command.
|
||||
@@ -146,6 +149,7 @@ by passing `-DKDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX=/usr/lib/python3.8/si
|
||||
to CMake (adjust to the python path on your system).
|
||||
|
||||
To run the KDDW python example
|
||||
|
||||
```
|
||||
$ export PYTHONPATH=/kddw/install/path # Only if needed
|
||||
$ cd python/examples/
|
||||
@@ -153,6 +157,20 @@ $ rcc -g python -o rc_assets.py ../../examples/dockwidgets/resources_example.qrc
|
||||
$ python3 main.py
|
||||
```
|
||||
|
||||
Versioning
|
||||
==========
|
||||
|
||||
New features go to master while the stable branch only accepts non-intrusive bug fixes.
|
||||
|
||||
We'll try to remain source-compatible across versions. API will get a deprecation
|
||||
notice before being removed in the next version. Note that this source-compatibility
|
||||
effort is only for the public API. Private API (headers ending in _p.h) might change so you
|
||||
shouldn't depend on them. Private API is only exposed so more advanced users can
|
||||
override, for example `paintEvent()`, and not so they can change internal business logic.
|
||||
|
||||
We don't promise or test binary compatibility. It's advised that you recompile
|
||||
your application whenever updating KDDW.
|
||||
|
||||
|
||||
Supported Qt versions and toolchains
|
||||
=====================================
|
||||
@@ -174,14 +192,26 @@ Contact KDAB at <info@kdab.com> to inquire about commercial licensing.
|
||||
|
||||
Get Involved
|
||||
============
|
||||
Please submit your issue reports to our GitHub space at
|
||||
https://github.com/KDAB/KDDockWidgets
|
||||
|
||||
|
||||
When reporting bugs please make it easy for the maintainer to reproduce it. Use `examples/minimal/` or
|
||||
`examples/dockwidgets/` for reproducing the problem. If you did modifications to the example in order to
|
||||
reproduce then please attach the *patch* and not a picture of your changes. You can get a patch by doing
|
||||
`git diff > repro.diff` at the repo root.
|
||||
|
||||
Also state which KDDW sha1, branch or version you're using, and which operating system.
|
||||
|
||||
|
||||
KDAB will happily accept external contributions; however, **all** contributions require a
|
||||
signed [Copyright Assignment Agreement](docs/KDDockWidgets-CopyrightAssignmentForm.docx).
|
||||
signed [Copyright Assignment Agreement](docs/KDDockWidgets-CopyrightAssignmentForm.pdf).
|
||||
|
||||
This is needed so we can continue to dual-license it.
|
||||
|
||||
Contact info@kdab.com for more information.
|
||||
|
||||
Please submit your contributions or issue reports from our GitHub space at
|
||||
https://github.com/KDAB/KDDockWidgets
|
||||
|
||||
Thanks to our [contributors](CONTRIBUTORS.txt).
|
||||
|
||||
About KDAB
|
||||
==========
|
||||
|
||||
@@ -160,7 +160,6 @@ function(ECM_GENERATE_PRI_FILE)
|
||||
else()
|
||||
set(PRI_TARGET_LIBS "${BASEPATH}/${EGPF_LIB_INSTALL_DIR}")
|
||||
endif()
|
||||
set(PRI_TARGET_DEFINES "")
|
||||
|
||||
set(PRI_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/qt_${PRI_TARGET_BASENAME}.pri)
|
||||
if (EGPF_FILENAME_VAR)
|
||||
@@ -168,6 +167,8 @@ function(ECM_GENERATE_PRI_FILE)
|
||||
endif()
|
||||
|
||||
set(PRI_TARGET_MODULE_CONFIG "")
|
||||
set(PRI_TARGET_DEFINES "")
|
||||
set(PRI_TARGET_POSTFIX "")
|
||||
# backward compat: it was not obvious LIB_NAME needs to be a target name,
|
||||
# and some projects where the target name was not the actual library output name
|
||||
# passed the output name for LIB_NAME, so .name & .module prperties are correctly set.
|
||||
@@ -177,6 +178,10 @@ function(ECM_GENERATE_PRI_FILE)
|
||||
if (target_type STREQUAL "STATIC_LIBRARY")
|
||||
set(PRI_TARGET_MODULE_CONFIG "staticlib")
|
||||
endif()
|
||||
get_target_property(target_defs ${EGPF_LIB_NAME} INTERFACE_COMPILE_DEFINITIONS)
|
||||
list(FILTER target_defs EXCLUDE REGEX ^QT_)
|
||||
string(JOIN " " PRI_TARGET_DEFINES "${target_defs}")
|
||||
set(PRI_TARGET_POSTFIX "$<TARGET_PROPERTY:${EGPF_LIB_NAME},$<UPPER_CASE:$<CONFIG>$<$<CONFIG:>:Debug>>_POSTFIX>")
|
||||
endif()
|
||||
|
||||
file(GENERATE
|
||||
@@ -187,8 +192,8 @@ QT.${PRI_TARGET_BASENAME}.MAJOR_VERSION = ${PROJECT_VERSION_MAJOR}
|
||||
QT.${PRI_TARGET_BASENAME}.MINOR_VERSION = ${PROJECT_VERSION_MINOR}
|
||||
QT.${PRI_TARGET_BASENAME}.PATCH_VERSION = ${PROJECT_VERSION_PATCH}
|
||||
QT.${PRI_TARGET_BASENAME}.name = ${PRI_TARGET_LIBNAME}
|
||||
QT.${PRI_TARGET_BASENAME}.module = ${PRI_TARGET_LIBNAME}
|
||||
QT.${PRI_TARGET_BASENAME}.defines = ${PRI_TARGET_DEFINES}
|
||||
QT.${PRI_TARGET_BASENAME}.module = ${PRI_TARGET_LIBNAME}${PRI_TARGET_POSTFIX}
|
||||
QT.${PRI_TARGET_BASENAME}.DEFINES = ${PRI_TARGET_DEFINES}
|
||||
QT.${PRI_TARGET_BASENAME}.includes = ${PRI_TARGET_INCLUDES}
|
||||
QT.${PRI_TARGET_BASENAME}.private_includes =
|
||||
QT.${PRI_TARGET_BASENAME}.libs = ${PRI_TARGET_LIBS}
|
||||
|
||||
202
cmake/ECM/modules/ECMSetupVersion.cmake
Normal file
202
cmake/ECM/modules/ECMSetupVersion.cmake
Normal file
@@ -0,0 +1,202 @@
|
||||
#.rst:
|
||||
# ECMSetupVersion
|
||||
# ---------------
|
||||
#
|
||||
# Handle library version information.
|
||||
#
|
||||
# ::
|
||||
#
|
||||
# ecm_setup_version(<version>
|
||||
# VARIABLE_PREFIX <prefix>
|
||||
# [SOVERSION <soversion>]
|
||||
# [VERSION_HEADER <filename>]
|
||||
# [PACKAGE_VERSION_FILE <filename> [COMPATIBILITY <compat>]] )
|
||||
#
|
||||
# This parses a version string and sets up a standard set of version variables.
|
||||
# It can optionally also create a C version header file and a CMake package
|
||||
# version file to install along with the library.
|
||||
#
|
||||
# If the ``<version>`` argument is of the form ``<major>.<minor>.<patch>``
|
||||
# (or ``<major>.<minor>.<patch>.<tweak>``), The following CMake variables are
|
||||
# set::
|
||||
#
|
||||
# <prefix>_VERSION_MAJOR - <major>
|
||||
# <prefix>_VERSION_MINOR - <minor>
|
||||
# <prefix>_VERSION_PATCH - <patch>
|
||||
# <prefix>_VERSION - <version>
|
||||
# <prefix>_VERSION_STRING - <version> (for compatibility: use <prefix>_VERSION instead)
|
||||
# <prefix>_SOVERSION - <soversion>, or <major> if SOVERSION was not given
|
||||
#
|
||||
# If CMake policy CMP0048 is not NEW, the following CMake variables will also
|
||||
# be set::
|
||||
#
|
||||
# PROJECT_VERSION_MAJOR - <major>
|
||||
# PROJECT_VERSION_MINOR - <minor>
|
||||
# PROJECT_VERSION_PATCH - <patch>
|
||||
# PROJECT_VERSION - <version>
|
||||
# PROJECT_VERSION_STRING - <version> (for compatibility: use PROJECT_VERSION instead)
|
||||
#
|
||||
# If the VERSION_HEADER option is used, a simple C header is generated with the
|
||||
# given filename. If filename is a relative path, it is interpreted as relative
|
||||
# to CMAKE_CURRENT_BINARY_DIR. The generated header contains the following
|
||||
# macros::
|
||||
#
|
||||
# <prefix>_VERSION_MAJOR - <major> as an integer
|
||||
# <prefix>_VERSION_MINOR - <minor> as an integer
|
||||
# <prefix>_VERSION_PATCH - <patch> as an integer
|
||||
# <prefix>_VERSION_STRING - <version> as a C string
|
||||
# <prefix>_VERSION - the version as an integer
|
||||
#
|
||||
# ``<prefix>_VERSION`` has ``<patch>`` in the bottom 8 bits, ``<minor>`` in the
|
||||
# next 8 bits and ``<major>`` in the remaining bits. Note that ``<patch>`` and
|
||||
# ``<minor>`` must be less than 256.
|
||||
#
|
||||
# If the PACKAGE_VERSION_FILE option is used, a simple CMake package version
|
||||
# file is created using the write_basic_package_version_file() macro provided by
|
||||
# CMake. It should be installed in the same location as the Config.cmake file of
|
||||
# the library so that it can be found by find_package(). If the filename is a
|
||||
# relative path, it is interpreted as relative to CMAKE_CURRENT_BINARY_DIR. The
|
||||
# optional COMPATIBILITY option is forwarded to
|
||||
# write_basic_package_version_file(), and defaults to AnyNewerVersion.
|
||||
#
|
||||
# If CMake policy CMP0048 is NEW, an alternative form of the command is
|
||||
# available::
|
||||
#
|
||||
# ecm_setup_version(PROJECT
|
||||
# [VARIABLE_PREFIX <prefix>]
|
||||
# [SOVERSION <soversion>]
|
||||
# [VERSION_HEADER <filename>]
|
||||
# [PACKAGE_VERSION_FILE <filename>] )
|
||||
#
|
||||
# This will use the version information set by the project() command.
|
||||
# VARIABLE_PREFIX defaults to the project name. Note that PROJECT must be the
|
||||
# first argument. In all other respects, it behaves like the other form of the
|
||||
# command.
|
||||
#
|
||||
# Since pre-1.0.0.
|
||||
#
|
||||
# COMPATIBILITY option available since 1.6.0.
|
||||
|
||||
#=============================================================================
|
||||
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
|
||||
# SPDX-FileCopyrightText: 2012 Alexander Neundorf <neundorf@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
# save the location of the header template while CMAKE_CURRENT_LIST_DIR
|
||||
# has the value we want
|
||||
set(_ECM_SETUP_VERSION_HEADER_TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/ECMVersionHeader.h.in")
|
||||
|
||||
function(ecm_setup_version _version)
|
||||
set(options )
|
||||
set(oneValueArgs VARIABLE_PREFIX SOVERSION VERSION_HEADER PACKAGE_VERSION_FILE COMPATIBILITY)
|
||||
set(multiValueArgs )
|
||||
|
||||
cmake_parse_arguments(ESV "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(ESV_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown keywords given to ECM_SETUP_VERSION(): \"${ESV_UNPARSED_ARGUMENTS}\"")
|
||||
endif()
|
||||
|
||||
set(project_manages_version FALSE)
|
||||
set(use_project_version FALSE)
|
||||
# CMP0048 only exists in CMake 3.0.0 and later
|
||||
if(CMAKE_VERSION VERSION_LESS 3.0.0)
|
||||
set(project_version_policy "OLD")
|
||||
else()
|
||||
cmake_policy(GET CMP0048 project_version_policy)
|
||||
endif()
|
||||
if(project_version_policy STREQUAL "NEW")
|
||||
set(project_manages_version TRUE)
|
||||
if(_version STREQUAL "PROJECT")
|
||||
set(use_project_version TRUE)
|
||||
endif()
|
||||
elseif(_version STREQUAL "PROJECT")
|
||||
message(FATAL_ERROR "ecm_setup_version given PROJECT argument, but CMP0048 is not NEW")
|
||||
endif()
|
||||
|
||||
set(should_set_prefixed_vars TRUE)
|
||||
if(NOT ESV_VARIABLE_PREFIX)
|
||||
if(use_project_version)
|
||||
set(ESV_VARIABLE_PREFIX "${PROJECT_NAME}")
|
||||
set(should_set_prefixed_vars FALSE)
|
||||
else()
|
||||
message(FATAL_ERROR "Required argument PREFIX missing in ECM_SETUP_VERSION() call")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(use_project_version)
|
||||
set(_version "${PROJECT_VERSION}")
|
||||
set(_major "${PROJECT_VERSION_MAJOR}")
|
||||
set(_minor "${PROJECT_VERSION_MINOR}")
|
||||
set(_patch "${PROJECT_VERSION_PATCH}")
|
||||
else()
|
||||
string(REGEX REPLACE "^0*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" _major "${_version}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.0*([0-9]+)\\.[0-9]+.*" "\\1" _minor "${_version}")
|
||||
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.0*([0-9]+).*" "\\1" _patch "${_version}")
|
||||
endif()
|
||||
|
||||
if(NOT ESV_SOVERSION)
|
||||
set(ESV_SOVERSION ${_major})
|
||||
endif()
|
||||
|
||||
if(should_set_prefixed_vars)
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION "${_version}")
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_MAJOR ${_major})
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_MINOR ${_minor})
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_PATCH ${_patch})
|
||||
endif()
|
||||
|
||||
set(${ESV_VARIABLE_PREFIX}_SOVERSION ${ESV_SOVERSION})
|
||||
|
||||
if(NOT project_manages_version)
|
||||
set(PROJECT_VERSION "${_version}")
|
||||
set(PROJECT_VERSION_MAJOR "${_major}")
|
||||
set(PROJECT_VERSION_MINOR "${_minor}")
|
||||
set(PROJECT_VERSION_PATCH "${_patch}")
|
||||
endif()
|
||||
|
||||
# compat
|
||||
set(PROJECT_VERSION_STRING "${PROJECT_VERSION}")
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_STRING "${${ESV_VARIABLE_PREFIX}_VERSION}")
|
||||
|
||||
if(ESV_VERSION_HEADER)
|
||||
set(HEADER_PREFIX "${ESV_VARIABLE_PREFIX}")
|
||||
set(HEADER_VERSION "${_version}")
|
||||
set(HEADER_VERSION_MAJOR "${_major}")
|
||||
set(HEADER_VERSION_MINOR "${_minor}")
|
||||
set(HEADER_VERSION_PATCH "${_patch}")
|
||||
configure_file("${_ECM_SETUP_VERSION_HEADER_TEMPLATE}" "${ESV_VERSION_HEADER}")
|
||||
endif()
|
||||
|
||||
if(ESV_PACKAGE_VERSION_FILE)
|
||||
if(NOT ESV_COMPATIBILITY)
|
||||
set(ESV_COMPATIBILITY AnyNewerVersion)
|
||||
endif()
|
||||
write_basic_package_version_file("${ESV_PACKAGE_VERSION_FILE}" VERSION ${_version} COMPATIBILITY ${ESV_COMPATIBILITY})
|
||||
endif()
|
||||
|
||||
if(should_set_prefixed_vars)
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_MAJOR "${${ESV_VARIABLE_PREFIX}_VERSION_MAJOR}" PARENT_SCOPE)
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_MINOR "${${ESV_VARIABLE_PREFIX}_VERSION_MINOR}" PARENT_SCOPE)
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_PATCH "${${ESV_VARIABLE_PREFIX}_VERSION_PATCH}" PARENT_SCOPE)
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION "${${ESV_VARIABLE_PREFIX}_VERSION}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# always set the soversion
|
||||
set(${ESV_VARIABLE_PREFIX}_SOVERSION "${${ESV_VARIABLE_PREFIX}_SOVERSION}" PARENT_SCOPE)
|
||||
|
||||
if(NOT project_manages_version)
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION}" PARENT_SCOPE)
|
||||
set(PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}" PARENT_SCOPE)
|
||||
set(PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}" PARENT_SCOPE)
|
||||
set(PROJECT_VERSION_PATCH "${PROJECT_VERSION_PATCH}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# always set the compatibility variables
|
||||
set(PROJECT_VERSION_STRING "${PROJECT_VERSION_STRING}" PARENT_SCOPE)
|
||||
set(${ESV_VARIABLE_PREFIX}_VERSION_STRING "${${ESV_VARIABLE_PREFIX}_VERSION}" PARENT_SCOPE)
|
||||
|
||||
endfunction()
|
||||
50
cmake/ECM/modules/ECMUninstallTarget.cmake
Normal file
50
cmake/ECM/modules/ECMUninstallTarget.cmake
Normal file
@@ -0,0 +1,50 @@
|
||||
#.rst:
|
||||
# ECMUninstallTarget
|
||||
# ------------------
|
||||
#
|
||||
# Add an ``uninstall`` target.
|
||||
#
|
||||
# By including this module, an ``uninstall`` target will be added to your CMake
|
||||
# project. This will remove all files installed (or updated) by a previous
|
||||
# invocation of the ``install`` target. It will not remove files created or
|
||||
# modified by an ``install(SCRIPT)`` or ``install(CODE)`` command; you should
|
||||
# create a custom uninstallation target for these and use ``add_dependency`` to
|
||||
# make the ``uninstall`` target depend on it:
|
||||
#
|
||||
# .. code-block:: cmake
|
||||
#
|
||||
# include(ECMUninstallTarget)
|
||||
# install(SCRIPT install-foo.cmake)
|
||||
# add_custom_target(uninstall_foo COMMAND ${CMAKE_COMMAND} -P uninstall-foo.cmake)
|
||||
# add_dependency(uninstall uninstall_foo)
|
||||
#
|
||||
# The target will fail if the ``install`` target has not yet been run (so it is
|
||||
# not possible to run CMake on the project and then immediately run the
|
||||
# ``uninstall`` target).
|
||||
#
|
||||
# .. warning::
|
||||
#
|
||||
# CMake deliberately does not provide an ``uninstall`` target by default on
|
||||
# the basis that such a target has the potential to remove important files
|
||||
# from a user's computer. Use with caution.
|
||||
#
|
||||
# Since 1.7.0.
|
||||
|
||||
#=============================================================================
|
||||
# SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if (NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_LIST_DIR}/ecm_uninstall.cmake.in"
|
||||
"${CMAKE_BINARY_DIR}/ecm_uninstall.cmake"
|
||||
IMMEDIATE
|
||||
@ONLY
|
||||
)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_BINARY_DIR}/ecm_uninstall.cmake"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
|
||||
)
|
||||
endif()
|
||||
17
cmake/ECM/modules/ECMVersionHeader.h.in
Normal file
17
cmake/ECM/modules/ECMVersionHeader.h.in
Normal file
@@ -0,0 +1,17 @@
|
||||
// This file was generated by ecm_setup_version(): DO NOT EDIT!
|
||||
|
||||
#ifndef @HEADER_PREFIX@_VERSION_H
|
||||
#define @HEADER_PREFIX@_VERSION_H
|
||||
|
||||
#define @HEADER_PREFIX@_VERSION_STRING "@HEADER_VERSION@"
|
||||
#define @HEADER_PREFIX@_VERSION_MAJOR @HEADER_VERSION_MAJOR@
|
||||
#define @HEADER_PREFIX@_VERSION_MINOR @HEADER_VERSION_MINOR@
|
||||
#define @HEADER_PREFIX@_VERSION_PATCH @HEADER_VERSION_PATCH@
|
||||
#define @HEADER_PREFIX@_VERSION @HEADER_PREFIX@_VERSION_CHECK(@HEADER_PREFIX@_VERSION_MAJOR, @HEADER_PREFIX@_VERSION_MINOR, @HEADER_PREFIX@_VERSION_PATCH)
|
||||
|
||||
/*
|
||||
for example: @HEADER_PREFIX@_VERSION >= @HEADER_PREFIX@_VERSION_CHECK(1, 2, 2))
|
||||
*/
|
||||
#define @HEADER_PREFIX@_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
|
||||
|
||||
#endif
|
||||
21
cmake/ECM/modules/ecm_uninstall.cmake.in
Normal file
21
cmake/ECM/modules/ecm_uninstall.cmake.in
Normal file
@@ -0,0 +1,21 @@
|
||||
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
endif()
|
||||
|
||||
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||
foreach(file ${files})
|
||||
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
||||
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
exec_program(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
if(NOT "${rm_retval}" STREQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
||||
endif()
|
||||
endforeach()
|
||||
43
code.dev-qtquick.code-workspace
Normal file
43
code.dev-qtquick.code-workspace
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"C_Cpp.default.compileCommands": "${workspaceFolder}/build-dev-qtquick/compile_commands.json",
|
||||
"C_Cpp.default.cStandard": "c17",
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"editor.formatOnType": true
|
||||
},
|
||||
"tasks": {
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "cmake",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--preset=dev-qtquick"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "make",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--build",
|
||||
"${workspaceFolder}/build-dev-qtquick"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/"
|
||||
},
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
43
code.dev-qtwidgets.code-workspace
Normal file
43
code.dev-qtwidgets.code-workspace
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"C_Cpp.default.compileCommands": "${workspaceFolder}/build-dev-qtwidgets/compile_commands.json",
|
||||
"C_Cpp.default.cStandard": "c17",
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"editor.formatOnType": true
|
||||
},
|
||||
"tasks": {
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "cmake",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--preset=dev-qtwidgets"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "make",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--build",
|
||||
"${workspaceFolder}/build-dev-qtwidgets"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/"
|
||||
},
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
43
code.dev-qtwidgets6.code-workspace
Normal file
43
code.dev-qtwidgets6.code-workspace
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"C_Cpp.default.compileCommands": "${workspaceFolder}/build-dev-qtwidgets6/compile_commands.json",
|
||||
"C_Cpp.default.cStandard": "c17",
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"editor.formatOnType": true
|
||||
},
|
||||
"tasks": {
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "cmake",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--preset=dev-qtwidgets6"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "make",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--build",
|
||||
"${workspaceFolder}/build-dev-qtwidgets6"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/"
|
||||
},
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,9 @@ Configuration options:
|
||||
* build_examples
|
||||
Build the examples. Default=True
|
||||
|
||||
* builde_python_bindings
|
||||
* build_python_bindings
|
||||
Build/Generate python bindings (always false for Debug or static builds). Default=False
|
||||
|
||||
* build_for_qt6
|
||||
Build against Qt6 rather than Qt5. Default=false (Qt5 will be used even if Qt6 is available)
|
||||
(Make sure the Qt6 bin directory is found in your execute PATH)
|
||||
|
||||
@@ -11,7 +11,7 @@ from conans import ConanFile, CMake, tools
|
||||
|
||||
class KDDockWidgetsConan(ConanFile):
|
||||
name = "kddockwidgets"
|
||||
version = "1.2.0"
|
||||
version = "1.3.1"
|
||||
default_user = "kdab"
|
||||
default_channel = "stable"
|
||||
license = ("https://raw.githubusercontent.com/KDAB/KDDockWidgets/master/LICENSES/GPL-2.0-only.txt",
|
||||
@@ -28,6 +28,7 @@ class KDDockWidgetsConan(ConanFile):
|
||||
"build_examples": [True, False],
|
||||
"build_tests": [True, False],
|
||||
"build_python_bindings": [True, False],
|
||||
"build_for_qt6": [True, False],
|
||||
}
|
||||
|
||||
default_options = {
|
||||
@@ -36,6 +37,7 @@ class KDDockWidgetsConan(ConanFile):
|
||||
"build_examples": True,
|
||||
"build_tests": False,
|
||||
"build_python_bindings": False,
|
||||
"build_for_qt6": False,
|
||||
}
|
||||
|
||||
def requirements(self):
|
||||
@@ -52,6 +54,7 @@ class KDDockWidgetsConan(ConanFile):
|
||||
self.cmake.definitions["KDDockWidgets_EXAMPLES"] = self.options.build_examples
|
||||
self.cmake.definitions["KDDockWidgets_TESTS"] = self.options.build_tests
|
||||
self.cmake.definitions["KDDockWidgets_PYTHON_BINDINGS"] = self.options.build_python_bindings
|
||||
self.cmake.definitions["KDDockWidgets_QT6"] = self.options.build_for_qt6
|
||||
self.cmake.configure()
|
||||
self.cmake.build()
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
kddockwidgets (1.3.0) release candidate; urgency=high
|
||||
|
||||
* 1.3.0 final
|
||||
|
||||
-- Allen Winter <allen.winter@kdab.com> Mon, 08 Feb 2021 15:00:00 -0500
|
||||
|
||||
kddockwidgets (1.2.0) release candidate; urgency=high
|
||||
|
||||
* 1.2.0 final
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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> [--unity] [--tests]
|
||||
*/
|
||||
|
||||
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;
|
||||
Preset.fromJson(var jsonData)
|
||||
: name = jsonData['name'],
|
||||
buildDir = jsonData['binaryDir'] {
|
||||
}
|
||||
|
||||
String buildDirectory() {
|
||||
return buildDir.replaceAll("\${sourceDir}", s_sourceDirectory);
|
||||
}
|
||||
|
||||
List<String> cmakeConfigArguments(bool isUnityBuild) {
|
||||
return [
|
||||
"-G",
|
||||
"Ninja",
|
||||
"-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] [--tests]");
|
||||
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;
|
||||
}
|
||||
Binary file not shown.
BIN
docs/KDDockWidgets-CopyrightAssignmentForm.pdf
Normal file
BIN
docs/KDDockWidgets-CopyrightAssignmentForm.pdf
Normal file
Binary file not shown.
@@ -32,9 +32,17 @@ add_custom_command(
|
||||
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_CURRENT_SOURCE_DIR}/../../screencap.gif ${DOXYGEN_OUTPUT_DIR}/html
|
||||
#copy some files by-hand that are referred to by the markdown README
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR}/html/LICENSES
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/LICENSES/GPL-2.0-only.txt ${DOXYGEN_OUTPUT_DIR}/html/LICENSES
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/LICENSES/GPL-3.0-only.txt ${DOXYGEN_OUTPUT_DIR}/html/LICENSES
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIR}/html/docs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/docs/KDDockWidgets-CopyrightAssignmentForm.pdf ${DOXYGEN_OUTPUT_DIR}/html/docs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/examples ${DOXYGEN_OUTPUT_DIR}/html/examples
|
||||
DEPENDS ${_dox_deps} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
add_custom_target(kddockwidgets-api.qch ALL DEPENDS ${DOXYGEN_OUTPUT_DIR}/qch/kddockwidgets-api.qch)
|
||||
add_custom_target(docs DEPENDS kddockwidgets-api.qch)
|
||||
|
||||
install(FILES ${DOXYGEN_OUTPUT_DIR}/qch/kddockwidgets-api.qch DESTINATION ${INSTALL_DOC_DIR})
|
||||
|
||||
@@ -261,7 +261,7 @@ TAB_SIZE = 8
|
||||
# commands \{ and \} for these it is advised to use the version @{ and @} or use
|
||||
# a double escape (\\{ and \\})
|
||||
|
||||
ALIASES =
|
||||
ALIASES = "reimp=Reimplemented for internal purposes.\n"
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||
# only. Doxygen will then generate output that is more tailored for C. For
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
#include "MyFrameworkWidgetFactory.h"
|
||||
|
||||
#include <kddockwidgets/FrameworkWidgetFactory.h>
|
||||
|
||||
#include <kddockwidgets/private/TabWidget_p.h>
|
||||
#include <kddockwidgets/private/widgets/FrameWidget_p.h>
|
||||
#include <kddockwidgets/private/widgets/TabBarWidget_p.h>
|
||||
#include <kddockwidgets/private/widgets/TabWidgetWidget_p.h>
|
||||
#include <kddockwidgets/private/widgets/TitleBarWidget_p.h>
|
||||
#include <kddockwidgets/private/multisplitter/Separator_qwidget.h>
|
||||
|
||||
|
||||
@@ -52,13 +52,14 @@ static MyWidget *newMyWidget()
|
||||
|
||||
MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
|
||||
bool maxSizeForDockWidget8,
|
||||
bool maxSizeForDockWidget8, bool dockwidget5DoesntCloseBeforeRestore,
|
||||
const QString &affinityName, QWidget *parent)
|
||||
: MainWindow(uniqueName, options, parent)
|
||||
, m_dockWidget0IsNonClosable(dockWidget0IsNonClosable)
|
||||
, m_dockWidget9IsNonDockable(nonDockableDockWidget9)
|
||||
, m_restoreIsRelative(restoreIsRelative)
|
||||
, m_maxSizeForDockWidget8(maxSizeForDockWidget8)
|
||||
, m_dockwidget5DoesntCloseBeforeRestore(dockwidget5DoesntCloseBeforeRestore)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
|
||||
qsrand(time(nullptr));
|
||||
@@ -133,7 +134,6 @@ void MyMainWindow::createDockWidgets()
|
||||
for (int i = 0; i < numDockWidgets; i++)
|
||||
m_dockwidgets << newDockWidget();
|
||||
|
||||
|
||||
// MainWindow::addDockWidget() attaches a dock widget to the main window:
|
||||
addDockWidget(m_dockwidgets.at(0), KDDockWidgets::Location_OnTop);
|
||||
|
||||
@@ -164,13 +164,18 @@ KDDockWidgets::DockWidgetBase *MyMainWindow::newDockWidget()
|
||||
|
||||
// Passing options is optional, we just want to illustrate Option_NotClosable here
|
||||
KDDockWidgets::DockWidget::Options options = KDDockWidgets::DockWidget::Option_None;
|
||||
KDDockWidgets::DockWidget::LayoutSaverOptions layoutSaverOptions = KDDockWidgets::DockWidget::LayoutSaverOption::None;
|
||||
|
||||
if (count == 0 && m_dockWidget0IsNonClosable)
|
||||
options |= KDDockWidgets::DockWidget::Option_NotClosable;
|
||||
|
||||
if (count == 9 && m_dockWidget9IsNonDockable)
|
||||
options |= KDDockWidgets::DockWidget::Option_NotDockable;
|
||||
|
||||
auto dock = new KDDockWidgets::DockWidget(QStringLiteral("DockWidget #%1").arg(count), options);
|
||||
if (count == 5 && m_dockwidget5DoesntCloseBeforeRestore)
|
||||
layoutSaverOptions |= KDDockWidgets::DockWidget::LayoutSaverOption::Skip;
|
||||
|
||||
auto dock = new KDDockWidgets::DockWidget(QStringLiteral("DockWidget #%1").arg(count), options, layoutSaverOptions);
|
||||
dock->setAffinities(affinities()); // optional, just to show the feature. Pass -mi to the example to see incompatible dock widgets
|
||||
|
||||
if (count == 1)
|
||||
@@ -192,6 +197,7 @@ KDDockWidgets::DockWidgetBase *MyMainWindow::newDockWidget()
|
||||
|
||||
dock->resize(600, 600);
|
||||
m_toggleMenu->addAction(dock->toggleAction());
|
||||
dock->toggleAction()->setShortcut(QStringLiteral("ctrl+%1").arg(count));
|
||||
|
||||
count++;
|
||||
return dock;
|
||||
|
||||
@@ -20,7 +20,7 @@ class MyMainWindow : public KDDockWidgets::MainWindow
|
||||
public:
|
||||
explicit MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
|
||||
bool maxSizeForDockWidget8,
|
||||
bool maxSizeForDockWidget8, bool dockwidget5DoesntCloseBeforeRestore,
|
||||
const QString &affinityName = {}, // Usually not needed. Just here to show the feature.
|
||||
QWidget *parent = nullptr);
|
||||
~MyMainWindow() override;
|
||||
@@ -33,5 +33,6 @@ private:
|
||||
const bool m_dockWidget9IsNonDockable;
|
||||
const bool m_restoreIsRelative;
|
||||
const bool m_maxSizeForDockWidget8;
|
||||
const bool m_dockwidget5DoesntCloseBeforeRestore;
|
||||
KDDockWidgets::DockWidget::List m_dockwidgets;
|
||||
};
|
||||
|
||||
@@ -111,6 +111,14 @@ int main(int argc, char **argv)
|
||||
QCommandLineOption autoHideSupport("w", QCoreApplication::translate("main", "Enables auto-hide/minimization to side-bar support"));
|
||||
parser.addOption(autoHideSupport);
|
||||
|
||||
QCommandLineOption closeOnlyCurrentTab("close-only-current-tab",
|
||||
QCoreApplication::translate("main", "The title bar's close button will only close the current tab instead of all. Illustrates using Config::Flag_CloseOnlyCurrentTab"));
|
||||
parser.addOption(closeOnlyCurrentTab);
|
||||
|
||||
QCommandLineOption dontCloseBeforeRestore("dont-close-widget-before-restore", //krazy:exclude=spelling
|
||||
QCoreApplication::translate("main", "DockWidget #5 wont be closed before a restore. Illustrates LayoutSaverOption::DontCloseBeforeRestore"));
|
||||
parser.addOption(dontCloseBeforeRestore);
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
parser.addOption(centralFrame);
|
||||
|
||||
@@ -177,6 +185,9 @@ int main(int argc, char **argv)
|
||||
if (parser.isSet(autoHideSupport))
|
||||
flags |= Config::Flag_AutoHideSupport;
|
||||
|
||||
if (parser.isSet(closeOnlyCurrentTab))
|
||||
flags |= Config::Flag_CloseOnlyCurrentTab;
|
||||
|
||||
if (parser.isSet(noTitleBars))
|
||||
flags |= KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible;
|
||||
|
||||
@@ -227,6 +238,7 @@ int main(int argc, char **argv)
|
||||
const bool restoreIsRelative = parser.isSet(relativeRestore);
|
||||
const bool nonDockableDockWidget9 = parser.isSet(nonDockable);
|
||||
const bool maxSizeForDockWidget8 = parser.isSet(maxSizeOption);
|
||||
const bool dontCloseDockWidget5BeforeRestore = parser.isSet(dontCloseBeforeRestore);
|
||||
const bool usesMainWindowsWithAffinity = parser.isSet(multipleMainWindows);
|
||||
|
||||
#ifdef KDDOCKWIDGETS_SUPPORTS_NESTED_MAINWINDOWS
|
||||
@@ -236,7 +248,8 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
MyMainWindow mainWindow(QStringLiteral("MyMainWindow"), options, nonClosableDockWidget0,
|
||||
nonDockableDockWidget9, restoreIsRelative, maxSizeForDockWidget8);
|
||||
nonDockableDockWidget9, restoreIsRelative, maxSizeForDockWidget8,
|
||||
dontCloseDockWidget5BeforeRestore);
|
||||
mainWindow.setWindowTitle("Main Window 1");
|
||||
mainWindow.resize(1200, 1200);
|
||||
mainWindow.show();
|
||||
@@ -254,7 +267,8 @@ int main(int argc, char **argv)
|
||||
|
||||
auto mainWindow2 = new MyMainWindow(QStringLiteral("MyMainWindow-2"), options,
|
||||
nonClosableDockWidget0, nonDockableDockWidget9,
|
||||
restoreIsRelative, maxSizeForDockWidget8, affinity);
|
||||
restoreIsRelative, maxSizeForDockWidget8,
|
||||
dontCloseDockWidget5BeforeRestore, affinity);
|
||||
if (affinity.isEmpty())
|
||||
mainWindow2->setWindowTitle("Main Window 2");
|
||||
else
|
||||
@@ -267,7 +281,8 @@ int main(int argc, char **argv)
|
||||
|
||||
const QString affinity = QStringLiteral("Inner-DockWidgets-2");
|
||||
auto dockableMainWindow = new MyMainWindow(QStringLiteral("MyMainWindow-2"), options,
|
||||
false, false, restoreIsRelative, false, affinity);
|
||||
false, false, restoreIsRelative, false,
|
||||
false, affinity);
|
||||
|
||||
dockableMainWindow->setAffinities({ affinity });
|
||||
|
||||
|
||||
37
examples/minimal-mdi/CMakeLists.txt
Normal file
37
examples/minimal-mdi/CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(kddockwidgets_minimal_mdi_example)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIRS ON)
|
||||
|
||||
if(NOT TARGET kddockwidgets)
|
||||
# This will look for Qt, do find_package yourself manually before
|
||||
# if you want to look for a specific Qt version for instance.
|
||||
find_package(KDDockWidgets REQUIRED)
|
||||
endif()
|
||||
|
||||
set(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../dockwidgets/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_minimal_mdi_example
|
||||
main.cpp
|
||||
../dockwidgets/MyWidget.cpp
|
||||
${RESOURCES_EXAMPLE_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(kddockwidgets_minimal_mdi_example
|
||||
PRIVATE
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
|
||||
116
examples/minimal-mdi/MyWidget.cpp
Normal file
116
examples/minimal-mdi/MyWidget.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "MyWidget.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QLineEdit>
|
||||
|
||||
static QHash<QString, QImage> s_images; /// clazy:exclude=non-pod-global-static
|
||||
|
||||
MyWidget::MyWidget(const QString &backgroundFile, const QString &logoFile, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
if (!backgroundFile.isEmpty()) {
|
||||
auto it = s_images.find(backgroundFile);
|
||||
if (it == s_images.end())
|
||||
it = s_images.insert(backgroundFile, QImage(backgroundFile));
|
||||
m_background = it.value();
|
||||
}
|
||||
|
||||
if (!logoFile.isEmpty()) {
|
||||
auto it = s_images.find(logoFile);
|
||||
if (it == s_images.end())
|
||||
it = s_images.insert(logoFile, QImage(logoFile));
|
||||
m_logo = it.value();
|
||||
}
|
||||
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
#if 0
|
||||
// Uncomment to show focus propagation working
|
||||
new QLineEdit(this);
|
||||
auto l2 = new QLineEdit(this);
|
||||
l2->move(0, 100);
|
||||
setFocusProxy(l2);
|
||||
#endif
|
||||
}
|
||||
|
||||
MyWidget::~MyWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void MyWidget::drawLogo(QPainter &p)
|
||||
{
|
||||
if (m_logo.isNull())
|
||||
return;
|
||||
|
||||
const qreal ratio = m_logo.height() / (m_logo.width() * 1.0);
|
||||
|
||||
const int maxWidth = int(0.80 * size().width());
|
||||
const int maxHeight = int(0.80 * size().height());
|
||||
|
||||
const int proposedHeight = int(maxWidth * ratio);
|
||||
|
||||
const int width = proposedHeight <= maxHeight ? maxWidth
|
||||
: int(maxHeight / ratio);
|
||||
|
||||
const int height = int(width * ratio);
|
||||
QRect targetLogoRect(0,0, width, height);
|
||||
targetLogoRect.moveCenter(rect().center() + QPoint(0, -int(size().height() * 0.00)));
|
||||
p.drawImage(targetLogoRect, m_logo, m_logo.rect());
|
||||
}
|
||||
|
||||
MyWidget1::MyWidget1(MyWidget::QWidget *parent)
|
||||
: MyWidget(QStringLiteral(":/assets/triangles.png"), QStringLiteral(":/assets/KDAB_bubble_white.png"), parent)
|
||||
{
|
||||
}
|
||||
|
||||
void MyWidget1::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.fillRect(rect(), QColor(0xCC, 0xCC, 0xCC));
|
||||
p.drawImage(m_background.rect(), m_background, m_background.rect());
|
||||
|
||||
drawLogo(p);
|
||||
}
|
||||
|
||||
MyWidget2::MyWidget2(MyWidget::QWidget *parent)
|
||||
: MyWidget(QString(), QStringLiteral(":/assets/KDAB_bubble_blue.png"), parent)
|
||||
{
|
||||
}
|
||||
|
||||
void MyWidget2::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.fillRect(rect(), Qt::white);
|
||||
drawLogo(p);
|
||||
}
|
||||
|
||||
MyWidget3::MyWidget3(MyWidget::QWidget *parent)
|
||||
: MyWidget(QStringLiteral(":/assets/base.png"), QStringLiteral(":/assets/KDAB_bubble_fulcolor.png"), parent)
|
||||
, m_triangle(QImage(QStringLiteral(":/assets/tri.png")))
|
||||
{
|
||||
}
|
||||
|
||||
void MyWidget3::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
p.fillRect(rect(), QColor(0xD5, 0xD5, 0xD5));
|
||||
|
||||
p.drawImage(m_background.rect(), m_background, m_background.rect());
|
||||
|
||||
const QRect targetRect = QRect({ width() - m_triangle.width(), height() - m_triangle.height() }, m_triangle.size());
|
||||
|
||||
p.drawImage(targetRect, m_triangle, m_triangle.rect());
|
||||
drawLogo(p);
|
||||
}
|
||||
65
examples/minimal-mdi/MyWidget.h
Normal file
65
examples/minimal-mdi/MyWidget.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#ifndef EXAMPLEDOCKABLEWIDGET_H
|
||||
#define EXAMPLEDOCKABLEWIDGET_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPainter;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MyWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MyWidget() = default;
|
||||
explicit MyWidget(const QString &backgroundFile, const QString &logoFile, QWidget *parent = nullptr);
|
||||
~MyWidget();
|
||||
protected:
|
||||
void drawLogo(QPainter &);
|
||||
QImage m_background;
|
||||
QImage m_logo;
|
||||
};
|
||||
|
||||
class MyWidget1 : public MyWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MyWidget1(QWidget *parent = nullptr);
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
};
|
||||
|
||||
class MyWidget2 : public MyWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MyWidget2(QWidget *parent = nullptr);
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
};
|
||||
|
||||
class MyWidget3 : public MyWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MyWidget3(QWidget *parent = nullptr);
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*) override;
|
||||
QImage m_triangle;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
62
examples/minimal-mdi/main.cpp
Normal file
62
examples/minimal-mdi/main.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "MyWidget.h"
|
||||
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
#include <kddockwidgets/MainWindowMDI.h>
|
||||
|
||||
#include <QStyleFactory>
|
||||
#include <QApplication>
|
||||
|
||||
// clazy:excludeall=qstring-allocations
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif
|
||||
QApplication app(argc, argv);
|
||||
|
||||
app.setOrganizationName(QStringLiteral("KDAB"));
|
||||
app.setApplicationName(QStringLiteral("Test app"));
|
||||
|
||||
// Fusion looks better in general, but feel free to change
|
||||
qApp->setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
|
||||
|
||||
// # 1. Create our main window
|
||||
|
||||
KDDockWidgets::MainWindowMDI mainWindow(QStringLiteral("MyMainWindow"));
|
||||
mainWindow.setWindowTitle("Main Window");
|
||||
mainWindow.resize(1200, 1200);
|
||||
mainWindow.show();
|
||||
|
||||
// # 2. Create a dock widget, it needs a unique name
|
||||
auto dock1 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock1"));
|
||||
auto widget1 = new MyWidget1();
|
||||
dock1->setWidget(widget1);
|
||||
|
||||
auto dock2 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock2"));
|
||||
auto widget2 = new MyWidget2();
|
||||
dock2->setWidget(widget2);
|
||||
|
||||
auto dock3 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock3"));
|
||||
auto widget3 = new MyWidget3();
|
||||
dock3->setWidget(widget3);
|
||||
|
||||
// # 3. Dock them
|
||||
mainWindow.addDockWidget(dock1, QPoint(10, 10));
|
||||
mainWindow.addDockWidget(dock2, QPoint(50, 50));
|
||||
mainWindow.addDockWidget(dock3, QPoint(90, 90));
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
add_subdirectory(customtitlebar)
|
||||
add_subdirectory(dockwidgets)
|
||||
add_subdirectory(mdi)
|
||||
|
||||
set_compiler_flags(kddockwidgets_example_quick)
|
||||
set_compiler_flags(kddockwidgets_example_mdi_quick)
|
||||
set_compiler_flags(kddockwidgets_customtitlebar_quick)
|
||||
|
||||
18
examples/qtquick/mdi/Another.qml
Normal file
18
examples/qtquick/mdi/Another.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "green"
|
||||
anchors.fill: parent
|
||||
}
|
||||
37
examples/qtquick/mdi/CMakeLists.txt
Normal file
37
examples/qtquick/mdi/CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(kddockwidgets_example_mdi_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_mdi_example.qrc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../dockwidgets/resources_example.qrc)
|
||||
|
||||
add_executable(kddockwidgets_example_mdi_quick
|
||||
main.cpp
|
||||
${RESOURCES_EXAMPLE_SRC}
|
||||
)
|
||||
|
||||
target_link_libraries(kddockwidgets_example_mdi_quick
|
||||
PRIVATE
|
||||
KDAB::kddockwidgets
|
||||
)
|
||||
37
examples/qtquick/mdi/Guest.qml
Normal file
37
examples/qtquick/mdi/Guest.qml
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Rectangle {
|
||||
color: "white"
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
examples/qtquick/mdi/Guest1.qml
Normal file
44
examples/qtquick/mdi/Guest1.qml
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
17
examples/qtquick/mdi/Guest2.qml
Normal file
17
examples/qtquick/mdi/Guest2.qml
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
logo: "qrc:/assets/KDAB_bubble_blue.png"
|
||||
}
|
||||
18
examples/qtquick/mdi/Guest3.qml
Normal file
18
examples/qtquick/mdi/Guest3.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.9
|
||||
|
||||
Guest {
|
||||
anchors.fill: parent
|
||||
background: "qrc:/assets/base.png"
|
||||
logo: "qrc:/assets/KDAB_bubble_fulcolor.png"
|
||||
}
|
||||
64
examples/qtquick/mdi/main.cpp
Normal file
64
examples/qtquick/mdi/main.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/DockWidgetQuick.h>
|
||||
#include <kddockwidgets/private/DockRegistry_p.h>
|
||||
#include <kddockwidgets/FrameworkWidgetFactory.h>
|
||||
#include <kddockwidgets/MainWindowMDI.h>
|
||||
|
||||
#include <QQuickView>
|
||||
#include <QGuiApplication>
|
||||
#include <QCommandLineParser>
|
||||
|
||||
// Foro my own debugging, until we have better API
|
||||
#include "../../src/private/MDILayoutWidget_p.h"
|
||||
|
||||
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();
|
||||
|
||||
QQuickView view;
|
||||
view.setObjectName("MainWindow QQuickView");
|
||||
KDDockWidgets::Config::self().setQmlEngine(view.engine());
|
||||
view.resize(1000, 1000);
|
||||
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(400, 400));
|
||||
|
||||
auto dw2 = new KDDockWidgets::DockWidgetQuick("Dock #2");
|
||||
dw2->setWidget(QStringLiteral("qrc:/Guest2.qml"));
|
||||
dw2->resize(QSize(400, 400));
|
||||
|
||||
auto dw3 = new KDDockWidgets::DockWidgetQuick("Dock #3");
|
||||
dw3->setWidget(QStringLiteral("qrc:/Guest3.qml"));
|
||||
|
||||
auto mainWindow = static_cast<KDDockWidgets::MainWindowMDI*>(KDDockWidgets::DockRegistry::self()->mainwindows().constFirst());
|
||||
|
||||
mainWindow->addDockWidget(dw1, QPoint(10, 10));
|
||||
mainWindow->addDockWidget(dw2, QPoint(50, 50));
|
||||
mainWindow->addDockWidget(dw3, QPoint(90, 90));
|
||||
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
19
examples/qtquick/mdi/main.qml
Normal file
19
examples/qtquick/mdi/main.qml
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
import QtQuick 2.6
|
||||
import com.kdab.dockwidgets 1.0 as KDDW
|
||||
import "qrc:/kddockwidgets/private/quick/qml/" // TODO: Improve the public API
|
||||
|
||||
MainWindowMDI {
|
||||
id: root
|
||||
uniqueName: "MyWindow1"
|
||||
}
|
||||
10
examples/qtquick/mdi/resources_qtquick_mdi_example.qrc
Normal file
10
examples/qtquick/mdi/resources_qtquick_mdi_example.qrc
Normal file
@@ -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>Another.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -1,10 +1,10 @@
|
||||
Format: 1.0
|
||||
Source: kddockwidgets
|
||||
Version: 1.2.0-1
|
||||
Version: 1.3.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.2.0.tar.gz
|
||||
00000000000000000000000000000000 00000 kddockwidgets-1.3.0.tar.gz
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: kddockwidgets
|
||||
Version: 1.2.0
|
||||
Version: 1.3.0
|
||||
Release: 1
|
||||
Summary: KDAB's Dock Widget Framework for Qt
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
@@ -79,7 +79,15 @@ cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
%if 0%{?sle_version} >= 150200 && 0%{?is_opensuse}
|
||||
%{_libdir}/qt5/mkspecs/modules/*
|
||||
%endif
|
||||
%if 0%{?suse_version} > 1500
|
||||
%{_libdir}/qt5/mkspecs/modules/*
|
||||
%endif
|
||||
%if 0%{?fedora} > 28
|
||||
%{_libdir}/qt5/mkspecs/modules/*
|
||||
%endif
|
||||
%dir %{_includedir}/kddockwidgets
|
||||
%{_includedir}/kddockwidgets/*
|
||||
%dir %{_libdir}/cmake/KDDockWidgets
|
||||
@@ -87,6 +95,8 @@ cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
|
||||
%{_libdir}/libkddockwidgets.so
|
||||
|
||||
%changelog
|
||||
* Mon Feb 08 2021 Allen Winter <allen.winter@kdab.com> 1.3.0
|
||||
1.3.0 final
|
||||
* 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
|
||||
|
||||
@@ -20,6 +20,8 @@ set(PyKDDockWidgets_SRC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_mainwindowbase_wrapper.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_mainwindow_wrapper.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_mainwindow_wrapper.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_layoutsaver_wrapper.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_layoutsaver_wrapper.h
|
||||
# global module wrapper
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_module_wrapper.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_python.h
|
||||
@@ -56,6 +58,7 @@ set(PyKDDockWidgets_DEPENDS
|
||||
${CMAKE_SOURCE_DIR}/src/DockWidget.h
|
||||
${CMAKE_SOURCE_DIR}/src/MainWindowBase.h
|
||||
${CMAKE_SOURCE_DIR}/src/MainWindow.h
|
||||
${CMAKE_SOURCE_DIR}/src/LayoutSaver.h
|
||||
)
|
||||
|
||||
create_python_bindings(
|
||||
@@ -75,4 +78,4 @@ create_python_bindings(
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.cmake ${CMAKE_CURRENT_BINARY_DIR}/__init__.py @ONLY)
|
||||
|
||||
# install
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/PyKDDockWidgets)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/__init__.py DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/PyKDDockWidgets)
|
||||
|
||||
@@ -25,3 +25,4 @@
|
||||
#include <kddockwidgets/MainWindow.h>
|
||||
#include <kddockwidgets/DockWidgetBase.h>
|
||||
#include <kddockwidgets/DockWidget.h>
|
||||
#include <kddockwidgets/LayoutSaver.h>
|
||||
|
||||
@@ -45,5 +45,6 @@
|
||||
</object-type>
|
||||
|
||||
<object-type name="DockWidget" />
|
||||
<object-type name="LayoutSaver" />
|
||||
</namespace-type>
|
||||
</typesystem>
|
||||
|
||||
@@ -33,9 +33,15 @@ set(DOCKSLIBS_SRCS
|
||||
DockWidgetBase.h
|
||||
MainWindowBase.cpp
|
||||
MainWindowBase.h
|
||||
MainWindowMDI.cpp
|
||||
MainWindowMDI.h
|
||||
LayoutSaver.cpp
|
||||
LayoutSaver.h
|
||||
LayoutSaver_p.h
|
||||
private/LayoutWidget.cpp
|
||||
private/LayoutWidget_p.h
|
||||
private/MDILayoutWidget.cpp
|
||||
private/MDILayoutWidget_p.h
|
||||
private/MultiSplitter.cpp
|
||||
private/MultiSplitter_p.h
|
||||
private/Position.cpp
|
||||
@@ -77,6 +83,8 @@ set(DOCKSLIBS_SRCS
|
||||
|
||||
private/multisplitter/Item.cpp
|
||||
private/multisplitter/Item_p.h
|
||||
private/multisplitter/ItemFreeContainer.cpp
|
||||
private/multisplitter/ItemFreeContainer_p.h
|
||||
private/multisplitter/Logging.cpp
|
||||
private/multisplitter/Logging_p.h
|
||||
private/multisplitter/MultiSplitterConfig.cpp
|
||||
@@ -97,18 +105,21 @@ set(DOCKS_INSTALLABLE_INCLUDES
|
||||
FocusScope.h
|
||||
QWidgetAdapter.h
|
||||
LayoutSaver.h
|
||||
LayoutSaver_p.h
|
||||
)
|
||||
|
||||
set(DOCKS_INSTALLABLE_PRIVATE_INCLUDES
|
||||
private/DragController_p.h
|
||||
private/Draggable_p.h
|
||||
private/DropArea_p.h
|
||||
private/DropIndicatorOverlayInterface_p.h
|
||||
private/FloatingWindow_p.h
|
||||
private/Frame_p.h
|
||||
private/MultiSplitter_p.h
|
||||
private/LayoutWidget_p.h
|
||||
private/SideBar_p.h
|
||||
private/TitleBar_p.h
|
||||
private/WindowBeingDragged_p.h
|
||||
private/WidgetResizeHandler_p.h
|
||||
private/DockRegistry_p.h
|
||||
private/TabWidget_p.h
|
||||
)
|
||||
@@ -192,6 +203,7 @@ else()
|
||||
set(DOCKS_INSTALLABLE_INCLUDES
|
||||
${DOCKS_INSTALLABLE_INCLUDES}
|
||||
MainWindow.h
|
||||
MainWindowMDI.h
|
||||
MainWindowBase.h
|
||||
DockWidget.h
|
||||
)
|
||||
@@ -207,6 +219,7 @@ 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)
|
||||
set_target_properties(kddockwidgets PROPERTIES OUTPUT_NAME "kddockwidgets${KDDockWidgets_LIBRARY_QTID}")
|
||||
set_compiler_flags(kddockwidgets)
|
||||
|
||||
target_include_directories(kddockwidgets
|
||||
@@ -232,6 +245,10 @@ else()
|
||||
target_compile_definitions(kddockwidgets PRIVATE BUILDING_DOCKS_LIBRARY)
|
||||
endif()
|
||||
|
||||
if (KDDockWidgets_QTQUICK)
|
||||
target_compile_definitions(kddockwidgets PUBLIC KDDOCKWIDGETS_QTQUICK)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR IS_CLANG_BUILD)
|
||||
target_compile_options(kddockwidgets PRIVATE -Wshadow -fvisibility=hidden)
|
||||
|
||||
@@ -265,13 +282,19 @@ set_target_properties(kddockwidgets PROPERTIES
|
||||
|
||||
#version libraries on Windows
|
||||
if(WIN32)
|
||||
set(postfix ${${PROJECT_NAME}_VERSION_MAJOR})
|
||||
set(CMAKE_RELEASE_POSTFIX ${postfix})
|
||||
set_target_properties(kddockwidgets PROPERTIES RELEASE_POSTFIX ${CMAKE_RELEASE_POSTFIX})
|
||||
#append 'd' to debug libraries
|
||||
string(CONCAT postfix ${postfix} "d")
|
||||
set(CMAKE_DEBUG_POSTFIX ${postfix})
|
||||
set_target_properties(kddockwidgets PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
|
||||
if (CMAKE_BUILD_TYPE)
|
||||
set(postfix ${${PROJECT_NAME}_VERSION_MAJOR})
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} UPPER_BUILD_TYPE)
|
||||
if(${UPPER_BUILD_TYPE} MATCHES "^DEBUG")
|
||||
string(CONCAT postfix ${postfix} "d")
|
||||
set_target_properties(kddockwidgets PROPERTIES DEBUG_POSTFIX ${postfix})
|
||||
else()
|
||||
set_target_properties(kddockwidgets PROPERTIES ${UPPER_BUILD_TYPE}_POSTFIX ${postfix})
|
||||
endif()
|
||||
elseif(CMAKE_CONFIGURATION_TYPES)
|
||||
# Visual Studio generator
|
||||
set_target_properties(kddockwidgets PROPERTIES DEBUG_POSTFIX d)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(TARGETS kddockwidgets
|
||||
@@ -295,12 +318,16 @@ install(FILES ${DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES} DESTINATION include/k
|
||||
install(FILES private/indicators/ClassicIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
|
||||
install(FILES private/indicators/SegmentedIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
KDDockWidgetsConfigVersion.cmake
|
||||
VERSION ${${PROJECT_NAME}_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
# Generate library version files
|
||||
include(ECMSetupVersion)
|
||||
ecm_setup_version(
|
||||
${${PROJECT_NAME}_VERSION}
|
||||
VARIABLE_PREFIX KDDOCKWIDGETS
|
||||
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kddockwidgets_version.h"
|
||||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgetsConfigVersion.cmake"
|
||||
SOVERSION ${${PROJECT_NAME}_SOVERSION}
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kddockwidgets_version.h" DESTINATION include/kddockwidgets)
|
||||
|
||||
install(EXPORT kddockwidgetsTargets
|
||||
FILE KDDockWidgetsTargets.cmake
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "DockRegistry_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "Utils_p.h"
|
||||
#include "DragController_p.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QOperatingSystemVersion>
|
||||
@@ -56,7 +57,9 @@ public:
|
||||
FrameworkWidgetFactory *m_frameworkWidgetFactory = nullptr;
|
||||
Flags m_flags = Flag_Default;
|
||||
InternalFlags m_internalFlags = InternalFlag_None;
|
||||
CustomizableWidgets m_disabledPaintEvents = CustomizableWidget_None;
|
||||
qreal m_draggedWindowOpacity = Q_QNAN;
|
||||
int m_mdiPopupThreshold = 250;
|
||||
};
|
||||
|
||||
Config::Config()
|
||||
@@ -226,6 +229,9 @@ void Config::setQmlEngine(QQmlEngine *qmlEngine)
|
||||
return;
|
||||
}
|
||||
|
||||
auto dr = DockRegistry::self(); // make sure our QML types are registered
|
||||
qmlEngine->rootContext()->setContextProperty(QStringLiteral("_kddwDockRegistry"), dr);
|
||||
qmlEngine->rootContext()->setContextProperty(QStringLiteral("_kddwDragController"), DragController::instance());
|
||||
d->m_qmlEngine = qmlEngine;
|
||||
|
||||
QQmlContext *context = qmlEngine->rootContext();
|
||||
@@ -234,6 +240,9 @@ void Config::setQmlEngine(QQmlEngine *qmlEngine)
|
||||
|
||||
QQmlEngine *Config::qmlEngine() const
|
||||
{
|
||||
if (!d->m_qmlEngine)
|
||||
qWarning() << "Please call KDDockWidgets::Config::self()->setQmlEngine(engine)";
|
||||
|
||||
return d->m_qmlEngine;
|
||||
}
|
||||
#endif
|
||||
@@ -241,8 +250,8 @@ QQmlEngine *Config::qmlEngine() const
|
||||
void Config::Private::fixFlags()
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
if (QOperatingSystemVersion::current().majorVersion() < 10) {
|
||||
// Aero-snap requires Windows 10
|
||||
if (QOperatingSystemVersion::current().majorVersion() < 8) {
|
||||
// Untested on Windows 7. Windows 8 doesn't have aerosnap but at least it can get native resizing
|
||||
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
||||
} else {
|
||||
// Unconditional now
|
||||
@@ -292,4 +301,23 @@ void Config::Private::fixFlags()
|
||||
}
|
||||
}
|
||||
|
||||
void Config::setDisabledPaintEvents(CustomizableWidgets widgets)
|
||||
{
|
||||
d->m_disabledPaintEvents = widgets;
|
||||
}
|
||||
|
||||
Config::CustomizableWidgets Config::disabledPaintEvents() const
|
||||
{
|
||||
return d->m_disabledPaintEvents;
|
||||
}
|
||||
|
||||
void Config::setMDIPopupThreshold(int threshold)
|
||||
{
|
||||
d->m_mdiPopupThreshold = threshold;
|
||||
}
|
||||
|
||||
int Config::mdiPopupThreshold() const
|
||||
{
|
||||
return d->m_mdiPopupThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
31
src/Config.h
31
src/Config.h
@@ -63,7 +63,7 @@ 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_NativeTitleBar = 1, ///< Enables the Native OS title bar on OSes that support it (Windows 10, macOS), ignored otherwise.
|
||||
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.
|
||||
@@ -75,15 +75,29 @@ public:
|
||||
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_DontUseUtilityFloatingWindows = 0x1000,
|
||||
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_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_CloseOnlyCurrentTab = 0x20000, ///< The TitleBar's close button will only close the current tab, instead of all of them
|
||||
Flag_Default = Flag_AeroSnapWithClientDecos ///< The defaults
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
///@brief List of customizable widgets
|
||||
enum CustomizableWidget {
|
||||
CustomizableWidget_None = 0, ///< None
|
||||
CustomizableWidget_TitleBar, ///< The title bar
|
||||
CustomizableWidget_DockWidget, ///< The dock widget
|
||||
CustomizableWidget_Frame, ///< The container for a group of 1 or more dockwidgets which are tabbed together
|
||||
CustomizableWidget_TabBar, ///< The tab bar, child of Frame, which contains 1 or more dock widgets
|
||||
CustomizableWidget_TabWidget, ///< The tab widget which relates to the tab bar
|
||||
CustomizableWidget_FloatingWindow, ///< A top-level window. The container for 1 or more Frame nested side by side
|
||||
CustomizableWidget_Separator ///< The draggable separator between dock widgets in a layout
|
||||
};
|
||||
Q_DECLARE_FLAGS(CustomizableWidgets, CustomizableWidget)
|
||||
|
||||
///@internal
|
||||
///Internal flags for addtional tunning.
|
||||
///@warning Not for public consumption, support will be limited.
|
||||
@@ -206,6 +220,13 @@ public:
|
||||
void setAbsoluteWidgetMaxSize(QSize size);
|
||||
QSize absoluteWidgetMaxSize() const;
|
||||
|
||||
///@brief Disables our internal widget's paint events
|
||||
/// By default, KDDockWidget's internal widgets reimplement paintEvent(). Disabling them
|
||||
/// (which makes the base-class, QWidget::paintEvent() be called instead) can be useful if you want to style
|
||||
// via CSS stylesheets.
|
||||
void setDisabledPaintEvents(CustomizableWidgets);
|
||||
Config::CustomizableWidgets disabledPaintEvents() const;
|
||||
|
||||
///@internal
|
||||
///@brief returns the internal flags.
|
||||
///@warning Not for public consumption, support will be limited.
|
||||
@@ -216,6 +237,12 @@ public:
|
||||
///@warning Not for public consumption, support will be limited.
|
||||
void setInternalFlags(InternalFlags flags);
|
||||
|
||||
/// @brief Sets the MDI popup threshold. When the layout is MDI and you drag a dock widget
|
||||
/// X pixels behond the window's edge, it will float the dock widget.
|
||||
/// by default this value is 250px. Use -1 to disable
|
||||
void setMDIPopupThreshold(int);
|
||||
int mdiPopupThreshold() const;
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
///@brief Sets the QQmlEngine to use. Applicable only when using QtQuick.
|
||||
void setQmlEngine(QQmlEngine *);
|
||||
|
||||
@@ -49,7 +49,8 @@ public:
|
||||
* when visible, or stays without a parent when hidden. This allows to support docking
|
||||
* to different main windows.
|
||||
*/
|
||||
explicit DockWidget(const QString &uniqueName, Options options = DockWidgetBase::Options());
|
||||
explicit DockWidget(const QString &uniqueName, Options options = DockWidgetBase::Options(),
|
||||
LayoutSaverOptions layoutSaverOptions = LayoutSaverOptions());
|
||||
|
||||
///@brief destructor
|
||||
~DockWidget() override;
|
||||
|
||||
@@ -10,18 +10,20 @@
|
||||
*/
|
||||
|
||||
#include "DockWidgetBase.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Config.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "private/Position_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "private/Position_p.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QCloseEvent>
|
||||
@@ -37,107 +39,10 @@
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
class DockWidgetBase::Private
|
||||
{
|
||||
public:
|
||||
Private(const QString &dockName, DockWidgetBase::Options options_, DockWidgetBase *qq)
|
||||
: name(dockName)
|
||||
, title(dockName)
|
||||
, q(qq)
|
||||
, options(options_)
|
||||
, toggleAction(new QAction(q))
|
||||
, floatAction(new QAction(q))
|
||||
{
|
||||
q->connect(toggleAction, &QAction::toggled, q, [this] (bool enabled) {
|
||||
if (!m_updatingToggleAction) { // guard against recursiveness
|
||||
toggleAction->blockSignals(true); // and don't emit spurious toggle. Like when a dock widget is inserted into a tab widget it might get hide events, ignore those. The Dock Widget is open.
|
||||
toggle(enabled);
|
||||
toggleAction->blockSignals(false);
|
||||
}
|
||||
});
|
||||
|
||||
q->connect(floatAction, &QAction::toggled, q, [this] (bool checked) {
|
||||
if (!m_updatingFloatAction) { // guard against recursiveness
|
||||
q->setFloating(checked);
|
||||
}
|
||||
|
||||
Q_EMIT q->isFloatingChanged(checked);
|
||||
});
|
||||
|
||||
toggleAction->setCheckable(true);
|
||||
floatAction->setCheckable(true);
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
FloatingWindow *floatingWindow() const
|
||||
{
|
||||
return qobject_cast<FloatingWindow*>(q->window());
|
||||
}
|
||||
|
||||
MainWindowBase *mainWindow() const
|
||||
{
|
||||
if (q->isWindow())
|
||||
return nullptr;
|
||||
|
||||
// Note: Don't simply use window(), as the MainWindow might be embedded into something else
|
||||
QWidgetOrQuick *p = q->parentWidget();
|
||||
while (p) {
|
||||
if (auto window = qobject_cast<MainWindowBase*>(p))
|
||||
return window;
|
||||
|
||||
if (p->isWindow())
|
||||
return nullptr;
|
||||
|
||||
p = p->parentWidget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QPoint defaultCenterPosForFloating();
|
||||
|
||||
void updateTitle();
|
||||
void toggle(bool enabled);
|
||||
void updateToggleAction();
|
||||
void updateFloatAction();
|
||||
void onDockWidgetShown();
|
||||
void onDockWidgetHidden();
|
||||
void show();
|
||||
void close();
|
||||
bool restoreToPreviousPosition();
|
||||
void maybeRestoreToPreviousPosition();
|
||||
int currentTabIndex() const;
|
||||
|
||||
/**
|
||||
* Before floating a dock widget we save its position. So it can be restored when calling
|
||||
* DockWidget::setFloating(false)
|
||||
*/
|
||||
void saveTabIndex();
|
||||
|
||||
const QString name;
|
||||
QStringList affinities;
|
||||
QString title;
|
||||
QIcon titleBarIcon;
|
||||
QIcon tabBarIcon;
|
||||
QWidgetOrQuick *widget = nullptr;
|
||||
DockWidgetBase *const q;
|
||||
DockWidgetBase::Options options;
|
||||
QAction *const toggleAction;
|
||||
QAction *const floatAction;
|
||||
LastPositions m_lastPositions;
|
||||
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)
|
||||
DockWidgetBase::DockWidgetBase(const QString &name, Options options,
|
||||
LayoutSaverOptions layoutSaverOptions)
|
||||
: QWidgetAdapter(nullptr, Qt::Tool)
|
||||
, d(new Private(name, options, this))
|
||||
, d(new Private(name, options, layoutSaverOptions, this))
|
||||
{
|
||||
d->init();
|
||||
DockRegistry::self()->registerDockWidget(this);
|
||||
@@ -146,7 +51,6 @@ DockWidgetBase::DockWidgetBase(const QString &name, Options options)
|
||||
qWarning() << Q_FUNC_INFO << "Name can't be null";
|
||||
|
||||
setAttribute(Qt::WA_PendingMoveEvent, false);
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
DockWidgetBase::~DockWidgetBase()
|
||||
@@ -179,7 +83,7 @@ void DockWidgetBase::addDockWidgetAsTab(DockWidgetBase *other, InitialOption opt
|
||||
return;
|
||||
}
|
||||
|
||||
Frame *frame = this->frame();
|
||||
Frame *frame = d->frame();
|
||||
|
||||
if (frame) {
|
||||
if (frame->containsDockWidget(other)) {
|
||||
@@ -189,8 +93,8 @@ void DockWidgetBase::addDockWidgetAsTab(DockWidgetBase *other, InitialOption opt
|
||||
} else {
|
||||
if (isWindow()) {
|
||||
// Doesn't have a frame yet
|
||||
morphIntoFloatingWindow();
|
||||
frame = this->frame();
|
||||
d->morphIntoFloatingWindow();
|
||||
frame = d->frame();
|
||||
} else {
|
||||
// Doesn't happen
|
||||
qWarning() << Q_FUNC_INFO << "null frame";
|
||||
@@ -226,10 +130,10 @@ void DockWidgetBase::addDockWidgetToContainingWindow(DockWidgetBase *other,
|
||||
}
|
||||
|
||||
if (isWindow())
|
||||
morphIntoFloatingWindow();
|
||||
d->morphIntoFloatingWindow();
|
||||
|
||||
if (auto fw = floatingWindow()) {
|
||||
fw->dropArea()->addDockWidget(other, location, relativeTo, initialOption);
|
||||
fw->addDockWidget(other, location, relativeTo, initialOption);
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Couldn't find floating nested window";
|
||||
}
|
||||
@@ -237,7 +141,6 @@ void DockWidgetBase::addDockWidgetToContainingWindow(DockWidgetBase *other,
|
||||
|
||||
void DockWidgetBase::setWidget(QWidgetOrQuick *w)
|
||||
{
|
||||
Q_ASSERT(w);
|
||||
if (w == d->widget)
|
||||
return;
|
||||
|
||||
@@ -251,7 +154,6 @@ void DockWidgetBase::setWidget(QWidgetOrQuick *w)
|
||||
setSizePolicy(w->sizePolicy());
|
||||
|
||||
Q_EMIT widgetChanged(w);
|
||||
setWindowTitle(uniqueName());
|
||||
}
|
||||
|
||||
QWidgetOrQuick *DockWidgetBase::widget() const
|
||||
@@ -284,7 +186,7 @@ bool DockWidgetBase::setFloating(bool floats)
|
||||
if (floats) {
|
||||
d->saveTabIndex();
|
||||
if (isTabbed()) {
|
||||
auto frame = this->frame();
|
||||
auto frame = d->frame();
|
||||
if (!frame) {
|
||||
qWarning() << "DockWidget::setFloating: Tabbed but no frame exists"
|
||||
<< this;
|
||||
@@ -294,17 +196,17 @@ bool DockWidgetBase::setFloating(bool floats)
|
||||
|
||||
frame->detachTab(this);
|
||||
} else {
|
||||
frame()->titleBar()->makeWindow();
|
||||
d->frame()->titleBar()->makeWindow();
|
||||
}
|
||||
|
||||
auto lastGeo = lastPositions().lastFloatingGeometry();
|
||||
auto lastGeo = d->lastPositions().lastFloatingGeometry();
|
||||
if (lastGeo.isValid()) {
|
||||
if (auto fw = floatingWindow())
|
||||
fw->setSuggestedGeometry(lastGeo, /*preserveCenter=*/true);
|
||||
fw->setSuggestedGeometry(lastGeo, SuggestedGeometryHint_PreserveCenter);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
saveLastFloatingGeometry();
|
||||
d->saveLastFloatingGeometry();
|
||||
return d->restoreToPreviousPosition();
|
||||
}
|
||||
}
|
||||
@@ -338,11 +240,25 @@ void DockWidgetBase::setTitle(const QString &title)
|
||||
}
|
||||
}
|
||||
|
||||
QRect DockWidgetBase::frameGeometry() const
|
||||
{
|
||||
if (Frame *f = d->frame())
|
||||
return f->QWidgetAdapter::geometry();
|
||||
|
||||
// Means the dock widget isn't visible. Just fallback to its own geometry
|
||||
return QWidgetAdapter::geometry();
|
||||
}
|
||||
|
||||
DockWidgetBase::Options DockWidgetBase::options() const
|
||||
{
|
||||
return d->options;
|
||||
}
|
||||
|
||||
DockWidgetBase::LayoutSaverOptions DockWidgetBase::layoutSaverOptions() const
|
||||
{
|
||||
return d->layoutSaverOptions;
|
||||
}
|
||||
|
||||
void DockWidgetBase::setOptions(Options options)
|
||||
{
|
||||
if ((d->options & Option_NotDockable) != (options & Option_NotDockable)) {
|
||||
@@ -354,13 +270,13 @@ void DockWidgetBase::setOptions(Options options)
|
||||
d->options = options;
|
||||
Q_EMIT optionsChanged(options);
|
||||
if (auto tb = titleBar())
|
||||
tb->updateCloseButton();
|
||||
tb->updateButtons();
|
||||
}
|
||||
}
|
||||
|
||||
bool DockWidgetBase::isTabbed() const
|
||||
{
|
||||
if (Frame *frame = this->frame()) {
|
||||
if (Frame *frame = d->frame()) {
|
||||
return frame->alwaysShowsTabs() || frame->dockWidgetCount() > 1;
|
||||
} else {
|
||||
if (!isFloating())
|
||||
@@ -371,7 +287,7 @@ bool DockWidgetBase::isTabbed() const
|
||||
|
||||
bool DockWidgetBase::isCurrentTab() const
|
||||
{
|
||||
if (Frame *frame = this->frame()) {
|
||||
if (Frame *frame = d->frame()) {
|
||||
return frame->currentIndex() == frame->indexOfDockWidget(const_cast<DockWidgetBase*>(this));
|
||||
} else {
|
||||
return true;
|
||||
@@ -380,10 +296,18 @@ bool DockWidgetBase::isCurrentTab() const
|
||||
|
||||
void DockWidgetBase::setAsCurrentTab()
|
||||
{
|
||||
if (Frame *frame = this->frame())
|
||||
if (Frame *frame = d->frame())
|
||||
frame->setCurrentDockWidget(this);
|
||||
}
|
||||
|
||||
int DockWidgetBase::tabIndex() const
|
||||
{
|
||||
if (Frame *frame = d->frame())
|
||||
return frame->indexOfDockWidget(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DockWidgetBase::setIcon(const QIcon &icon, IconPlaces places)
|
||||
{
|
||||
if (places & IconPlace::TitleBar)
|
||||
@@ -414,13 +338,12 @@ QIcon DockWidgetBase::icon(IconPlace place) const
|
||||
|
||||
void DockWidgetBase::forceClose()
|
||||
{
|
||||
QScopedValueRollback<bool> rollback(d->m_isForceClosing, true);
|
||||
d->close();
|
||||
d->forceClose();
|
||||
}
|
||||
|
||||
TitleBar *DockWidgetBase::titleBar() const
|
||||
{
|
||||
if (Frame *f = frame())
|
||||
if (Frame *f = d->frame())
|
||||
return f->actualTitleBar();
|
||||
|
||||
return nullptr;
|
||||
@@ -441,7 +364,7 @@ void DockWidgetBase::show()
|
||||
if (isWindow() && (d->m_lastPositions.wasFloating() || !d->m_lastPositions.isValid())) {
|
||||
// Create the FloatingWindow already, instead of waiting for the show event.
|
||||
// This reduces flickering on some platforms
|
||||
morphIntoFloatingWindow();
|
||||
d->morphIntoFloatingWindow();
|
||||
} else {
|
||||
QWidgetOrQuick::show();
|
||||
}
|
||||
@@ -477,7 +400,7 @@ MainWindowBase* DockWidgetBase::mainWindow() const
|
||||
|
||||
bool DockWidgetBase::isFocused() const
|
||||
{
|
||||
auto f = this->frame();
|
||||
auto f = d->frame();
|
||||
return f && f->isFocused() && isCurrentTab();
|
||||
}
|
||||
|
||||
@@ -523,6 +446,11 @@ SideBarLocation DockWidgetBase::sideBarLocation() const
|
||||
return DockRegistry::self()->sideBarLocationForDockWidget(this);
|
||||
}
|
||||
|
||||
bool DockWidgetBase::isInSideBar() const
|
||||
{
|
||||
return sideBarLocation() != SideBarLocation::None;
|
||||
}
|
||||
|
||||
bool DockWidgetBase::hasPreviousDockedLocation() const
|
||||
{
|
||||
return d->m_lastPositions.isValid();
|
||||
@@ -538,25 +466,40 @@ DockWidgetBase *DockWidgetBase::byName(const QString &uniqueName)
|
||||
return DockRegistry::self()->dockByName(uniqueName);
|
||||
}
|
||||
|
||||
FloatingWindow *DockWidgetBase::morphIntoFloatingWindow()
|
||||
bool DockWidgetBase::skipsRestore() const
|
||||
{
|
||||
return d->layoutSaverOptions & LayoutSaverOption::Skip;
|
||||
}
|
||||
|
||||
void DockWidgetBase::setFloatingGeometry(QRect geometry)
|
||||
{
|
||||
if (isOpen() && isFloating()) {
|
||||
window()->setGeometry(geometry);
|
||||
} else {
|
||||
d->m_lastPositions.setLastFloatingGeometry(geometry);
|
||||
}
|
||||
}
|
||||
|
||||
FloatingWindow *DockWidgetBase::Private::morphIntoFloatingWindow()
|
||||
{
|
||||
if (auto fw = floatingWindow())
|
||||
return fw; // Nothing to do
|
||||
|
||||
if (isWindow()) {
|
||||
QRect geo = d->m_lastPositions.lastFloatingGeometry();
|
||||
if (q->isWindow()) {
|
||||
QRect geo = m_lastPositions.lastFloatingGeometry();
|
||||
if (geo.isNull()) {
|
||||
geo = geometry();
|
||||
geo = q->geometry();
|
||||
|
||||
if (!testAttribute(Qt::WA_PendingMoveEvent)) { // If user already moved it, we don't interfere
|
||||
const QPoint center = d->defaultCenterPosForFloating();
|
||||
if (!q->testAttribute(Qt::WA_PendingMoveEvent)) { // If user already moved it, we don't
|
||||
// interfere
|
||||
const QPoint center = defaultCenterPosForFloating();
|
||||
if (!center.isNull())
|
||||
geo.moveCenter(center);
|
||||
}
|
||||
}
|
||||
|
||||
auto frame = Config::self().frameworkWidgetFactory()->createFrame();
|
||||
frame->addWidget(this);
|
||||
frame->addWidget(q);
|
||||
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(frame);
|
||||
floatingWindow->setSuggestedGeometry(geo);
|
||||
floatingWindow->show();
|
||||
@@ -567,60 +510,23 @@ FloatingWindow *DockWidgetBase::morphIntoFloatingWindow()
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::maybeMorphIntoFloatingWindow()
|
||||
void DockWidgetBase::Private::maybeMorphIntoFloatingWindow()
|
||||
{
|
||||
if (isWindow() && isVisible())
|
||||
if (q->isWindow() && q->isVisible())
|
||||
morphIntoFloatingWindow();
|
||||
}
|
||||
|
||||
Frame *DockWidgetBase::frame() const
|
||||
MDILayoutWidget *DockWidgetBase::Private::mdiLayout() const
|
||||
{
|
||||
QWidgetOrQuick *p = parentWidget();
|
||||
while (p) {
|
||||
if (auto frame = qobject_cast<Frame *>(p))
|
||||
return frame;
|
||||
p = p->parentWidget();
|
||||
}
|
||||
if (auto mw = mainWindow())
|
||||
return mw->mdiLayoutWidget();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FloatingWindow *DockWidgetBase::floatingWindow() const
|
||||
DockWidgetBase::Private *DockWidgetBase::dptr() const
|
||||
{
|
||||
return d->floatingWindow();
|
||||
}
|
||||
|
||||
void DockWidgetBase::addPlaceholderItem(Layouting::Item *item)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
d->m_lastPositions.addPosition(item);
|
||||
}
|
||||
|
||||
LastPositions& DockWidgetBase::lastPositions() const
|
||||
{
|
||||
return d->m_lastPositions;
|
||||
}
|
||||
|
||||
void DockWidgetBase::saveLastFloatingGeometry()
|
||||
{
|
||||
if (isFloating() && isVisible()) {
|
||||
// It's getting docked, save last floating position
|
||||
lastPositions().setLastFloatingGeometry(window()->geometry());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return d;
|
||||
}
|
||||
|
||||
QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
|
||||
@@ -634,21 +540,36 @@ QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
|
||||
return mw->geometry().center();
|
||||
}
|
||||
|
||||
bool DockWidgetBase::Private::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
const bool isWindowActivate = event->type() == QEvent::WindowActivate;
|
||||
const bool isWindowDeactivate = event->type() == QEvent::WindowDeactivate;
|
||||
if ((isWindowActivate || isWindowDeactivate) && watched == q->window())
|
||||
Q_EMIT q->windowActiveAboutToChange(isWindowActivate);
|
||||
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::updateTitle()
|
||||
{
|
||||
if (q->isFloating())
|
||||
q->window()->setWindowTitle(title);
|
||||
|
||||
|
||||
toggleAction->setText(title);
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::toggle(bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
show();
|
||||
if (SideBar *sb = sideBar()) {
|
||||
// The widget is in the sidebar, let's toggle its overlayed state
|
||||
sb->toggleOverlay(q);
|
||||
} else {
|
||||
q->close();
|
||||
// The most common case. The dock widget is not in the sidebar. just close or open it.
|
||||
if (enabled) {
|
||||
show();
|
||||
} else {
|
||||
q->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,9 +577,9 @@ void DockWidgetBase::Private::updateToggleAction()
|
||||
{
|
||||
QScopedValueRollback<bool> recursionGuard(m_updatingToggleAction, true); // Guard against recursiveness
|
||||
m_updatingToggleAction = true;
|
||||
if ((q->isVisible() || q->frame()) && !toggleAction->isChecked()) {
|
||||
if ((q->isVisible() || frame()) && !toggleAction->isChecked()) {
|
||||
toggleAction->setChecked(true);
|
||||
} else if ((!q->isVisible() && !q->frame()) && toggleAction->isChecked()) {
|
||||
} else if ((!q->isVisible() && !frame()) && toggleAction->isChecked()) {
|
||||
toggleAction->setChecked(false);
|
||||
}
|
||||
}
|
||||
@@ -692,6 +613,10 @@ void DockWidgetBase::Private::onDockWidgetHidden()
|
||||
|
||||
void DockWidgetBase::Private::close()
|
||||
{
|
||||
if (!m_processingToggleAction && !q->isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_isForceClosing && q->isFloating() && q->isVisible()) { // only user-closing is interesting to save the geometry
|
||||
// We check for isVisible so we don't save geometry if you call close() on an already closed dock widget
|
||||
m_lastPositions.setLastFloatingGeometry(q->window()->geometry());
|
||||
@@ -700,7 +625,7 @@ void DockWidgetBase::Private::close()
|
||||
saveTabIndex();
|
||||
|
||||
// Do some cleaning. Widget is hidden, but we must hide the tab containing it.
|
||||
if (Frame *frame = q->frame()) {
|
||||
if (Frame *frame = this->frame()) {
|
||||
frame->removeWidget(q);
|
||||
q->setParent(nullptr);
|
||||
|
||||
@@ -708,6 +633,9 @@ void DockWidgetBase::Private::close()
|
||||
sb->removeDockWidget(q);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_isMovingToSideBar && (options & DockWidgetBase::Option_DeleteOnClose))
|
||||
q->deleteLater();
|
||||
}
|
||||
|
||||
bool DockWidgetBase::Private::restoreToPreviousPosition()
|
||||
@@ -717,7 +645,7 @@ bool DockWidgetBase::Private::restoreToPreviousPosition()
|
||||
|
||||
Layouting::Item *item = m_lastPositions.lastItem();
|
||||
|
||||
MultiSplitter *layout = DockRegistry::self()->layoutForItem(item);
|
||||
LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
|
||||
Q_ASSERT(layout);
|
||||
layout->restorePlaceholder(q, item, m_lastPositions.lastTabIndex());
|
||||
return true;
|
||||
@@ -737,7 +665,7 @@ void DockWidgetBase::Private::maybeRestoreToPreviousPosition()
|
||||
if (m_lastPositions.wasFloating())
|
||||
return; // Nothing to do, it was floating before, now it'll just get visible
|
||||
|
||||
Frame *frame = q->frame();
|
||||
Frame *frame = this->frame();
|
||||
|
||||
if (frame && frame->QWidgetAdapter::parentWidget() == DockRegistry::self()->layoutForItem(layoutItem)) {
|
||||
// There's a frame already. Means the DockWidget was hidden instead of closed.
|
||||
@@ -758,7 +686,7 @@ void DockWidgetBase::Private::maybeRestoreToPreviousPosition()
|
||||
|
||||
int DockWidgetBase::Private::currentTabIndex() const
|
||||
{
|
||||
Frame *frame = q->frame();
|
||||
Frame *frame = this->frame();
|
||||
return frame ? frame->indexOfDockWidget(q) : 0;
|
||||
}
|
||||
|
||||
@@ -783,6 +711,8 @@ void DockWidgetBase::onParentChanged()
|
||||
#endif
|
||||
d->updateToggleAction();
|
||||
d->updateFloatAction();
|
||||
|
||||
Q_EMIT actualTitleBarChanged();
|
||||
}
|
||||
|
||||
void DockWidgetBase::onShown(bool spontaneous)
|
||||
@@ -790,7 +720,7 @@ void DockWidgetBase::onShown(bool spontaneous)
|
||||
d->onDockWidgetShown();
|
||||
Q_EMIT shown();
|
||||
|
||||
if (Frame *f = frame()) {
|
||||
if (Frame *f = d->frame()) {
|
||||
if (!spontaneous) {
|
||||
f->onDockWidgetShown(this);
|
||||
}
|
||||
@@ -799,7 +729,7 @@ void DockWidgetBase::onShown(bool spontaneous)
|
||||
d->maybeRestoreToPreviousPosition();
|
||||
|
||||
// Transform into a FloatingWindow if this will be a regular floating dock widget.
|
||||
QTimer::singleShot(0, this, &DockWidgetBase::maybeMorphIntoFloatingWindow);
|
||||
QTimer::singleShot(0, d, &DockWidgetBase::Private::maybeMorphIntoFloatingWindow);
|
||||
}
|
||||
|
||||
void DockWidgetBase::onHidden(bool spontaneous)
|
||||
@@ -807,7 +737,7 @@ void DockWidgetBase::onHidden(bool spontaneous)
|
||||
d->onDockWidgetHidden();
|
||||
Q_EMIT hidden();
|
||||
|
||||
if (Frame *f = frame()) {
|
||||
if (Frame *f = d->frame()) {
|
||||
if (!spontaneous) {
|
||||
f->onDockWidgetHidden(this);
|
||||
}
|
||||
@@ -817,7 +747,7 @@ void DockWidgetBase::onHidden(bool spontaneous)
|
||||
bool DockWidgetBase::onResize(QSize newSize)
|
||||
{
|
||||
if (isOverlayed()) {
|
||||
if (auto frame = this->frame()) {
|
||||
if (auto frame = d->frame()) {
|
||||
d->m_lastOverlayedSize = frame->QWidgetAdapter::size();
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Overlayed dock widget without frame shouldn't happen";
|
||||
@@ -865,10 +795,127 @@ DockWidgetBase *DockWidgetBase::deserialize(const LayoutSaver::DockWidget::Ptr &
|
||||
return dw;
|
||||
}
|
||||
|
||||
LayoutSaver::DockWidget::Ptr DockWidgetBase::serialize() const
|
||||
void DockWidgetBase::setUserType(int userType)
|
||||
{
|
||||
auto ptr = LayoutSaver::DockWidget::dockWidgetForName(uniqueName());
|
||||
ptr->affinities = affinities();
|
||||
d->m_userType = userType;
|
||||
}
|
||||
|
||||
int DockWidgetBase::userType() const
|
||||
{
|
||||
return d->m_userType;
|
||||
}
|
||||
|
||||
void DockWidgetBase::setMDIPosition(QPoint pos)
|
||||
{
|
||||
if (MDILayoutWidget *layout = d->mdiLayout())
|
||||
layout->moveDockWidget(this, pos);
|
||||
}
|
||||
|
||||
void DockWidgetBase::setMDISize(QSize size)
|
||||
{
|
||||
if (MDILayoutWidget *layout = d->mdiLayout())
|
||||
layout->resizeDockWidget(this, size);
|
||||
}
|
||||
|
||||
void DockWidgetBase::setMDIZ(int z)
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
if (Frame *frame = d->frame()) {
|
||||
if (!frame->isMDI())
|
||||
return;
|
||||
frame->setZ(z);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(z);
|
||||
qWarning() << Q_FUNC_INFO << "Not implemented for QtQuick";
|
||||
#endif
|
||||
}
|
||||
|
||||
LayoutSaver::DockWidget::Ptr DockWidgetBase::Private::serialize() const
|
||||
{
|
||||
auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
|
||||
ptr->affinities = q->affinities();
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::forceClose()
|
||||
{
|
||||
QScopedValueRollback<bool> rollback(m_isForceClosing, true);
|
||||
close();
|
||||
}
|
||||
|
||||
DockWidgetBase::Private::Private(const QString &dockName, DockWidgetBase::Options options_,
|
||||
LayoutSaverOptions layoutSaverOptions_, DockWidgetBase *qq)
|
||||
|
||||
: name(dockName)
|
||||
, title(dockName)
|
||||
, q(qq)
|
||||
, options(options_)
|
||||
, layoutSaverOptions(layoutSaverOptions_)
|
||||
, toggleAction(new QAction(q))
|
||||
, floatAction(new QAction(q))
|
||||
{
|
||||
q->connect(toggleAction, &QAction::toggled, q, [this](bool enabled) {
|
||||
if (!m_updatingToggleAction) { // guard against recursiveness
|
||||
toggleAction->blockSignals(true); // and don't emit spurious toggle. Like when a dock
|
||||
// widget is inserted into a tab widget it might get
|
||||
// hide events, ignore those. The Dock Widget is open.
|
||||
m_processingToggleAction = true;
|
||||
toggle(enabled);
|
||||
toggleAction->blockSignals(false);
|
||||
m_processingToggleAction = false;
|
||||
}
|
||||
});
|
||||
|
||||
q->connect(floatAction, &QAction::toggled, q, [this](bool checked) {
|
||||
if (!m_updatingFloatAction) { // guard against recursiveness
|
||||
q->setFloating(checked);
|
||||
}
|
||||
|
||||
Q_EMIT q->isFloatingChanged(checked);
|
||||
|
||||
// When floating, we remove from the sidebar
|
||||
if (checked && q->isOpen()) {
|
||||
if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
|
||||
sb->mainWindow()->clearSideBarOverlay(/* deleteFrame=*/false);
|
||||
sb->removeDockWidget(q);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
toggleAction->setCheckable(true);
|
||||
floatAction->setCheckable(true);
|
||||
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::addPlaceholderItem(Layouting::Item *item)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
m_lastPositions.addPosition(item);
|
||||
}
|
||||
|
||||
LastPositions &DockWidgetBase::Private::lastPositions()
|
||||
{
|
||||
return m_lastPositions;
|
||||
}
|
||||
|
||||
Frame *DockWidgetBase::Private::frame() const
|
||||
{
|
||||
QWidgetOrQuick *p = q->parentWidget();
|
||||
while (p) {
|
||||
if (auto frame = qobject_cast<Frame *>(p))
|
||||
return frame;
|
||||
p = p->parentWidget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DockWidgetBase::Private::saveLastFloatingGeometry()
|
||||
{
|
||||
if (q->isFloating() && q->isVisible()) {
|
||||
// It's getting docked, save last floating position
|
||||
lastPositions().setLastFloatingGeometry(q->window()->geometry());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,25 +22,17 @@
|
||||
#include "docks_export.h"
|
||||
#include "KDDockWidgets.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "LayoutSaver.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <memory>
|
||||
|
||||
// clazy:excludeall=ctor-missing-parent-argument
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace Layouting {
|
||||
class Item;
|
||||
}
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
struct LastPositions;
|
||||
class Frame;
|
||||
class FloatingWindow;
|
||||
class DragController;
|
||||
@@ -51,6 +43,8 @@ class TitleBar;
|
||||
class MainWindowBase;
|
||||
class StateDragging;
|
||||
class FrameQuick;
|
||||
class DockWidgetQuick;
|
||||
class LayoutWidget;
|
||||
|
||||
/**
|
||||
* @brief The DockWidget base-class. DockWidget and DockWidgetBase are only
|
||||
@@ -75,10 +69,19 @@ public:
|
||||
enum Option {
|
||||
Option_None = 0, ///< No option, the default
|
||||
Option_NotClosable = 1, ///< The DockWidget can't be closed on the [x], only programatically
|
||||
Option_NotDockable = 2 ///< The DockWidget can't be docked, it's always floating
|
||||
Option_NotDockable = 2, ///< The DockWidget can't be docked, it's always floating
|
||||
Option_DeleteOnClose = 4 ///< Deletes the DockWidget when closed
|
||||
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
|
||||
/// @brief Options which will affect LayoutSaver save/restore
|
||||
enum class LayoutSaverOption {
|
||||
None = 0, ///< Just use the defaults
|
||||
Skip = 1, ///< The dock widget won't participate in save/restore. Currently only available for floating windows.
|
||||
};
|
||||
Q_DECLARE_FLAGS(LayoutSaverOptions, LayoutSaverOption)
|
||||
|
||||
enum class IconPlace {
|
||||
TitleBar = 1,
|
||||
TabBar = 2,
|
||||
@@ -91,12 +94,15 @@ public:
|
||||
/**
|
||||
* @brief constructs a new DockWidget
|
||||
* @param uniqueName the name of the dockwidget, should be unique. Use title for user visible text.
|
||||
* @param options optional options controlling behaviour
|
||||
* @param options the options controlling certain behaviours
|
||||
* @param layoutSaverOptions the options to control save/restore
|
||||
*
|
||||
* There's no parent argument. The DockWidget is either parented to FloatingWindow or MainWindow
|
||||
* when visible, or stays without a parent when hidden.
|
||||
*/
|
||||
explicit DockWidgetBase(const QString &uniqueName, Options options = DockWidgetBase::Options());
|
||||
explicit DockWidgetBase(const QString &uniqueName,
|
||||
Options options = DockWidgetBase::Options(),
|
||||
LayoutSaverOptions layoutSaverOptions = LayoutSaverOptions());
|
||||
|
||||
///@brief destructor
|
||||
~DockWidgetBase() override;
|
||||
@@ -158,7 +164,7 @@ public:
|
||||
*
|
||||
* Returns true if the request was accomplished
|
||||
*/
|
||||
bool setFloating(bool floats);
|
||||
Q_INVOKABLE bool setFloating(bool floats);
|
||||
|
||||
/**
|
||||
* @brief Returns the QAction that allows to hide/show the dock widget
|
||||
@@ -192,12 +198,28 @@ public:
|
||||
*/
|
||||
void setTitle(const QString &title);
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the dock widget's parent frame.
|
||||
*
|
||||
* This will always be bigger than the DockWidget's size, as there's margins and a title bar.
|
||||
* Also, a frame can contain more than 1 dock widget (tabbed), meaning the geometry will account
|
||||
* for the tab bar and title bar.
|
||||
*
|
||||
* The position of the rect is in layout coordinates. 0,0 is the top-left of the layout
|
||||
* holding the widgets.
|
||||
*/
|
||||
QRect frameGeometry() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the dock widget's options which control behaviour.
|
||||
* @sa setOptions(), optionsChanged()
|
||||
*/
|
||||
Options options() const;
|
||||
|
||||
/// @brief returns the per-dockwidget options which will affect LayoutSaver
|
||||
/// These are the options which were passed to the constructor
|
||||
KDDockWidgets::DockWidgetBase::LayoutSaverOptions layoutSaverOptions() const;
|
||||
|
||||
/**
|
||||
* @brief Setter for the options.
|
||||
* Only Option_NotClosable is allowed to change after construction. For the other options use
|
||||
@@ -230,6 +252,12 @@ public:
|
||||
*/
|
||||
void setAsCurrentTab();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns which tab index this dock widget occupies in the tab widget it's contained in
|
||||
*/
|
||||
int tabIndex() const;
|
||||
|
||||
/**
|
||||
* @brief Sets an icon to show on title bars and tab bars.
|
||||
* @param places Specifies where the icon will be shown (TitleBar, TabBar, ToggleAction, or All)
|
||||
@@ -322,7 +350,7 @@ public:
|
||||
bool isMainWindow() const;
|
||||
|
||||
/**
|
||||
* @brief Returns whether this dock widget is docked into a main window.
|
||||
* @brief Returns whether this dock widget is docked into a main window (as opposed to floating)
|
||||
*
|
||||
* Note that isFloating() returning false might either mean the dock widget is docked into a
|
||||
* main window or into a floating window (groupped/nested with other dock widgets. Use this function
|
||||
@@ -331,6 +359,7 @@ public:
|
||||
bool isInMainWindow() const;
|
||||
|
||||
/// @brief Returns the main window this dock widget is in. nullptr if it's not inside a main window
|
||||
/// Also returns nullptr if it's minimized to a sidebar
|
||||
MainWindowBase *mainWindow() const;
|
||||
|
||||
///@brief Returns whether This or any child of this dock widget is focused
|
||||
@@ -350,15 +379,22 @@ public:
|
||||
*/
|
||||
void moveToSideBar();
|
||||
|
||||
/// @brief Returns whether this dock widget is overlayed on top of the main window, instead of
|
||||
/// docked into the layout. This is only relevant when using the auto-hide and side-bar feature.
|
||||
/// @brief Returns whether this dock widget is overlayed from the side-bar.
|
||||
///
|
||||
/// This is only relevant when using the auto-hide and side-bar feature.
|
||||
/// Not to be confused with "floating", which means top-level window.
|
||||
bool isOverlayed() const;
|
||||
|
||||
///@brief Returns whether this dock widget is in a side bar, and which.
|
||||
/// SideBarLocation::None is returned if it's not in a sidebar.
|
||||
/// This is only relevant when using the auto-hide and side-bar feature.
|
||||
/// @sa isInSideBar
|
||||
SideBarLocation sideBarLocation() const;
|
||||
|
||||
/// @brief Returns where this dockwidget is in a sidebar
|
||||
/// Similar to sideBarLocation(), but returns a bool
|
||||
bool isInSideBar() const;
|
||||
|
||||
/// @brief Returns whether this floating dock widget knows its previous docked location
|
||||
/// Result only makes sense if it's floating.
|
||||
///
|
||||
@@ -375,6 +411,34 @@ public:
|
||||
/// nullptr is returned if the dock widget isn't found.
|
||||
static DockWidgetBase* byName(const QString &uniqueName);
|
||||
|
||||
/// @brief Returns whether this widget has the LayoutSaverOption::Skip flag
|
||||
bool skipsRestore() const;
|
||||
|
||||
/// @brief If this dock widget is floating, then sets its geometry to @p geo.
|
||||
///
|
||||
/// If this dock widget is hidden then it stores the geometry so it can be used the next
|
||||
/// time it becomes floating.
|
||||
///
|
||||
/// This is just convenience, equivalent to calling window()->setGeometry(rect), with the
|
||||
/// added bonus of remembering the requested geometry in case it's still hidden.
|
||||
void setFloatingGeometry(QRect geo);
|
||||
|
||||
///@brief Allows the user to set a type on this dock widget
|
||||
///The type is opaque and will not be interpreted by KDDockWidgets.
|
||||
///This type is passed to FrameWorkWidgetFactory::createTitleBar(), which the user can override
|
||||
///and return different TitleBar subclasses, depending on the type.
|
||||
void setUserType(int userType);
|
||||
int userType() const;
|
||||
|
||||
/// @brief Sets this dock widgets position to pos within the MDI layout
|
||||
/// This only applies if the main window is in MDI mode, which it is not by default
|
||||
void setMDIPosition(QPoint pos);
|
||||
/// @brief like setMDIPosition(), but for the size.
|
||||
void setMDISize(QSize size);
|
||||
/// @brief like setMDIPosition(), but for the Z
|
||||
/// only implemented for QtQuick
|
||||
void setMDIZ(int z);
|
||||
|
||||
Q_SIGNALS:
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
///@brief signal emitted when the parent changed
|
||||
@@ -424,6 +488,9 @@ Q_SIGNALS:
|
||||
/// have it's 'activeWindow' property updated yet at this point.
|
||||
void windowActiveAboutToChange(bool activated);
|
||||
|
||||
///@brief Emitted when the title bar that serves this dock widget changes
|
||||
void actualTitleBarChanged();
|
||||
|
||||
protected:
|
||||
void onParentChanged();
|
||||
void onShown(bool spontaneous);
|
||||
@@ -434,21 +501,6 @@ protected:
|
||||
bool onResize(QSize newSize) override;
|
||||
#endif
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
public Q_SLOTS:
|
||||
#else
|
||||
private Q_SLOTS:
|
||||
#endif
|
||||
/**
|
||||
* @brief Creates a FloatingWindow and adds itself into it
|
||||
* @return the created FloatingWindow
|
||||
*/
|
||||
KDDockWidgets::FloatingWindow *morphIntoFloatingWindow();
|
||||
|
||||
/// @brief calls morphIntoFloatingWindow() if the dock widget is visible and is a top-level
|
||||
/// This is called delayed whenever we show a floating dock widget, so we get a FloatingWindow
|
||||
void maybeMorphIntoFloatingWindow();
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
public:
|
||||
#else
|
||||
@@ -456,6 +508,8 @@ private:
|
||||
#endif
|
||||
Q_DISABLE_COPY(DockWidgetBase)
|
||||
friend class MultiSplitter;
|
||||
friend class LayoutWidget;
|
||||
friend class MDILayoutWidget;
|
||||
friend class Frame;
|
||||
friend class DropArea;
|
||||
friend class ::TestDocks;
|
||||
@@ -467,125 +521,22 @@ private:
|
||||
friend class KDDockWidgets::LayoutSaver;
|
||||
friend class KDDockWidgets::MainWindowBase;
|
||||
friend class KDDockWidgets::FrameQuick;
|
||||
friend class KDDockWidgets::DockWidgetQuick;
|
||||
|
||||
/**
|
||||
* @brief Constructs a dock widget from its serialized form.
|
||||
* @internal
|
||||
*/
|
||||
static DockWidgetBase *deserialize(const LayoutSaver::DockWidget::Ptr &);
|
||||
static DockWidgetBase *deserialize(const std::shared_ptr<LayoutSaver::DockWidget> &);
|
||||
|
||||
/**
|
||||
* @brief Serializes this dock widget into an intermediate form
|
||||
*/
|
||||
LayoutSaver::DockWidget::Ptr serialize() const;
|
||||
|
||||
/**
|
||||
* @brief the Frame which contains this dock widgets.
|
||||
*
|
||||
* A frame wraps a docked DockWidget, giving it a TabWidget so it can accept other dock widgets.
|
||||
* Frame is also the actual class that goes into a MultiSplitter.
|
||||
*
|
||||
* It's nullptr immediately after creation.
|
||||
*/
|
||||
Frame *frame() const;
|
||||
|
||||
/**
|
||||
* @brief returns the FloatingWindow this dock widget is in. If nullptr then it's in a MainWindow.
|
||||
*
|
||||
* Note: Being in a FloatingWindow doesn't necessarily mean @ref isFloating() returns true, as
|
||||
* the dock widget might be in a floating window with other dock widgets side by side.
|
||||
*/
|
||||
FloatingWindow *floatingWindow() const;
|
||||
|
||||
///@brief adds the current layout item containing this dock widget
|
||||
void addPlaceholderItem(Layouting::Item*);
|
||||
|
||||
///@brief returns the last position, just for tests. TODO Make tests just use the d-pointer.
|
||||
LastPositions &lastPositions() const;
|
||||
|
||||
///@brief If this dock widget is floating, then it saves its geometry
|
||||
void saveLastFloatingGeometry();
|
||||
|
||||
///@brief Updates the floatAction state
|
||||
void updateFloatAction();
|
||||
|
||||
///@reimp
|
||||
bool eventFilter(QObject *, QEvent *) override;
|
||||
|
||||
class Private;
|
||||
Private *const d;
|
||||
|
||||
Private *dptr() const;
|
||||
};
|
||||
|
||||
}
|
||||
Q_DECLARE_METATYPE(KDDockWidgets::Location)
|
||||
|
||||
#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
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
*/
|
||||
|
||||
#include "DockWidgetQuick.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "private/quick/FrameQuick_p.h"
|
||||
|
||||
#include <Config.h>
|
||||
#include <QQuickItem>
|
||||
@@ -29,7 +32,8 @@ class DockWidgetQuick::Private
|
||||
public:
|
||||
Private(DockWidgetQuick *dw)
|
||||
: q(dw)
|
||||
, m_visualItem(q->createItem(Config::self().qmlEngine(), QStringLiteral("qrc:/kddockwidgets/private/quick/qml/DockWidget.qml")))
|
||||
, m_visualItem(q->createItem(Config::self().qmlEngine(),
|
||||
Config::self().frameworkWidgetFactory()->dockwidgetFilename().toString()))
|
||||
{
|
||||
Q_ASSERT(m_visualItem);
|
||||
m_visualItem->setParent(q);
|
||||
@@ -40,8 +44,8 @@ public:
|
||||
QQuickItem *const m_visualItem;
|
||||
};
|
||||
|
||||
DockWidgetQuick::DockWidgetQuick(const QString &name, Options options)
|
||||
: DockWidgetBase(name, options)
|
||||
DockWidgetQuick::DockWidgetQuick(const QString &name, Options options, LayoutSaverOptions layoutSaverOptions)
|
||||
: DockWidgetBase(name, options, layoutSaverOptions)
|
||||
, d(new Private(this))
|
||||
{
|
||||
// To mimic what QtWidgets does when creating a new QWidget.
|
||||
@@ -59,11 +63,7 @@ void DockWidgetQuick::setWidget(const QString &qmlFilename)
|
||||
if (!guest)
|
||||
return;
|
||||
|
||||
auto adapter = new QWidgetAdapter(this);
|
||||
guest->setParentItem(adapter);
|
||||
guest->setParent(adapter);
|
||||
|
||||
setWidget(adapter);
|
||||
setWidget(guest);
|
||||
}
|
||||
|
||||
void DockWidgetQuick::setWidget(QWidgetAdapter *widget)
|
||||
@@ -73,10 +73,27 @@ void DockWidgetQuick::setWidget(QWidgetAdapter *widget)
|
||||
DockWidgetBase::setWidget(widget);
|
||||
}
|
||||
|
||||
void DockWidgetQuick::setWidget(QQuickItem *guest)
|
||||
{
|
||||
auto adapter = new QWidgetAdapter(this);
|
||||
adapter->setIsWrapper();
|
||||
|
||||
// In case the user app needs to use them:
|
||||
adapter->setProperty("originalParent", QVariant::fromValue(guest->parent()));
|
||||
adapter->setProperty("originalParentItem", QVariant::fromValue(guest->parentItem()));
|
||||
|
||||
guest->setParentItem(adapter);
|
||||
guest->setParent(adapter);
|
||||
QWidgetAdapter::makeItemFillParent(guest);
|
||||
|
||||
setWidget(adapter);
|
||||
}
|
||||
|
||||
bool DockWidgetQuick::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::ParentChange) {
|
||||
onParentChanged();
|
||||
Q_EMIT actualTitleBarChanged();
|
||||
} else if (e->type() == QEvent::Show) {
|
||||
onShown(e->spontaneous());
|
||||
} else if (e->type() == QEvent::Hide) {
|
||||
@@ -107,3 +124,31 @@ QSize DockWidgetQuick::maximumSize() const
|
||||
|
||||
return DockWidgetBase::maximumSize();
|
||||
}
|
||||
|
||||
TitleBar *DockWidgetQuick::actualTitleBar() const
|
||||
{
|
||||
if (Frame *frame = DockWidgetBase::d->frame())
|
||||
return frame->actualTitleBar();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QQuickItem *DockWidgetQuick::frameVisualItem() const
|
||||
{
|
||||
if (auto frame = qobject_cast<FrameQuick *>(DockWidgetBase::d->frame()))
|
||||
return frame->visualItem();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DockWidgetQuick::onGeometryUpdated()
|
||||
{
|
||||
if (auto frame = qobject_cast<FrameQuick *>(DockWidgetBase::d->frame())) {
|
||||
frame->updateConstriants();
|
||||
frame->updateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
Frame *DockWidgetQuick::frame() const
|
||||
{
|
||||
return qobject_cast<FrameQuick *>(DockWidgetBase::d->frame());
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define KD_DOCKWIDGET_QUICK_H
|
||||
|
||||
#include "DockWidgetBase.h"
|
||||
#include "private/TitleBar_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCloseEvent;
|
||||
@@ -27,6 +28,8 @@ QT_END_NAMESPACE
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class Frame;
|
||||
|
||||
/**
|
||||
* @brief Represents a dock widget.
|
||||
*
|
||||
@@ -35,17 +38,18 @@ namespace KDDockWidgets {
|
||||
class DOCKS_EXPORT DockWidgetQuick : public DockWidgetBase
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(KDDockWidgets::TitleBar* actualTitleBar READ actualTitleBar NOTIFY actualTitleBarChanged)
|
||||
public:
|
||||
/**
|
||||
* @brief constructs a new DockWidget
|
||||
* @param name the name of the dockwidget, should be unique. Use title for user visible text.
|
||||
* @param uniqueName the name of the dockwidget, should be unique. Use title for user visible text.
|
||||
* @param options optional options controlling behaviour
|
||||
* @param parent optional QWidget parent, for ownership purposes
|
||||
*
|
||||
* There's no parent argument. The DockWidget is either parented to FloatingWindow or MainWindow
|
||||
* when visible, or stays without a parent when hidden.
|
||||
*/
|
||||
explicit DockWidgetQuick(const QString &uniqueName, Options options = {});
|
||||
explicit DockWidgetQuick(const QString &uniqueName, Options options = {},
|
||||
LayoutSaverOptions layoutSaverOptions = LayoutSaverOptions());
|
||||
|
||||
///@brief destructor
|
||||
~DockWidgetQuick() override;
|
||||
@@ -57,12 +61,28 @@ public:
|
||||
/// @reimp
|
||||
void setWidget(QWidgetAdapter *widget) override;
|
||||
|
||||
/// @reimp
|
||||
Q_INVOKABLE void setWidget(QQuickItem *widget);
|
||||
|
||||
/// @reimp
|
||||
QSize minimumSize() const override;
|
||||
|
||||
/// @reimp
|
||||
QSize maximumSize() const override;
|
||||
|
||||
/// @brief Returns the title bar
|
||||
TitleBar *actualTitleBar() const;
|
||||
|
||||
/// @brief Returns the visual item which represents Frame in the screen
|
||||
/// Equivalent to Frame::visualItem().
|
||||
QQuickItem *frameVisualItem() const;
|
||||
|
||||
///@internal
|
||||
Frame *frame() const;
|
||||
|
||||
/// @brief Called by QtQuick when min-size changes
|
||||
Q_INVOKABLE void onGeometryUpdated();
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
|
||||
@@ -217,6 +217,21 @@ QUrl DefaultWidgetFactory::titleBarFilename() const
|
||||
return QUrl(QStringLiteral("qrc:/kddockwidgets/private/quick/qml/TitleBar.qml"));
|
||||
}
|
||||
|
||||
QUrl DefaultWidgetFactory::dockwidgetFilename() const
|
||||
{
|
||||
return QUrl(QStringLiteral("qrc:/kddockwidgets/private/quick/qml/DockWidget.qml"));
|
||||
}
|
||||
|
||||
QUrl DefaultWidgetFactory::frameFilename() const
|
||||
{
|
||||
return QUrl(QStringLiteral("qrc:/kddockwidgets/private/quick/qml/Frame.qml"));
|
||||
}
|
||||
|
||||
QUrl DefaultWidgetFactory::floatingWindowFilename() const
|
||||
{
|
||||
return QUrl(QStringLiteral("qrc:/kddockwidgets/private/quick/qml/FloatingWindow.qml"));
|
||||
}
|
||||
|
||||
#endif // QtQuick
|
||||
|
||||
// iconForButtonType impl is the same for QtQuick and QtWidgets
|
||||
@@ -252,25 +267,15 @@ QIcon DefaultWidgetFactory::iconForButtonType(TitleBarButtonType type, qreal dpr
|
||||
return {};
|
||||
|
||||
QIcon icon(QStringLiteral(":/img/%1.png").arg(iconName));
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
|
||||
const bool isFractional = int(dpr) != dpr;
|
||||
if (isFractional) {
|
||||
// We don't support 1.5x yet.
|
||||
// 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.
|
||||
if (!scalingFactorIsSupported(dpr))
|
||||
return icon;
|
||||
}
|
||||
#else
|
||||
|
||||
// Not using Qt's sugar syntax, which doesn't support 1.5x anyway when we need it.
|
||||
// Simply add the high-res files and Qt will pick them when needed
|
||||
|
||||
icon.addFile(QStringLiteral(":/img/%1-1.5x.png").arg(iconName));
|
||||
Q_UNUSED(dpr);
|
||||
#endif
|
||||
if (scalingFactorIsSupported(1.5))
|
||||
icon.addFile(QStringLiteral(":/img/%1-1.5x.png").arg(iconName));
|
||||
|
||||
icon.addFile(QStringLiteral(":/img/%1-2x.png").arg(iconName));
|
||||
|
||||
return icon;
|
||||
|
||||
@@ -66,9 +66,6 @@ class TabWidgetQuick;
|
||||
*/
|
||||
class DOCKS_EXPORT FrameworkWidgetFactory : public QObject
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
Q_PROPERTY(QUrl titleBarFilename READ titleBarFilename CONSTANT)
|
||||
#endif
|
||||
Q_OBJECT
|
||||
public:
|
||||
FrameworkWidgetFactory() = default;
|
||||
@@ -146,6 +143,9 @@ public:
|
||||
virtual QAbstractButton* createTitleBarButton(QWidget *parent, TitleBarButtonType) const = 0;
|
||||
#else
|
||||
virtual QUrl titleBarFilename() const = 0;
|
||||
virtual QUrl dockwidgetFilename() const = 0;
|
||||
virtual QUrl frameFilename() const = 0;
|
||||
virtual QUrl floatingWindowFilename() const = 0;
|
||||
#endif
|
||||
|
||||
/// @brief Returns the icon to be used with the specified @p type
|
||||
@@ -178,7 +178,10 @@ public:
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
QAbstractButton* createTitleBarButton(QWidget *parent, TitleBarButtonType) const override;
|
||||
#else
|
||||
QUrl titleBarFilename() const override;
|
||||
Q_INVOKABLE QUrl titleBarFilename() const override;
|
||||
QUrl dockwidgetFilename() const override;
|
||||
QUrl frameFilename() const override;
|
||||
QUrl floatingWindowFilename() const override;
|
||||
#endif
|
||||
|
||||
QIcon iconForButtonType(TitleBarButtonType type, qreal dpr) const override;
|
||||
|
||||
@@ -36,6 +36,7 @@ class ItemBoxContainer;
|
||||
|
||||
namespace KDDockWidgets
|
||||
{
|
||||
Q_NAMESPACE
|
||||
class MultiSplitter;
|
||||
class DropArea;
|
||||
|
||||
@@ -49,7 +50,8 @@ namespace KDDockWidgets
|
||||
|
||||
enum MainWindowOption {
|
||||
MainWindowOption_None = 0, ///> No option set
|
||||
MainWindowOption_HasCentralFrame = 1 ///> Makes the MainWindow always have a central frame, for tabbing documents
|
||||
MainWindowOption_HasCentralFrame = 1, ///> Makes the MainWindow always have a central frame, for tabbing documents
|
||||
MainWindowOption_MDI = 2 ///> EXPERIMENTAL!!1 The layout will be MDI. DockWidgets can have arbitrary positions, not restricted by any layout
|
||||
};
|
||||
Q_DECLARE_FLAGS(MainWindowOptions, MainWindowOption)
|
||||
|
||||
@@ -154,15 +156,6 @@ namespace KDDockWidgets
|
||||
const DefaultSizeMode sizeMode = DefaultSizeMode::Fair;
|
||||
};
|
||||
|
||||
///@internal
|
||||
enum FrameOption {
|
||||
FrameOption_None = 0,
|
||||
FrameOption_AlwaysShowsTabs = 1,
|
||||
FrameOption_IsCentralFrame = 2,
|
||||
FrameOption_IsOverlayed = 4
|
||||
};
|
||||
Q_DECLARE_FLAGS(FrameOptions, FrameOption)
|
||||
|
||||
enum RestoreOption {
|
||||
RestoreOption_None = 0,
|
||||
RestoreOption_RelativeToMainWindow = 1, ///< Skips restoring the main window geometry and the restored dock widgets will use relative sizing.
|
||||
@@ -177,23 +170,12 @@ namespace KDDockWidgets
|
||||
};
|
||||
|
||||
///@internal
|
||||
inline QString locationStr(Location loc)
|
||||
{
|
||||
switch (loc) {
|
||||
case KDDockWidgets::Location_None:
|
||||
return QStringLiteral("none");
|
||||
case KDDockWidgets::Location_OnLeft:
|
||||
return QStringLiteral("left");
|
||||
case KDDockWidgets::Location_OnTop:
|
||||
return QStringLiteral("top");
|
||||
case KDDockWidgets::Location_OnRight:
|
||||
return QStringLiteral("right");
|
||||
case KDDockWidgets::Location_OnBottom:
|
||||
return QStringLiteral("bottom");
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
enum SuggestedGeometryHint {
|
||||
SuggestedGeometryHint_None,
|
||||
SuggestedGeometryHint_PreserveCenter = 1,
|
||||
SuggestedGeometryHint_GeometryIsFromDocked = 2
|
||||
};
|
||||
Q_DECLARE_FLAGS(SuggestedGeometryHints, SuggestedGeometryHint)
|
||||
|
||||
/// @brief Each main window supports 4 sidebars
|
||||
enum class SideBarLocation {
|
||||
@@ -220,6 +202,52 @@ namespace KDDockWidgets
|
||||
{
|
||||
return ::qHash(static_cast<uint>(loc), seed);
|
||||
}
|
||||
|
||||
///@internal
|
||||
enum CursorPosition {
|
||||
CursorPosition_Undefined = 0,
|
||||
CursorPosition_Left = 1,
|
||||
CursorPosition_Right = 2,
|
||||
CursorPosition_Top = 4,
|
||||
CursorPosition_Bottom = 8,
|
||||
CursorPosition_TopLeft = CursorPosition_Top | CursorPosition_Left,
|
||||
CursorPosition_TopRight = CursorPosition_Top | CursorPosition_Right,
|
||||
CursorPosition_BottomRight = CursorPosition_Bottom | CursorPosition_Right,
|
||||
CursorPosition_BottomLeft = CursorPosition_Bottom | CursorPosition_Left,
|
||||
CursorPosition_Horizontal = CursorPosition_Right | CursorPosition_Left,
|
||||
CursorPosition_Vertical = CursorPosition_Top | CursorPosition_Bottom,
|
||||
CursorPosition_All = CursorPosition_Left | CursorPosition_Right | CursorPosition_Top | CursorPosition_Bottom
|
||||
};
|
||||
Q_DECLARE_FLAGS(CursorPositions, CursorPosition)
|
||||
Q_ENUM_NS(CursorPosition)
|
||||
|
||||
///@internal
|
||||
enum FrameOption {
|
||||
FrameOption_None = 0,
|
||||
FrameOption_AlwaysShowsTabs = 1,
|
||||
FrameOption_IsCentralFrame = 2,
|
||||
FrameOption_IsOverlayed = 4
|
||||
};
|
||||
Q_DECLARE_FLAGS(FrameOptions, FrameOption)
|
||||
|
||||
///@internal
|
||||
inline QString locationStr(Location loc)
|
||||
{
|
||||
switch (loc) {
|
||||
case KDDockWidgets::Location_None:
|
||||
return QStringLiteral("none");
|
||||
case KDDockWidgets::Location_OnLeft:
|
||||
return QStringLiteral("left");
|
||||
case KDDockWidgets::Location_OnTop:
|
||||
return QStringLiteral("top");
|
||||
case KDDockWidgets::Location_OnRight:
|
||||
return QStringLiteral("right");
|
||||
case KDDockWidgets::Location_OnBottom:
|
||||
return QStringLiteral("bottom");
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@@ -16,7 +16,7 @@ if (@KDDockWidgets_QTQUICK@)
|
||||
find_dependency(Qt5Quick REQUIRED)
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN)
|
||||
find_dependency(Qt5X11Extras REQUIRED)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -17,17 +17,18 @@
|
||||
*/
|
||||
|
||||
#include "LayoutSaver.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "Config.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "Position_p.h"
|
||||
|
||||
#include <qmath.h>
|
||||
#include <QDebug>
|
||||
@@ -69,6 +70,9 @@ public:
|
||||
return m_affinityNames.isEmpty() || affinities.isEmpty() || DockRegistry::self()->affinitiesMatch(m_affinityNames, affinities);
|
||||
}
|
||||
|
||||
|
||||
void floatWidgetsWhichSkipRestore(const QStringList &mainWindowNames);
|
||||
|
||||
template <typename T>
|
||||
void deserializeWindowGeometry(const T &saved, QWidgetOrQuick *topLevel);
|
||||
void deleteEmptyFrames();
|
||||
@@ -174,7 +178,7 @@ QByteArray LayoutSaver::serializeLayout() const
|
||||
layout.closedDockWidgets.reserve(closedDockWidgets.size());
|
||||
for (DockWidgetBase *dockWidget : closedDockWidgets) {
|
||||
if (d->matchesAffinity(dockWidget->affinities()))
|
||||
layout.closedDockWidgets.push_back(dockWidget->serialize());
|
||||
layout.closedDockWidgets.push_back(dockWidget->d->serialize());
|
||||
}
|
||||
|
||||
// Save the placeholder info. We do it last, as we also restore it last, since we need all items to be created
|
||||
@@ -184,8 +188,8 @@ QByteArray LayoutSaver::serializeLayout() const
|
||||
layout.allDockWidgets.reserve(dockWidgets.size());
|
||||
for (DockWidgetBase *dockWidget : dockWidgets) {
|
||||
if (d->matchesAffinity(dockWidget->affinities())) {
|
||||
auto dw = dockWidget->serialize();
|
||||
dw->lastPosition = dockWidget->lastPositions().serialize();
|
||||
auto dw = dockWidget->d->serialize();
|
||||
dw->lastPosition = dockWidget->d->lastPositions().serialize();
|
||||
layout.allDockWidgets.push_back(dw);
|
||||
}
|
||||
}
|
||||
@@ -229,9 +233,12 @@ bool LayoutSaver::restoreLayout(const QByteArray &data)
|
||||
if (d->m_restoreOptions & RestoreOption_RelativeToMainWindow)
|
||||
layout.scaleSizes();
|
||||
|
||||
d->floatWidgetsWhichSkipRestore(layout.mainWindowNames());
|
||||
|
||||
// Hide all dockwidgets and unparent them from any layout before starting restore
|
||||
// We only close the stuff that the loaded JSON knows about. Unknown widgets might be newer.
|
||||
d->m_dockRegistry->clear(d->m_dockRegistry->dockWidgets(layout.dockWidgetNames()),
|
||||
|
||||
d->m_dockRegistry->clear(d->m_dockRegistry->dockWidgets(layout.dockWidgetsToClose()),
|
||||
d->m_dockRegistry->mainWindows(layout.mainWindowNames()),
|
||||
d->m_affinityNames);
|
||||
|
||||
@@ -258,14 +265,15 @@ bool LayoutSaver::restoreLayout(const QByteArray &data)
|
||||
}
|
||||
|
||||
// 2. Restore FloatingWindows
|
||||
for (const LayoutSaver::FloatingWindow &fw : qAsConst(layout.floatingWindows)) {
|
||||
if (!d->matchesAffinity(fw.affinities))
|
||||
for (LayoutSaver::FloatingWindow &fw : layout.floatingWindows) {
|
||||
if (!d->matchesAffinity(fw.affinities) || fw.skipsRestore())
|
||||
continue;
|
||||
|
||||
MainWindowBase *parent = fw.parentIndex == -1 ? nullptr
|
||||
: DockRegistry::self()->mainwindows().at(fw.parentIndex);
|
||||
|
||||
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(parent);
|
||||
fw.floatingWindowInstance = floatingWindow;
|
||||
d->deserializeWindowGeometry(fw, floatingWindow);
|
||||
if (!floatingWindow->deserialize(fw)) {
|
||||
qWarning() << Q_FUNC_INFO << "Failed to deserialize floating window";
|
||||
@@ -286,7 +294,7 @@ bool LayoutSaver::restoreLayout(const QByteArray &data)
|
||||
continue;
|
||||
|
||||
if (DockWidgetBase *dockWidget = d->m_dockRegistry->dockByName(dw->uniqueName)) {
|
||||
dockWidget->lastPositions().deserialize(dw->lastPosition);
|
||||
dockWidget->d->lastPositions().deserialize(dw->lastPosition);
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Couldn't find dock widget" << dw->uniqueName;
|
||||
}
|
||||
@@ -332,6 +340,24 @@ void LayoutSaver::Private::deserializeWindowGeometry(const T &saved, QWidgetOrQu
|
||||
topLevel->setVisible(saved.isVisible);
|
||||
}
|
||||
|
||||
void LayoutSaver::Private::floatWidgetsWhichSkipRestore(const QStringList &mainWindowNames)
|
||||
{
|
||||
// Widgets with the DockWidget::LayoutSaverOption::Skip flag skip restore completely.
|
||||
// If they were visible before they need to remain visible now.
|
||||
// If they were previously docked we need to float them, as the main window they were on will
|
||||
// be loading a new layout.
|
||||
|
||||
for (MainWindowBase *mw : DockRegistry::self()->mainWindows(mainWindowNames)) {
|
||||
const KDDockWidgets::DockWidgetBase::List docks = mw->layoutWidget()->dockWidgets();
|
||||
for (auto dw : docks) {
|
||||
if (dw->skipsRestore()) {
|
||||
dw->setFloating(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LayoutSaver::Private::deleteEmptyFrames()
|
||||
{
|
||||
// After a restore it can happen that some DockWidgets didn't exist, so weren't restored.
|
||||
@@ -471,6 +497,14 @@ LayoutSaver::MainWindow LayoutSaver::Layout::mainWindowForIndex(int index) const
|
||||
return mainWindows.at(index);
|
||||
}
|
||||
|
||||
LayoutSaver::FloatingWindow LayoutSaver::Layout::floatingWindowForIndex(int index) const
|
||||
{
|
||||
if (index < 0 || index >= floatingWindows.size())
|
||||
return {};
|
||||
|
||||
return floatingWindows.at(index);
|
||||
}
|
||||
|
||||
QStringList LayoutSaver::Layout::mainWindowNames() const
|
||||
{
|
||||
QStringList names;
|
||||
@@ -493,6 +527,35 @@ QStringList LayoutSaver::Layout::dockWidgetNames() const
|
||||
return names;
|
||||
}
|
||||
|
||||
QStringList LayoutSaver::Layout::dockWidgetsToClose() const
|
||||
{
|
||||
// Before restoring a layout we close all dock widgets, unless they're a floating window with the DontCloseBeforeRestore flag
|
||||
|
||||
QStringList names;
|
||||
names.reserve(allDockWidgets.size());
|
||||
auto registry = DockRegistry::self();
|
||||
for (const auto &dw : allDockWidgets) {
|
||||
if (DockWidgetBase *dockWidget = registry->dockByName(dw->uniqueName)) {
|
||||
|
||||
bool doClose = true;
|
||||
|
||||
if (dockWidget->skipsRestore()) {
|
||||
if (auto fw = dockWidget->floatingWindow()) {
|
||||
if (fw->allDockWidgetsHave(DockWidgetBase::LayoutSaverOption::Skip)) {
|
||||
// All dock widgets in this floating window skips float, so we can honour it for all.
|
||||
doClose = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doClose)
|
||||
names << dw->uniqueName;
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
bool LayoutSaver::Frame::isValid() const
|
||||
{
|
||||
if (isNull)
|
||||
@@ -528,9 +591,24 @@ bool LayoutSaver::Frame::isValid() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void LayoutSaver::Frame::scaleSizes(const ScalingInfo &scalingInfo)
|
||||
bool LayoutSaver::Frame::hasSingleDockWidget() const
|
||||
{
|
||||
scalingInfo.applyFactorsTo(geometry);
|
||||
return dockWidgets.size() == 1;
|
||||
}
|
||||
|
||||
bool LayoutSaver::Frame::skipsRestore() const
|
||||
{
|
||||
return std::all_of(dockWidgets.cbegin(), dockWidgets.cend(), [] (LayoutSaver::DockWidget::Ptr dw) {
|
||||
return dw->skipsRestore();
|
||||
});
|
||||
}
|
||||
|
||||
LayoutSaver::DockWidget::Ptr LayoutSaver::Frame::singleDockWidget() const
|
||||
{
|
||||
if (!hasSingleDockWidget())
|
||||
return {};
|
||||
|
||||
return dockWidgets.first();
|
||||
}
|
||||
|
||||
QVariantMap LayoutSaver::Frame::toVariantMap() const
|
||||
@@ -583,6 +661,14 @@ void LayoutSaver::DockWidget::scaleSizes(const ScalingInfo &scalingInfo)
|
||||
lastPosition.scaleSizes(scalingInfo);
|
||||
}
|
||||
|
||||
bool LayoutSaver::DockWidget::skipsRestore() const
|
||||
{
|
||||
if (DockWidgetBase *dw = DockRegistry::self()->dockByName(uniqueName))
|
||||
return dw->skipsRestore();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariantMap LayoutSaver::DockWidget::toVariantMap() const
|
||||
{
|
||||
QVariantMap map;
|
||||
@@ -621,10 +707,24 @@ bool LayoutSaver::FloatingWindow::isValid() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LayoutSaver::FloatingWindow::hasSingleDockWidget() const
|
||||
{
|
||||
return multiSplitterLayout.hasSingleDockWidget();
|
||||
}
|
||||
|
||||
LayoutSaver::DockWidget::Ptr LayoutSaver::FloatingWindow::singleDockWidget() const
|
||||
{
|
||||
return multiSplitterLayout.singleDockWidget();
|
||||
}
|
||||
|
||||
bool LayoutSaver::FloatingWindow::skipsRestore() const
|
||||
{
|
||||
return multiSplitterLayout.skipsRestore();
|
||||
}
|
||||
|
||||
void LayoutSaver::FloatingWindow::scaleSizes(const ScalingInfo &scalingInfo)
|
||||
{
|
||||
scalingInfo.applyFactorsTo(/*by-ref*/geometry);
|
||||
multiSplitterLayout.scaleSizes(scalingInfo);
|
||||
}
|
||||
|
||||
QVariantMap LayoutSaver::FloatingWindow::toVariantMap() const
|
||||
@@ -682,9 +782,6 @@ void LayoutSaver::MainWindow::scaleSizes()
|
||||
}
|
||||
|
||||
scalingInfo = ScalingInfo(uniqueName, geometry);
|
||||
|
||||
if (scalingInfo.isValid())
|
||||
multiSplitterLayout.scaleSizes(scalingInfo);
|
||||
}
|
||||
|
||||
QVariantMap LayoutSaver::MainWindow::toVariantMap() const
|
||||
@@ -698,6 +795,7 @@ QVariantMap LayoutSaver::MainWindow::toVariantMap() const
|
||||
map.insert(QStringLiteral("screenSize"), Layouting::sizeToMap(screenSize));
|
||||
map.insert(QStringLiteral("isVisible"), isVisible);
|
||||
map.insert(QStringLiteral("affinities"), stringListToVariant(affinities));
|
||||
map.insert(QStringLiteral("windowState"), windowState);
|
||||
|
||||
for (SideBarLocation loc : { SideBarLocation::North, SideBarLocation::East, SideBarLocation::West, SideBarLocation::South }) {
|
||||
const QStringList dockWidgets = dockWidgetsPerSideBar.value(loc);
|
||||
@@ -718,6 +816,7 @@ void LayoutSaver::MainWindow::fromVariantMap(const QVariantMap &map)
|
||||
screenSize = Layouting::mapToSize(map.value(QStringLiteral("screenSize")).toMap());
|
||||
isVisible = map.value(QStringLiteral("isVisible")).toBool();
|
||||
affinities = variantToStringList(map.value(QStringLiteral("affinities")).toList());
|
||||
windowState = Qt::WindowState(map.value(QStringLiteral("windowState"), Qt::WindowNoState).toInt());
|
||||
|
||||
// Compatibility hack. Old json format had a single "affinityName" instead of an "affinities" list:
|
||||
const QString affinityName = map.value(QStringLiteral("affinityName")).toString();
|
||||
@@ -747,11 +846,24 @@ bool LayoutSaver::MultiSplitter::isValid() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void LayoutSaver::MultiSplitter::scaleSizes(const ScalingInfo &)
|
||||
bool LayoutSaver::MultiSplitter::hasSingleDockWidget() const
|
||||
{
|
||||
// scalingInfo.applyFactorsTo(/*by-ref*/size);
|
||||
//for (LayoutSaver::Item &item : items) TODO
|
||||
// item.scaleSizes(scalingInfo);
|
||||
return frames.size() == 1 && frames.cbegin()->hasSingleDockWidget();
|
||||
}
|
||||
|
||||
LayoutSaver::DockWidget::Ptr LayoutSaver::MultiSplitter::singleDockWidget() const
|
||||
{
|
||||
if (!hasSingleDockWidget())
|
||||
return {};
|
||||
|
||||
return frames.cbegin()->singleDockWidget();
|
||||
}
|
||||
|
||||
bool LayoutSaver::MultiSplitter::skipsRestore() const
|
||||
{
|
||||
return std::all_of(frames.cbegin(), frames.cend(), [] (const LayoutSaver::Frame &frame) {
|
||||
return frame.skipsRestore();
|
||||
});
|
||||
}
|
||||
|
||||
QVariantMap LayoutSaver::MultiSplitter::toVariantMap() const
|
||||
@@ -883,8 +995,7 @@ void LayoutSaver::ScalingInfo::translatePos(QPoint &pt) const
|
||||
|
||||
void LayoutSaver::ScalingInfo::applyFactorsTo(QPoint &pt) const
|
||||
{
|
||||
pt.setX(qCeil(pt.x() * widthFactor));
|
||||
pt.setY(qCeil(pt.y() * heightFactor));
|
||||
translatePos(pt);
|
||||
}
|
||||
|
||||
void LayoutSaver::ScalingInfo::applyFactorsTo(QSize &sz) const
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class FloatingWindow;
|
||||
|
||||
template <typename T>
|
||||
typename T::List fromVariantList(const QVariantList &listV)
|
||||
{
|
||||
@@ -104,6 +106,7 @@ struct LayoutSaver::Position
|
||||
int tabIndex;
|
||||
bool wasFloating;
|
||||
LayoutSaver::Placeholder::List placeholders;
|
||||
QHash<SideBarLocation, QRect> lastOverlayedGeometries;
|
||||
|
||||
/// Iterates through the layout and patches all absolute sizes. See RestoreOption_RelativeToMainWindow.
|
||||
void scaleSizes(const ScalingInfo &scalingInfo);
|
||||
@@ -137,6 +140,8 @@ struct DOCKS_EXPORT LayoutSaver::DockWidget
|
||||
return dw;
|
||||
}
|
||||
|
||||
bool skipsRestore() const;
|
||||
|
||||
QVariantMap toVariantMap() const;
|
||||
void fromVariantMap(const QVariantMap &map);
|
||||
|
||||
@@ -173,8 +178,11 @@ struct LayoutSaver::Frame
|
||||
{
|
||||
bool isValid() const;
|
||||
|
||||
/// Iterates through the layout and patches all absolute sizes. See RestoreOption_RelativeToMainWindow.
|
||||
void scaleSizes(const ScalingInfo &scalingInfo);
|
||||
bool hasSingleDockWidget() const;
|
||||
bool skipsRestore() const;
|
||||
|
||||
/// @brief in case this frame only has one frame, returns the name of that dock widget
|
||||
LayoutSaver::DockWidget::Ptr singleDockWidget() const;
|
||||
|
||||
QVariantMap toVariantMap() const;
|
||||
void fromVariantMap(const QVariantMap &map);
|
||||
@@ -192,8 +200,10 @@ struct LayoutSaver::Frame
|
||||
struct LayoutSaver::MultiSplitter
|
||||
{
|
||||
bool isValid() const;
|
||||
/// Iterates through the layout and patches all absolute sizes. See RestoreOption_RelativeToMainWindow.
|
||||
void scaleSizes(const ScalingInfo &scalingInfo);
|
||||
|
||||
bool hasSingleDockWidget() const;
|
||||
LayoutSaver::DockWidget::Ptr singleDockWidget() const;
|
||||
bool skipsRestore() const;
|
||||
|
||||
QVariantMap toVariantMap() const;
|
||||
void fromVariantMap(const QVariantMap &map);
|
||||
@@ -208,6 +218,10 @@ struct LayoutSaver::FloatingWindow
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
bool hasSingleDockWidget() const;
|
||||
LayoutSaver::DockWidget::Ptr singleDockWidget() const;
|
||||
bool skipsRestore() const;
|
||||
|
||||
/// Iterates through the layout and patches all absolute sizes. See RestoreOption_RelativeToMainWindow.
|
||||
void scaleSizes(const ScalingInfo &);
|
||||
|
||||
@@ -221,6 +235,9 @@ struct LayoutSaver::FloatingWindow
|
||||
int screenIndex;
|
||||
QSize screenSize; // for relative-size restoring
|
||||
bool isVisible = true;
|
||||
|
||||
// The instance that was created during a restore:
|
||||
KDDockWidgets::FloatingWindow *floatingWindowInstance = nullptr;
|
||||
};
|
||||
|
||||
struct LayoutSaver::MainWindow
|
||||
@@ -245,6 +262,7 @@ public:
|
||||
int screenIndex;
|
||||
QSize screenSize; // for relative-size restoring
|
||||
bool isVisible;
|
||||
Qt::WindowState windowState = Qt::WindowNoState;
|
||||
|
||||
ScalingInfo scalingInfo;
|
||||
};
|
||||
@@ -301,9 +319,11 @@ public:
|
||||
static LayoutSaver::Layout* s_currentLayoutBeingRestored;
|
||||
|
||||
LayoutSaver::MainWindow mainWindowForIndex(int index) const;
|
||||
LayoutSaver::FloatingWindow floatingWindowForIndex(int index) const;
|
||||
|
||||
QStringList mainWindowNames() const;
|
||||
QStringList dockWidgetNames() const;
|
||||
QStringList dockWidgetsToClose() const;
|
||||
|
||||
int serializationVersion = KDDOCKWIDGETS_SERIALIZATION_VERSION;
|
||||
LayoutSaver::MainWindow::List mainWindows;
|
||||
|
||||
@@ -18,26 +18,45 @@
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Config.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "Logging_p.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QPainter>
|
||||
#include <QScreen>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWindow>
|
||||
|
||||
// clazy:excludeall=ctor-missing-parent-argument,missing-qobject-macro
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
class MyCentralWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit MyCentralWidget(QWidget *parent = nullptr)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setObjectName(QStringLiteral("MyCentralWidget"));
|
||||
}
|
||||
|
||||
~MyCentralWidget() override;
|
||||
};
|
||||
}
|
||||
|
||||
class MainWindow::Private
|
||||
{
|
||||
public:
|
||||
|
||||
explicit Private(MainWindowOptions, MainWindowBase *mainWindow)
|
||||
: m_supportsAutoHide(Config::self().flags() & Config::Flag_AutoHideSupport)
|
||||
explicit Private(MainWindowOptions, MainWindow *mainWindow)
|
||||
: q(mainWindow)
|
||||
, m_supportsAutoHide(Config::self().flags() & Config::Flag_AutoHideSupport)
|
||||
, m_centralWidget(new MyCentralWidget(mainWindow))
|
||||
, m_layout(new QHBoxLayout(m_centralWidget)) // 1 level of indirection so we can add some margins
|
||||
{
|
||||
if (m_supportsAutoHide) {
|
||||
for (auto location : { SideBarLocation::North, SideBarLocation::East,
|
||||
@@ -45,33 +64,23 @@ public:
|
||||
m_sideBars.insert(location, Config::self().frameworkWidgetFactory()->createSideBar(location, mainWindow) );
|
||||
}
|
||||
}
|
||||
|
||||
m_layout->setSpacing(0);
|
||||
updateMargins();
|
||||
}
|
||||
|
||||
void updateMargins()
|
||||
{
|
||||
m_layout->setContentsMargins(q->centerWidgetMargins());
|
||||
}
|
||||
|
||||
MainWindow *const q;
|
||||
const bool m_supportsAutoHide;
|
||||
QHash<SideBarLocation, SideBar*> m_sideBars;
|
||||
MyCentralWidget *const m_centralWidget;
|
||||
QHBoxLayout *const m_layout;
|
||||
};
|
||||
|
||||
namespace KDDockWidgets {
|
||||
class MyCentralWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit MyCentralWidget(QWidget *parent = nullptr) : QWidget(parent)
|
||||
{
|
||||
setObjectName(QStringLiteral("MyCentralWidget"));
|
||||
}
|
||||
|
||||
~MyCentralWidget() override;
|
||||
|
||||
void paintEvent(QPaintEvent *) override
|
||||
{
|
||||
QPainter p(this);
|
||||
QPen pen(QColor(184, 184, 184, 184));
|
||||
p.setPen(pen);
|
||||
p.drawLine(0, 0, width(), 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
MyCentralWidget::~MyCentralWidget() {}
|
||||
|
||||
|
||||
@@ -80,26 +89,28 @@ MainWindow::MainWindow(const QString &name, MainWindowOptions options,
|
||||
: MainWindowBase(name, options, parent, flags)
|
||||
, d(new Private(options, this))
|
||||
{
|
||||
auto centralWidget = new MyCentralWidget(this);
|
||||
auto layout = new QHBoxLayout(centralWidget); // 1 level of indirection so we can add some margins
|
||||
layout->setSpacing(0);
|
||||
layout->setContentsMargins(centerWidgetMargins());
|
||||
|
||||
if (d->m_supportsAutoHide) {
|
||||
layout->addWidget(sideBar(SideBarLocation::West));
|
||||
d->m_layout->addWidget(sideBar(SideBarLocation::West));
|
||||
auto innerVLayout = new QVBoxLayout();
|
||||
innerVLayout->setSpacing(0);
|
||||
innerVLayout->setContentsMargins(0, 0, 0, 0);
|
||||
innerVLayout->addWidget(sideBar(SideBarLocation::North));
|
||||
innerVLayout->addWidget(dropArea());
|
||||
innerVLayout->addWidget(layoutWidget());
|
||||
innerVLayout->addWidget(sideBar(SideBarLocation::South));
|
||||
layout->addLayout(innerVLayout);
|
||||
layout->addWidget(sideBar(SideBarLocation::East));
|
||||
d->m_layout->addLayout(innerVLayout);
|
||||
d->m_layout->addWidget(sideBar(SideBarLocation::East));
|
||||
} else {
|
||||
layout->addWidget(dropArea());
|
||||
d->m_layout->addWidget(layoutWidget());
|
||||
}
|
||||
|
||||
setCentralWidget(centralWidget);
|
||||
setCentralWidget(d->m_centralWidget);
|
||||
|
||||
create();
|
||||
connect(windowHandle(), &QWindow::screenChanged, DockRegistry::self(),
|
||||
[this] {
|
||||
d->updateMargins(); // logical dpi might have changed
|
||||
Q_EMIT DockRegistry::self()->windowChangedScreen(windowHandle());
|
||||
});
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
@@ -125,7 +136,8 @@ void MainWindow::resizeEvent(QResizeEvent *ev)
|
||||
|
||||
QMargins MainWindow::centerWidgetMargins() const
|
||||
{
|
||||
return { 1, 5, 1, 1};
|
||||
const QMargins margins = { 1, 5, 1, 1 };
|
||||
return margins * logicalDpiFactor(this);
|
||||
}
|
||||
|
||||
QRect MainWindow::centralAreaGeometry() const
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "MainWindowBase.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Utils_p.h"
|
||||
@@ -27,16 +28,26 @@
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
static LayoutWidget* createLayoutWidget(MainWindowBase *mainWindow, MainWindowOptions options)
|
||||
{
|
||||
if (options & MainWindowOption_MDI)
|
||||
return new MDILayoutWidget(mainWindow);
|
||||
|
||||
return new DropAreaWithCentralFrame(mainWindow, options);
|
||||
}
|
||||
|
||||
class MainWindowBase::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(MainWindowBase *mainWindow, MainWindowOptions options)
|
||||
: m_options(options)
|
||||
, q(mainWindow)
|
||||
, m_dropArea(new DropAreaWithCentralFrame(mainWindow, options))
|
||||
, m_layoutWidget(createLayoutWidget(mainWindow, options))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -45,11 +56,11 @@ public:
|
||||
return m_options & MainWindowOption_HasCentralFrame;
|
||||
}
|
||||
|
||||
WidgetResizeHandler::CursorPositions allowedResizeSides(SideBarLocation loc) const;
|
||||
CursorPositions allowedResizeSides(SideBarLocation loc) const;
|
||||
|
||||
QRect rectForOverlay(Frame *, SideBarLocation) const;
|
||||
SideBarLocation preferredSideBar(DockWidgetBase *) const;
|
||||
void updateOverlayGeometry(bool reusePreviousSize = false);
|
||||
void updateOverlayGeometry(QSize suggestedSize);
|
||||
void clearSideBars();
|
||||
|
||||
QString name;
|
||||
@@ -57,7 +68,7 @@ public:
|
||||
const MainWindowOptions m_options;
|
||||
MainWindowBase *const q;
|
||||
QPointer<DockWidgetBase> m_overlayedDockWidget;
|
||||
DropAreaWithCentralFrame *const m_dropArea;
|
||||
LayoutWidget *const m_layoutWidget;
|
||||
};
|
||||
|
||||
MainWindowBase::MainWindowBase(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
@@ -90,6 +101,11 @@ void MainWindowBase::addDockWidgetAsTab(DockWidgetBase *widget)
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMDI()) {
|
||||
// Not applicable to MDI
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->supportsCentralFrame()) {
|
||||
dropArea()->m_centralFrame->addWidget(widget);
|
||||
} else {
|
||||
@@ -105,6 +121,11 @@ void MainWindowBase::addDockWidget(DockWidgetBase *dw, Location location,
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMDI()) {
|
||||
// Not applicable to MDI
|
||||
return;
|
||||
}
|
||||
|
||||
dropArea()->addDockWidget(dw, location, relativeTo, option);
|
||||
}
|
||||
|
||||
@@ -120,7 +141,7 @@ MainWindowOptions MainWindowBase::options() const
|
||||
|
||||
DropAreaWithCentralFrame *MainWindowBase::dropArea() const
|
||||
{
|
||||
return d->m_dropArea;
|
||||
return qobject_cast<DropAreaWithCentralFrame *>(d->m_layoutWidget);
|
||||
}
|
||||
|
||||
MultiSplitter *MainWindowBase::multiSplitter() const
|
||||
@@ -128,6 +149,16 @@ MultiSplitter *MainWindowBase::multiSplitter() const
|
||||
return dropArea();
|
||||
}
|
||||
|
||||
LayoutWidget *MainWindowBase::layoutWidget() const
|
||||
{
|
||||
return d->m_layoutWidget;
|
||||
}
|
||||
|
||||
MDILayoutWidget *MainWindowBase::mdiLayoutWidget() const
|
||||
{
|
||||
return qobject_cast<MDILayoutWidget *>(layoutWidget());
|
||||
}
|
||||
|
||||
void MainWindowBase::setAffinities(const QStringList &affinityNames)
|
||||
{
|
||||
QStringList affinities = affinityNames;
|
||||
@@ -161,25 +192,25 @@ void MainWindowBase::layoutParentContainerEqually(DockWidgetBase *dockWidget)
|
||||
dropArea()->layoutParentContainerEqually(dockWidget);
|
||||
}
|
||||
|
||||
WidgetResizeHandler::CursorPositions MainWindowBase::Private::allowedResizeSides(SideBarLocation loc) const
|
||||
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;
|
||||
return CursorPosition_Bottom;
|
||||
case SideBarLocation::East:
|
||||
return WidgetResizeHandler::CursorPosition_Left;
|
||||
return CursorPosition_Left;
|
||||
case SideBarLocation::West:
|
||||
return WidgetResizeHandler::CursorPosition_Right;
|
||||
return CursorPosition_Right;
|
||||
case SideBarLocation::South:
|
||||
return WidgetResizeHandler::CursorPosition_Top;
|
||||
return CursorPosition_Top;
|
||||
case SideBarLocation::None:
|
||||
return WidgetResizeHandler::CursorPosition_Undefined;
|
||||
return CursorPosition_Undefined;
|
||||
}
|
||||
|
||||
return WidgetResizeHandler::CursorPosition_Undefined;
|
||||
return CursorPosition_Undefined;
|
||||
}
|
||||
|
||||
QRect MainWindowBase::Private::rectForOverlay(Frame *frame, SideBarLocation location) const
|
||||
@@ -286,7 +317,7 @@ SideBarLocation MainWindowBase::Private::preferredSideBar(DockWidgetBase *dw) co
|
||||
{
|
||||
// TODO: Algorithm can still be made smarter
|
||||
|
||||
Layouting::Item *item = q->multiSplitter()->itemForFrame(dw->frame());
|
||||
Layouting::Item *item = q->layoutWidget()->itemForFrame(dw->d->frame());
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "No item for dock widget";
|
||||
return SideBarLocation::None;
|
||||
@@ -348,7 +379,7 @@ SideBarLocation MainWindowBase::Private::preferredSideBar(DockWidgetBase *dw) co
|
||||
: SideBarLocation::West;
|
||||
}
|
||||
|
||||
void MainWindowBase::Private::updateOverlayGeometry(bool reusePreviousSize)
|
||||
void MainWindowBase::Private::updateOverlayGeometry(QSize suggestedSize)
|
||||
{
|
||||
if (!m_overlayedDockWidget)
|
||||
return;
|
||||
@@ -359,46 +390,45 @@ void MainWindowBase::Private::updateOverlayGeometry(bool reusePreviousSize)
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect defaultGeometry = rectForOverlay(m_overlayedDockWidget->frame(), sb->location());
|
||||
const QRect defaultGeometry = rectForOverlay(m_overlayedDockWidget->d->frame(), sb->location());
|
||||
QRect newGeometry = defaultGeometry;
|
||||
|
||||
Frame *frame = m_overlayedDockWidget->frame();
|
||||
Frame *frame = m_overlayedDockWidget->d->frame();
|
||||
|
||||
if (reusePreviousSize) {
|
||||
// Let's try to honour the previous overlay size
|
||||
if (suggestedSize.isValid() && !suggestedSize.isEmpty()) {
|
||||
// Let's try to honour the suggested overlay size
|
||||
switch (sb->location()) {
|
||||
case SideBarLocation::North: {
|
||||
const int maxHeight = q->height() - frame->pos().y() - 10; // gap
|
||||
newGeometry.setHeight(qMin(frame->height(), maxHeight));
|
||||
newGeometry.setHeight(qMin(suggestedSize.height(), maxHeight));
|
||||
break;
|
||||
}
|
||||
case SideBarLocation::South: {
|
||||
const int maxHeight = sb->pos().y() - m_dropArea->pos().y() - 10; // gap
|
||||
const int maxHeight = sb->pos().y() - m_layoutWidget->pos().y() - 10; // gap
|
||||
const int bottom = newGeometry.bottom();
|
||||
newGeometry.setHeight(qMin(frame->height(), maxHeight));
|
||||
newGeometry.setHeight(qMin(suggestedSize.height(), maxHeight));
|
||||
newGeometry.moveBottom(bottom);
|
||||
break;
|
||||
}
|
||||
case SideBarLocation::East: {
|
||||
const int maxWidth = sb->pos().x() - m_dropArea->pos().x() - 10; // gap
|
||||
const int maxWidth = sb->pos().x() - m_layoutWidget->pos().x() - 10; // gap
|
||||
const int right = newGeometry.right();
|
||||
newGeometry.setWidth(qMin(frame->width(), maxWidth));
|
||||
newGeometry.setWidth(qMin(suggestedSize.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));
|
||||
newGeometry.setWidth(qMin(suggestedSize.width(), maxWidth));
|
||||
break;
|
||||
}
|
||||
case SideBarLocation::None:
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected sidebar value";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_overlayedDockWidget->frame()->QWidgetAdapter::setGeometry(newGeometry);
|
||||
m_overlayedDockWidget->d->frame()->QWidgetAdapter::setGeometry(newGeometry);
|
||||
}
|
||||
|
||||
void MainWindowBase::Private::clearSideBars()
|
||||
@@ -418,6 +448,7 @@ void MainWindowBase::moveToSideBar(DockWidgetBase *dw)
|
||||
void MainWindowBase::moveToSideBar(DockWidgetBase *dw, SideBarLocation location)
|
||||
{
|
||||
if (SideBar *sb = sideBar(location)) {
|
||||
QScopedValueRollback<bool> rollback(dw->d->m_isMovingToSideBar, true);
|
||||
dw->forceClose();
|
||||
sb->addDockWidget(dw);
|
||||
} else {
|
||||
@@ -465,12 +496,9 @@ void MainWindowBase::overlayOnSideBar(DockWidgetBase *dw)
|
||||
auto frame = Config::self().frameworkWidgetFactory()->createFrame(this, FrameOption_IsOverlayed);
|
||||
d->m_overlayedDockWidget = dw;
|
||||
frame->addWidget(dw);
|
||||
d->updateOverlayGeometry(/*reusePreviousSize=*/ false);
|
||||
|
||||
// Uncomment once I'm happy with the resizing
|
||||
auto resizeHandler = new WidgetResizeHandler(true, frame);
|
||||
resizeHandler->setAllowedResizeSides(d->allowedResizeSides(sb->location()));
|
||||
d->updateOverlayGeometry(dw->d->lastPositions().lastOverlayedGeometry(sb->location()).size());
|
||||
|
||||
frame->setAllowedResizeSides(d->allowedResizeSides(sb->location()));
|
||||
frame->QWidgetAdapter::show();
|
||||
|
||||
Q_EMIT dw->isOverlayedChanged(true);
|
||||
@@ -485,16 +513,29 @@ void MainWindowBase::toggleOverlayOnSideBar(DockWidgetBase *dw)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindowBase::clearSideBarOverlay()
|
||||
void MainWindowBase::clearSideBarOverlay(bool deleteFrame)
|
||||
{
|
||||
if (!d->m_overlayedDockWidget)
|
||||
return;
|
||||
|
||||
Frame *frame = d->m_overlayedDockWidget->frame();
|
||||
d->m_overlayedDockWidget->setParent(nullptr);
|
||||
Q_EMIT d->m_overlayedDockWidget->isOverlayedChanged(false);
|
||||
d->m_overlayedDockWidget = nullptr;
|
||||
delete frame;
|
||||
Frame *frame = d->m_overlayedDockWidget->d->frame();
|
||||
const SideBarLocation loc = d->m_overlayedDockWidget->sideBarLocation();
|
||||
d->m_overlayedDockWidget->d->lastPositions().setLastOverlayedGeometry(
|
||||
loc, frame->QWidgetAdapter::geometry());
|
||||
|
||||
frame->unoverlay();
|
||||
|
||||
if (deleteFrame) {
|
||||
d->m_overlayedDockWidget->setParent(nullptr);
|
||||
Q_EMIT d->m_overlayedDockWidget->isOverlayedChanged(false);
|
||||
d->m_overlayedDockWidget = nullptr;
|
||||
delete frame;
|
||||
} else {
|
||||
// No cleanup, just unset. When we drag the overlay it becomes a normal floating window
|
||||
// meaning we reuse Frame. Don't delete it.
|
||||
Q_EMIT d->m_overlayedDockWidget->isOverlayedChanged(false);
|
||||
d->m_overlayedDockWidget = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SideBar *MainWindowBase::sideBarForDockWidget(const DockWidgetBase *dw) const
|
||||
@@ -536,6 +577,11 @@ bool MainWindowBase::anySideBarIsVisible() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MainWindowBase::isMDI() const
|
||||
{
|
||||
return d->m_options & MainWindowOption_MDI;
|
||||
}
|
||||
|
||||
void MainWindowBase::setUniqueName(const QString &uniqueName)
|
||||
{
|
||||
if (uniqueName.isEmpty())
|
||||
@@ -553,7 +599,7 @@ void MainWindowBase::setUniqueName(const QString &uniqueName)
|
||||
void MainWindowBase::onResized(QResizeEvent *)
|
||||
{
|
||||
if (d->m_overlayedDockWidget)
|
||||
d->updateOverlayGeometry(/*reusePreviousSize=*/ true);
|
||||
d->updateOverlayGeometry(d->m_overlayedDockWidget->d->frame()->QWidgetAdapter::size());
|
||||
}
|
||||
|
||||
bool MainWindowBase::deserialize(const LayoutSaver::MainWindow &mw)
|
||||
@@ -571,7 +617,7 @@ bool MainWindowBase::deserialize(const LayoutSaver::MainWindow &mw)
|
||||
d->affinities = mw.affinities;
|
||||
}
|
||||
|
||||
const bool success = dropArea()->deserialize(mw.multiSplitterLayout);
|
||||
const bool success = layoutWidget()->deserialize(mw.multiSplitterLayout);
|
||||
|
||||
// Restore the SideBars
|
||||
d->clearSideBars();
|
||||
@@ -594,6 +640,12 @@ bool MainWindowBase::deserialize(const LayoutSaver::MainWindow &mw)
|
||||
}
|
||||
}
|
||||
|
||||
if (mw.windowState != Qt::WindowNoState) {
|
||||
if (auto w = windowHandle()) {
|
||||
w->setWindowState(mw.windowState);
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
@@ -611,8 +663,10 @@ LayoutSaver::MainWindow MainWindowBase::serialize() const
|
||||
m.uniqueName = uniqueName();
|
||||
m.screenIndex = screenNumberForWidget(this);
|
||||
m.screenSize = screenSizeForWidget(this);
|
||||
m.multiSplitterLayout = dropArea()->serialize();
|
||||
m.multiSplitterLayout = layoutWidget()->serialize();
|
||||
m.affinities = d->affinities;
|
||||
m.windowState = windowHandle() ? windowHandle()->windowState()
|
||||
: Qt::WindowNoState;
|
||||
|
||||
for (SideBarLocation loc : { SideBarLocation::North, SideBarLocation::East, SideBarLocation::West, SideBarLocation::South }) {
|
||||
if (SideBar *sb = sideBar(loc)) {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "docks_export.h"
|
||||
#include "KDDockWidgets.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "LayoutSaver.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QMargins>
|
||||
@@ -35,7 +35,9 @@ namespace KDDockWidgets {
|
||||
class DockWidgetBase;
|
||||
class Frame;
|
||||
class DropArea;
|
||||
class MDILayoutWidget;
|
||||
class MultiSplitter;
|
||||
class LayoutWidget;
|
||||
class DropAreaWithCentralFrame;
|
||||
class SideBar;
|
||||
|
||||
@@ -100,7 +102,15 @@ public:
|
||||
|
||||
///@internal
|
||||
///@brief returns the MultiSplitter.
|
||||
MultiSplitter* multiSplitter() const;
|
||||
MultiSplitter *multiSplitter() const;
|
||||
|
||||
///@internal
|
||||
///@brief returns the MultiSplitter.
|
||||
LayoutWidget *layoutWidget() const;
|
||||
|
||||
///@internal
|
||||
///@brief Returns the MDI layout. Or nullptr if this isn't a MDI main window
|
||||
MDILayoutWidget *mdiLayoutWidget() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the affinities names. Dock widgets can only dock into main windows of the same affinity.
|
||||
@@ -159,7 +169,7 @@ public:
|
||||
void toggleOverlayOnSideBar(DockWidgetBase *);
|
||||
|
||||
/// @brief closes any overlayed dock widget. The sidebar still displays them as button.
|
||||
void clearSideBarOverlay();
|
||||
void clearSideBarOverlay(bool deleteFrame = true);
|
||||
|
||||
/// @brief Returns the sidebar this dockwidget is in. nullptr if not in any.
|
||||
SideBar *sideBarForDockWidget(const DockWidgetBase *) const;
|
||||
@@ -174,6 +184,10 @@ public:
|
||||
/// @brief Returns whether any side bar is visible
|
||||
bool anySideBarIsVisible() const;
|
||||
|
||||
/// @brief Returns whether this main window is using an MDI layout.
|
||||
/// In other words, returns true if MainWindowOption_MDI was passed in the ctor.
|
||||
bool isMDI() const;
|
||||
|
||||
protected:
|
||||
void setUniqueName(const QString &uniqueName);
|
||||
void onResized(QResizeEvent *); // Because QtQuick doesn't have resizeEvent()
|
||||
|
||||
35
src/MainWindowMDI.cpp
Normal file
35
src/MainWindowMDI.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "MainWindowMDI.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
MainWindowMDI::MainWindowMDI(const QString &uniqueName, QWidgetOrQuick *parent, Qt::WindowFlags flags)
|
||||
: MDIMainWindowBase(uniqueName, MainWindowOption_MDI, parent, flags)
|
||||
{
|
||||
}
|
||||
|
||||
MainWindowMDI::~MainWindowMDI()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindowMDI::addDockWidget(DockWidgetBase *dockWidget, QPoint localPos, InitialOption addingOption)
|
||||
{
|
||||
auto layout = static_cast<MDILayoutWidget *>(this->layoutWidget());
|
||||
layout->addDockWidget(dockWidget, localPos, addingOption);
|
||||
}
|
||||
|
||||
void MainWindowMDI::addDockWidget(DockWidgetBase *dockWidget, QPointF localPos, InitialOption addingOption)
|
||||
{
|
||||
MainWindowMDI::addDockWidget(dockWidget, localPos.toPoint(), addingOption);
|
||||
}
|
||||
53
src/MainWindowMDI.h
Normal file
53
src/MainWindowMDI.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief MainWindow sub-class which uses MDI as a layout
|
||||
*
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
|
||||
#ifndef KD_MAINWINDOW_MDI_H
|
||||
#define KD_MAINWINDOW_MDI_H
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
# include "MainWindow.h"
|
||||
#else
|
||||
# include "private/quick/MainWindowQuick_p.h"
|
||||
#endif
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
/// @brief MainWindow sub-class which uses MDI as a layout
|
||||
class DOCKS_EXPORT MainWindowMDI : public KDDockWidgets::MDIMainWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
///@brief Constructor. See base class documentation
|
||||
explicit MainWindowMDI(const QString &uniqueName, QWidgetOrQuick *parent = nullptr,
|
||||
Qt::WindowFlags flags = Qt::WindowFlags());
|
||||
|
||||
///@brief Destructor
|
||||
~MainWindowMDI() override;
|
||||
|
||||
///@brief Docks @p dockWidget
|
||||
/// The widget will be placed at the specified position
|
||||
void addDockWidget(DockWidgetBase *dockWidget, QPoint localPos, InitialOption addingOption = {});
|
||||
|
||||
///@brief Convenience overload
|
||||
void addDockWidget(DockWidgetBase *dockWidget, QPointF localPos, InitialOption addingOption = {});
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -51,6 +51,7 @@ inline bool isMinimized(QWindow *window)
|
||||
typedef QMainWindow QMainWindowOrQuick;
|
||||
typedef Layouting::Widget_qwidget LayoutGuestWidgetBase;
|
||||
typedef KDDockWidgets::MainWindow MainWindowType;
|
||||
typedef KDDockWidgets::MainWindow MDIMainWindowBase;
|
||||
typedef KDDockWidgets::DockWidget DockWidgetType;
|
||||
typedef QWidget WidgetType;
|
||||
}
|
||||
@@ -64,12 +65,17 @@ inline bool isMinimized(QWindow *window)
|
||||
typedef QWidgetOrQuick QMainWindowOrQuick;
|
||||
typedef Layouting::Widget_quick LayoutGuestWidgetBase;
|
||||
typedef KDDockWidgets::MainWindowQuick MainWindowType;
|
||||
typedef KDDockWidgets::MainWindowQuick MDIMainWindowBase;
|
||||
typedef KDDockWidgets::DockWidgetQuick DockWidgetType;
|
||||
typedef QQuickItem WidgetType;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace KDDockWidgets {
|
||||
/// @brief LayoutGuestWidget is is the type that Item will host.
|
||||
///
|
||||
/// The layouting deals in items, represented by Item. Each item wraps a QWidget (or QQuickItem),
|
||||
/// such widgets derive from LayoutGuestWidget.
|
||||
class LayoutGuestWidget : public KDDockWidgets::QWidgetAdapter
|
||||
, public LayoutGuestWidgetBase
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../../../LayoutSaver_p.h"
|
||||
#include "../../MainWindowMDI.h"
|
||||
12
src/fwd_headers/kddockwidgets/private/DragController_p.h
Normal file
12
src/fwd_headers/kddockwidgets/private/DragController_p.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../../../private/DragController_p.h"
|
||||
12
src/fwd_headers/kddockwidgets/private/Frame_p.h
Normal file
12
src/fwd_headers/kddockwidgets/private/Frame_p.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../../../private/Frame_p.h"
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sergio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../../../private/WidgetResizeHandler_p.h"
|
||||
@@ -4,6 +4,8 @@
|
||||
<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/MainWindowMDI.qml</file>
|
||||
<file>private/quick/qml/ResizeHandlerHelper.qml</file>
|
||||
<file>private/quick/qml/RubberBand.qml</file>
|
||||
<file>private/quick/qml/TitleBarBase.qml</file>
|
||||
<file>private/quick/qml/TitleBar.qml</file>
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
*/
|
||||
|
||||
#include "DebugWindow_p.h"
|
||||
#include "ObjectViewer_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "MainWindow.h"
|
||||
#include "LayoutSaver.h"
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "MainWindow.h"
|
||||
#include "ObjectViewer_p.h"
|
||||
#include "Qt5Qt6Compat_p.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
@@ -197,12 +197,12 @@ DebugWindow::DebugWindow(QWidget *parent)
|
||||
connect(button, &QPushButton::clicked, this, [] {
|
||||
const auto mainWindows = DockRegistry::self()->mainwindows();
|
||||
for (MainWindowBase *mainWindow : mainWindows) {
|
||||
mainWindow->multiSplitter()->checkSanity();
|
||||
mainWindow->layoutWidget()->checkSanity();
|
||||
}
|
||||
|
||||
const auto floatingWindows = DockRegistry::self()->floatingWindows();
|
||||
for (FloatingWindow *floatingWindow : floatingWindows) {
|
||||
floatingWindow->multiSplitter()->checkSanity();
|
||||
floatingWindow->layoutWidget()->checkSanity();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -314,12 +314,12 @@ void DebugWindow::dumpDockWidgetInfo()
|
||||
|
||||
for (FloatingWindow *fw : floatingWindows) {
|
||||
qDebug() << fw << "; affinities=" << fw->affinities();
|
||||
fw->dropArea()->dumpLayout();
|
||||
fw->layoutWidget()->dumpLayout();
|
||||
}
|
||||
|
||||
for (MainWindowBase *mw : mainWindows) {
|
||||
qDebug() << mw << "; affinities=" << mw->affinities();
|
||||
mw->multiSplitter()->dumpLayout();
|
||||
mw->layoutWidget()->dumpLayout();
|
||||
}
|
||||
|
||||
for (DockWidgetBase *dw : dockWidgets) {
|
||||
|
||||
@@ -9,17 +9,20 @@
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "Config.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "Config.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "MainWindowMDI.h"
|
||||
#include "Position_p.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QDebug>
|
||||
@@ -47,9 +50,10 @@ static void initKDDockWidgetResources()
|
||||
DockRegistry::DockRegistry(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
qApp->installEventFilter(this);
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
|
||||
# ifdef DOCKS_DEVELOPER_MODE
|
||||
if (qEnvironmentVariableIntValue("KDDOCKWIDGETS_SHOW_DEBUG_WINDOW") == 1) {
|
||||
auto dv = new Debug::DebugWindow();
|
||||
@@ -222,6 +226,25 @@ SideBar *DockRegistry::sideBarForDockWidget(const DockWidgetBase *dw) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Frame *DockRegistry::frameInMDIResize() const
|
||||
{
|
||||
for (auto mw : m_mainWindows) {
|
||||
if (!mw->isMDI())
|
||||
continue;
|
||||
|
||||
LayoutWidget *layout = mw->layoutWidget();
|
||||
const QList<Frame *> frames = layout->frames();
|
||||
for (Frame *frame : frames) {
|
||||
if (WidgetResizeHandler *wrh = frame->resizeHandler()) {
|
||||
if (wrh->isResizing())
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MainWindowBase::List DockRegistry::mainWindowsWithAffinity(const QStringList &affinities) const
|
||||
{
|
||||
MainWindowBase::List result;
|
||||
@@ -236,12 +259,12 @@ MainWindowBase::List DockRegistry::mainWindowsWithAffinity(const QStringList &af
|
||||
return result;
|
||||
}
|
||||
|
||||
MultiSplitter *DockRegistry::layoutForItem(const Layouting::Item *item) const
|
||||
LayoutWidget *DockRegistry::layoutForItem(const Layouting::Item *item) const
|
||||
{
|
||||
if (!item->hostWidget())
|
||||
return nullptr;
|
||||
|
||||
if (auto ms = qobject_cast<MultiSplitter*>(item->hostWidget()->asQObject()))
|
||||
if (auto ms = qobject_cast<LayoutWidget *>(item->hostWidget()->asQObject()))
|
||||
return ms;
|
||||
|
||||
return nullptr;
|
||||
@@ -314,12 +337,12 @@ void DockRegistry::unregisterFloatingWindow(FloatingWindow *window)
|
||||
maybeDelete();
|
||||
}
|
||||
|
||||
void DockRegistry::registerLayout(MultiSplitter *layout)
|
||||
void DockRegistry::registerLayout(LayoutWidget *layout)
|
||||
{
|
||||
m_layouts << layout;
|
||||
}
|
||||
|
||||
void DockRegistry::unregisterLayout(MultiSplitter *layout)
|
||||
void DockRegistry::unregisterLayout(LayoutWidget *layout)
|
||||
{
|
||||
m_layouts.removeOne(layout);
|
||||
}
|
||||
@@ -359,6 +382,11 @@ MainWindowBase *DockRegistry::mainWindowByName(const QString &name) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MainWindowMDI *DockRegistry::mdiMainWindowByName(const QString &name) const
|
||||
{
|
||||
return qobject_cast<MainWindowMDI *>(mainWindowByName(name));
|
||||
}
|
||||
|
||||
DockWidgetBase *DockRegistry::dockWidgetForGuest(QWidgetOrQuick *guest) const
|
||||
{
|
||||
if (!guest)
|
||||
@@ -457,7 +485,7 @@ const MainWindowBase::List DockRegistry::mainwindows() const
|
||||
return m_mainWindows;
|
||||
}
|
||||
|
||||
const QVector<MultiSplitter *> DockRegistry::layouts() const
|
||||
const QVector<LayoutWidget *> DockRegistry::layouts() const
|
||||
{
|
||||
return m_layouts;
|
||||
}
|
||||
@@ -505,6 +533,18 @@ bool DockRegistry::hasFloatingWindows() const
|
||||
});
|
||||
}
|
||||
|
||||
QWindow *DockRegistry::windowForHandle(WId id) const
|
||||
{
|
||||
const QWindowList windows = qApp->topLevelWindows();
|
||||
for (QWindow *w : windows) {
|
||||
if (w->isVisible() && w->handle()) {
|
||||
if (w->winId() == id)
|
||||
return w;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FloatingWindow *DockRegistry::floatingWindowForHandle(QWindow *windowHandle) const
|
||||
{
|
||||
for (FloatingWindow *fw : m_floatingWindows) {
|
||||
@@ -591,7 +631,7 @@ void DockRegistry::clear(const DockWidgetBase::List &dockWidgets,
|
||||
for (auto dw : qAsConst(dockWidgets)) {
|
||||
if (affinities.isEmpty() || affinitiesMatch(affinities, dw->affinities())) {
|
||||
dw->forceClose();
|
||||
dw->lastPositions().removePlaceholders();
|
||||
dw->d->lastPositions().removePlaceholders();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,7 +646,7 @@ void DockRegistry::ensureAllFloatingWidgetsAreMorphed()
|
||||
{
|
||||
for (DockWidgetBase *dw : qAsConst(m_dockWidgets)) {
|
||||
if (dw->window() == dw && dw->isVisible())
|
||||
dw->morphIntoFloatingWindow();
|
||||
dw->d->morphIntoFloatingWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +666,13 @@ bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
// When clicking on a MDI Frame we raise the window
|
||||
if (Frame *f = parentFrame(watched)) {
|
||||
if (f->isMDI())
|
||||
f->raise();
|
||||
}
|
||||
|
||||
// The following code is for hididng the overlay
|
||||
if (!(Config::self().flags() & Config::Flag_AutoHideSupport))
|
||||
return false;
|
||||
|
||||
@@ -637,7 +684,16 @@ bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
|
||||
auto p = watched;
|
||||
while (p) {
|
||||
if (auto dw = qobject_cast<DockWidgetBase*>(p))
|
||||
return onDockWidgetPressed(dw, static_cast<QMouseEvent*>(event));
|
||||
return onDockWidgetPressed(dw, static_cast<QMouseEvent *>(event));
|
||||
|
||||
if (auto layoutWidget = qobject_cast<LayoutWidget *>(p)) {
|
||||
if (auto mw = layoutWidget->mainWindow()) {
|
||||
// The user clicked somewhere in the main window's drop area, but outside of the
|
||||
// overlayed dock widget
|
||||
mw->clearSideBarOverlay();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
p = p->parent();
|
||||
}
|
||||
@@ -651,13 +707,19 @@ 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.
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
// Don't be sending mouse events around if a popup is open, they are sensitive
|
||||
if (qApp->activePopupWidget())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
MainWindowBase *mainWindow = dw->mainWindow();
|
||||
if (!mainWindow) // Only docked widgets are interesting
|
||||
return false;
|
||||
|
||||
if (DockWidgetBase *overlayedDockWidget = mainWindow->overlayedDockWidget()) {
|
||||
ev->ignore();
|
||||
qApp->sendEvent(overlayedDockWidget->frame(), ev);
|
||||
qApp->sendEvent(overlayedDockWidget->d->frame(), ev);
|
||||
|
||||
if (ev->isAccepted()) {
|
||||
// The Frame accepted it. It means the user is resizing it. We allow for 4px outside for better resize.
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
#ifndef KD_DOCKREGISTRY_P_H
|
||||
#define KD_DOCKREGISTRY_P_H
|
||||
|
||||
#include "../DockWidgetBase.h"
|
||||
#include "../MainWindowBase.h"
|
||||
#include "kddockwidgets/DockWidgetBase.h"
|
||||
#include "kddockwidgets/MainWindowBase.h"
|
||||
|
||||
#include "kddockwidgets/private/Frame_p.h"
|
||||
|
||||
#include <QVector>
|
||||
#include <QObject>
|
||||
@@ -29,12 +31,16 @@ namespace KDDockWidgets
|
||||
|
||||
class FloatingWindow;
|
||||
class Frame;
|
||||
class LayoutWidget;
|
||||
class MainWindowMDI;
|
||||
class SideBar;
|
||||
struct WindowBeingDragged;
|
||||
|
||||
class DOCKS_EXPORT DockRegistry : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(
|
||||
KDDockWidgets::Frame *frameInMDIResize READ frameInMDIResize NOTIFY frameInMDIResizeChanged)
|
||||
public:
|
||||
static DockRegistry *self();
|
||||
~DockRegistry();
|
||||
@@ -47,8 +53,8 @@ public:
|
||||
void registerFloatingWindow(FloatingWindow *);
|
||||
void unregisterFloatingWindow(FloatingWindow *);
|
||||
|
||||
void registerLayout(MultiSplitter *);
|
||||
void unregisterLayout(MultiSplitter *);
|
||||
void registerLayout(LayoutWidget *);
|
||||
void unregisterLayout(LayoutWidget *);
|
||||
|
||||
void registerFrame(Frame *);
|
||||
void unregisterFrame(Frame *);
|
||||
@@ -56,8 +62,9 @@ public:
|
||||
DockWidgetBase *focusedDockWidget() const;
|
||||
|
||||
bool containsDockWidget(const QString &uniqueName) const;
|
||||
DockWidgetBase *dockByName(const QString &) const;
|
||||
Q_INVOKABLE KDDockWidgets::DockWidgetBase *dockByName(const QString &) const;
|
||||
MainWindowBase *mainWindowByName(const QString &) const;
|
||||
MainWindowMDI *mdiMainWindowByName(const QString &) const;
|
||||
|
||||
/// @brief returns the dock widget that hosts @p guest widget. Nullptr if there's none.
|
||||
DockWidgetBase *dockWidgetForGuest(QWidgetOrQuick *guest) const;
|
||||
@@ -79,8 +86,8 @@ public:
|
||||
///@brief overload returning only the ones with the specified names
|
||||
const MainWindowBase::List mainWindows(const QStringList &names);
|
||||
|
||||
///@brief returns the list of MultiSplitter instances
|
||||
const QVector<MultiSplitter*> layouts() const;
|
||||
///@brief returns the list of LayoutWidget instances
|
||||
const QVector<LayoutWidget *> layouts() const;
|
||||
|
||||
///@brief returns a list of all Frame instances
|
||||
const QList<Frame*> frames() const;
|
||||
@@ -95,6 +102,9 @@ public:
|
||||
///@brief returns whether if there's at least one floating window
|
||||
bool hasFloatingWindows() const;
|
||||
|
||||
///@brief Returns the window with the specified id
|
||||
QWindow *windowForHandle(WId id) const;
|
||||
|
||||
///@brief returns the FloatingWindow with handle @p windowHandle
|
||||
FloatingWindow *floatingWindowForHandle(QWindow *windowHandle) const;
|
||||
|
||||
@@ -150,12 +160,12 @@ public:
|
||||
bool isEmpty(bool excludeBeingDeleted = false) const;
|
||||
|
||||
/**
|
||||
* @brief Calls MultiSplitter::checkSanity() on all layouts.
|
||||
* @brief Calls LayoutWidget::checkSanity() on all layouts.
|
||||
*
|
||||
* @param dumpDebug If true then each layout is dumped too
|
||||
*
|
||||
* This is called by the unit-tests or the fuzzer. If during this the framework spits a qWarning()
|
||||
* then the app will qFatal()
|
||||
* This is called by the unit-tests or the fuzzer. If during this the framework spits a
|
||||
* qWarning() then the app will qFatal()
|
||||
*/
|
||||
void checkSanityAll(bool dumpDebug = false);
|
||||
|
||||
@@ -172,7 +182,7 @@ public:
|
||||
MainWindowBase::List mainWindowsWithAffinity(const QStringList &affinities) const;
|
||||
|
||||
// TODO: docs
|
||||
MultiSplitter* layoutForItem(const Layouting::Item *) const;
|
||||
LayoutWidget *layoutForItem(const Layouting::Item *) const;
|
||||
|
||||
// TODO: docs
|
||||
bool itemIsInMainWindow(const Layouting::Item *) const;
|
||||
@@ -202,7 +212,17 @@ public:
|
||||
SideBarLocation sideBarLocationForDockWidget(const DockWidgetBase *) const;
|
||||
|
||||
///@brief Overload that returns the SideBar itself
|
||||
SideBar* sideBarForDockWidget(const DockWidgetBase *) const;
|
||||
SideBar *sideBarForDockWidget(const DockWidgetBase *) const;
|
||||
|
||||
///@brief Returns the Frame which is being resized in a MDI layout. nullptr if none
|
||||
Frame *frameInMDIResize() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/// @brief emitted when a main window or a floating window change screen
|
||||
void windowChangedScreen(QWindow *);
|
||||
|
||||
/// @brief emitted when the MDI frame that's being resized changed
|
||||
void frameInMDIResizeChanged();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
@@ -219,7 +239,7 @@ private:
|
||||
MainWindowBase::List m_mainWindows;
|
||||
QList<Frame*> m_frames;
|
||||
QVector<FloatingWindow*> m_floatingWindows;
|
||||
QVector<MultiSplitter*> m_layouts;
|
||||
QVector<LayoutWidget *> m_layouts;
|
||||
QPointer<DockWidgetBase> m_focusedDockWidget;
|
||||
};
|
||||
|
||||
|
||||
242
src/private/DockWidgetBase_p.h
Normal file
242
src/private/DockWidgetBase_p.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#ifndef KD_DOCKWIDGET_BASE_P_H
|
||||
#define KD_DOCKWIDGET_BASE_P_H
|
||||
|
||||
#include "DockWidgetBase.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
#include <QSize>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class DOCKS_EXPORT_FOR_UNIT_TESTS DockWidgetBase::Private : public QObject /// clazy:exclude=missing-qobject-macro
|
||||
{
|
||||
public:
|
||||
Private(const QString &dockName, DockWidgetBase::Options options_,
|
||||
LayoutSaverOptions layoutSaverOptions_, DockWidgetBase *qq);
|
||||
|
||||
void init()
|
||||
{
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns the FloatingWindow this dock widget is in. If nullptr then it's in a
|
||||
* MainWindow.
|
||||
*
|
||||
* Note: Being in a FloatingWindow doesn't necessarily mean @ref isFloating() returns true, as
|
||||
* the dock widget might be in a floating window with other dock widgets side by side.
|
||||
*/
|
||||
FloatingWindow *floatingWindow() const
|
||||
{
|
||||
return qobject_cast<FloatingWindow*>(q->window());
|
||||
}
|
||||
|
||||
MainWindowBase *mainWindow() const
|
||||
{
|
||||
if (q->isWindow())
|
||||
return nullptr;
|
||||
|
||||
// Note: Don't simply use window(), as the MainWindow might be embedded into something else
|
||||
QWidgetOrQuick *p = q->parentWidget();
|
||||
while (p) {
|
||||
if (auto window = qobject_cast<MainWindowBase*>(p))
|
||||
return window;
|
||||
|
||||
if (p->isWindow())
|
||||
return nullptr;
|
||||
|
||||
p = p->parentWidget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SideBar* sideBar() const
|
||||
{
|
||||
return DockRegistry::self()->sideBarForDockWidget(q);
|
||||
}
|
||||
|
||||
///@brief adds the current layout item containing this dock widget
|
||||
void addPlaceholderItem(Layouting::Item *);
|
||||
|
||||
///@brief returns the last position, just for tests.
|
||||
LastPositions &lastPositions();
|
||||
|
||||
void forceClose();
|
||||
QPoint defaultCenterPosForFloating();
|
||||
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
void updateTitle();
|
||||
void toggle(bool enabled);
|
||||
void updateToggleAction();
|
||||
void updateFloatAction();
|
||||
void onDockWidgetShown();
|
||||
void onDockWidgetHidden();
|
||||
void show();
|
||||
void close();
|
||||
bool restoreToPreviousPosition();
|
||||
void maybeRestoreToPreviousPosition();
|
||||
int currentTabIndex() const;
|
||||
|
||||
/**
|
||||
* @brief Serializes this dock widget into an intermediate form
|
||||
*/
|
||||
std::shared_ptr<LayoutSaver::DockWidget> serialize() const;
|
||||
|
||||
/**
|
||||
* @brief the Frame which contains this dock widgets.
|
||||
*
|
||||
* A frame wraps a docked DockWidget, giving it a TabWidget so it can accept other dock widgets.
|
||||
* Frame is also the actual class that goes into a LayoutWidget.
|
||||
*
|
||||
* It's nullptr immediately after creation.
|
||||
*/
|
||||
Frame *frame() const;
|
||||
|
||||
///@brief If this dock widget is floating, then it saves its geometry
|
||||
void saveLastFloatingGeometry();
|
||||
|
||||
/**
|
||||
* Before floating a dock widget we save its position. So it can be restored when calling
|
||||
* DockWidget::setFloating(false)
|
||||
*/
|
||||
void saveTabIndex();
|
||||
|
||||
/**
|
||||
* @brief Creates a FloatingWindow and adds itself into it
|
||||
* @return the created FloatingWindow
|
||||
*/
|
||||
KDDockWidgets::FloatingWindow *morphIntoFloatingWindow();
|
||||
|
||||
/// @brief calls morphIntoFloatingWindow() if the dock widget is visible and is a top-level
|
||||
/// This is called delayed whenever we show a floating dock widget, so we get a FloatingWindow
|
||||
void maybeMorphIntoFloatingWindow();
|
||||
|
||||
/// @brief Returns the mdi layout this dock widget is in, if any.
|
||||
MDILayoutWidget *mdiLayout() const;
|
||||
|
||||
const QString name;
|
||||
QStringList affinities;
|
||||
QString title;
|
||||
QIcon titleBarIcon;
|
||||
QIcon tabBarIcon;
|
||||
QWidgetOrQuick *widget = nullptr;
|
||||
DockWidgetBase *const q;
|
||||
DockWidgetBase::Options options;
|
||||
const LayoutSaverOptions layoutSaverOptions;
|
||||
QAction *const toggleAction;
|
||||
QAction *const floatAction;
|
||||
LastPositions m_lastPositions;
|
||||
bool m_processingToggleAction = false;
|
||||
bool m_updatingToggleAction = false;
|
||||
bool m_updatingFloatAction = false;
|
||||
bool m_isForceClosing = false;
|
||||
bool m_isMovingToSideBar = false;
|
||||
QSize m_lastOverlayedSize = QSize(0, 0);
|
||||
int m_userType = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#endif
|
||||
@@ -10,14 +10,17 @@
|
||||
*/
|
||||
|
||||
#include "DragController_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Qt5Qt6Compat_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "Config.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QGuiApplication>
|
||||
@@ -170,6 +173,8 @@ void StateNone::onEntry()
|
||||
q->m_currentDropArea->removeHover();
|
||||
q->m_currentDropArea = nullptr;
|
||||
}
|
||||
|
||||
Q_EMIT q->isDraggingChanged();
|
||||
}
|
||||
|
||||
bool StateNone::handleMouseButtonPress(Draggable *draggable, QPoint globalPos, QPoint pos)
|
||||
@@ -213,7 +218,10 @@ bool StatePreDrag::handleMouseMove(QPoint globalPos)
|
||||
}
|
||||
|
||||
if (q->m_draggable->dragCanStart(q->m_pressPos, globalPos)) {
|
||||
Q_EMIT q->manhattanLengthMove();
|
||||
if (q->m_draggable->isMDI())
|
||||
Q_EMIT q->manhattanLengthMoveMDI();
|
||||
else
|
||||
Q_EMIT q->manhattanLengthMove();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -246,25 +254,34 @@ 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
|
||||
if (dw->isFloating())
|
||||
dw->saveLastFloatingGeometry();
|
||||
dw->d->saveLastFloatingGeometry();
|
||||
}
|
||||
|
||||
const bool needsUndocking = !q->m_draggable->isWindow();
|
||||
q->m_windowBeingDragged = q->m_draggable->makeWindow();
|
||||
if (q->m_windowBeingDragged) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
# ifdef Q_OS_WIN
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) && defined(Q_OS_WIN)
|
||||
if (!q->m_nonClientDrag && KDDockWidgets::usesNativeDraggingAndResizing()) {
|
||||
// Started as a client move, as the dock widget was docked,
|
||||
// but now that we're dragging it as a floating window, switch to native drag
|
||||
// but now that we're dragging it as a floating window, switch to native drag, so we can still get aero-snap
|
||||
FloatingWindow *fw = q->m_windowBeingDragged->floatingWindow();
|
||||
q->m_nonClientDrag = true;
|
||||
q->m_windowBeingDragged.reset();
|
||||
q->m_windowBeingDragged = fw->makeWindow();
|
||||
|
||||
QWindow *window = fw->windowHandle();
|
||||
|
||||
if (needsUndocking) {
|
||||
// Position the window before the drag start, otherwise if you move mouse too fast there will be an offset
|
||||
// Only required when we've undocked/detached a window.
|
||||
window->setPosition(QCursor::pos() - q->m_offset);
|
||||
}
|
||||
|
||||
// Start the native move
|
||||
window->startSystemMove();
|
||||
}
|
||||
# endif
|
||||
#else
|
||||
Q_UNUSED(needsUndocking);
|
||||
#endif
|
||||
|
||||
qCDebug(state) << "StateDragging entered. m_draggable=" << q->m_draggable->asWidget()
|
||||
@@ -284,6 +301,8 @@ void StateDragging::onEntry()
|
||||
qWarning() << Q_FUNC_INFO << "No window being dragged for " << q->m_draggable->asWidget();
|
||||
Q_EMIT q->dragCanceled();
|
||||
}
|
||||
|
||||
Q_EMIT q->isDraggingChanged();
|
||||
}
|
||||
|
||||
bool StateDragging::handleMouseButtonRelease(QPoint globalPos)
|
||||
@@ -369,6 +388,86 @@ bool StateDragging::handleMouseDoubleClick()
|
||||
return false;
|
||||
}
|
||||
|
||||
StateInternalMDIDragging::StateInternalMDIDragging(DragController *parent)
|
||||
: StateBase(parent)
|
||||
{
|
||||
}
|
||||
|
||||
StateInternalMDIDragging::~StateInternalMDIDragging()
|
||||
{
|
||||
}
|
||||
|
||||
void StateInternalMDIDragging::onEntry()
|
||||
{
|
||||
qCDebug(state) << "StateInternalMDIDragging entered. draggable="
|
||||
<< q->m_draggable->asWidget();
|
||||
|
||||
// Raise the dock widget being dragged
|
||||
if (auto tb = qobject_cast<TitleBar *>(q->m_draggable->asWidget())) {
|
||||
if (Frame *f = tb->frame())
|
||||
f->raise();
|
||||
}
|
||||
|
||||
Q_EMIT q->isDraggingChanged();
|
||||
}
|
||||
|
||||
bool StateInternalMDIDragging::handleMouseButtonRelease(QPoint)
|
||||
{
|
||||
Q_EMIT q->dragCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StateInternalMDIDragging::handleMouseMove(QPoint globalPos)
|
||||
{
|
||||
// for MDI we only support dragging via the title bar, other cases don't make sense conceptually
|
||||
auto tb = qobject_cast<TitleBar *>(q->m_draggable->asWidget());
|
||||
if (!tb) {
|
||||
qWarning() << Q_FUNC_INFO << "expected a title bar, not" << q->m_draggable->asWidget();
|
||||
Q_EMIT q->dragCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
Frame *frame = tb->frame();
|
||||
if (!frame) {
|
||||
// Doesn't happen.
|
||||
qWarning() << Q_FUNC_INFO << "null frame.";
|
||||
Q_EMIT q->dragCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
const QSize parentSize = frame->QWidgetAdapter::parentWidget()->size();
|
||||
const QPoint oldPos = frame->mapToGlobal(QPoint(0, 0));
|
||||
const QPoint delta = globalPos - oldPos;
|
||||
const QPoint newLocalPos = frame->pos() + delta - q->m_offset;
|
||||
|
||||
// Let's not allow the MDI window to go outside of its parent
|
||||
|
||||
QPoint newLocalPosBounded = {qMax(0, newLocalPos.x()), qMax(0, newLocalPos.y())};
|
||||
newLocalPosBounded.setX(qMin(newLocalPosBounded.x(), parentSize.width() - frame->width()));
|
||||
newLocalPosBounded.setY(qMin(newLocalPosBounded.y(), parentSize.height() - frame->height()));
|
||||
|
||||
auto layout = frame->mdiLayoutWidget();
|
||||
Q_ASSERT(layout);
|
||||
layout->moveDockWidget(frame, newLocalPosBounded);
|
||||
|
||||
// Check if we need to pop out the MDI window (make it float)
|
||||
// If we drag the window against an edge, and move behind the edge some threshold, we float it
|
||||
const int threshold = Config::self().mdiPopupThreshold();
|
||||
if (threshold != -1) {
|
||||
const QPoint overflow = newLocalPosBounded - newLocalPos;
|
||||
if (qAbs(overflow.x()) > threshold || qAbs(overflow.y()) > threshold)
|
||||
Q_EMIT q->mdiPopOut();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StateInternalMDIDragging::handleMouseDoubleClick()
|
||||
{
|
||||
Q_EMIT q->dragCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
StateDraggingWayland::StateDraggingWayland(DragController *parent)
|
||||
: StateDragging(parent)
|
||||
{
|
||||
@@ -471,13 +570,18 @@ DragController::DragController(QObject *parent)
|
||||
auto statepreDrag = new StatePreDrag(this);
|
||||
auto stateDragging = isWayland() ? new StateDraggingWayland(this)
|
||||
: new StateDragging(this);
|
||||
m_stateDraggingMDI = new StateInternalMDIDragging(this);
|
||||
|
||||
stateNone->addTransition(this, &DragController::mousePressed, statepreDrag);
|
||||
statepreDrag->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
statepreDrag->addTransition(this, &DragController::manhattanLengthMove, stateDragging);
|
||||
statepreDrag->addTransition(this, &DragController::manhattanLengthMoveMDI, m_stateDraggingMDI);
|
||||
stateDragging->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
stateDragging->addTransition(this, &DragController::dropped, stateNone);
|
||||
|
||||
m_stateDraggingMDI->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
m_stateDraggingMDI->addTransition(this, &DragController::mdiPopOut, stateDragging);
|
||||
|
||||
if (usesFallbackMouseGrabber())
|
||||
enableFallbackMouseGrabber();
|
||||
|
||||
@@ -504,7 +608,7 @@ void DragController::unregisterDraggable(Draggable *drg)
|
||||
|
||||
bool DragController::isDragging() const
|
||||
{
|
||||
return m_windowBeingDragged != nullptr;
|
||||
return m_windowBeingDragged != nullptr || activeState() == m_stateDraggingMDI;
|
||||
}
|
||||
|
||||
bool DragController::isInNonClientDrag() const
|
||||
@@ -605,7 +709,7 @@ bool DragController::eventFilter(QObject *o, QEvent *e)
|
||||
switch (e->type()) {
|
||||
case QEvent::NonClientAreaMouseButtonPress: {
|
||||
if (auto fw = qobject_cast<FloatingWindow*>(o)) {
|
||||
if (fw->isInDragArea(Qt5Qt6Compat::eventGlobalPos(me))) {
|
||||
if (KDDockWidgets::usesNativeTitleBar() || fw->isInDragArea(Qt5Qt6Compat::eventGlobalPos(me))) {
|
||||
m_nonClientDrag = true;
|
||||
return activeState()->handleMouseButtonPress(draggableForQObject(o), Qt5Qt6Compat::eventGlobalPos(me), me->pos());
|
||||
}
|
||||
@@ -627,6 +731,7 @@ bool DragController::eventFilter(QObject *o, QEvent *e)
|
||||
case QEvent::MouseMove:
|
||||
return activeState()->handleMouseMove(Qt5Qt6Compat::eventGlobalPos(me));
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::NonClientAreaMouseButtonDblClick:
|
||||
return activeState()->handleMouseDoubleClick();
|
||||
default:
|
||||
break;
|
||||
@@ -645,6 +750,10 @@ static QWidgetOrQuick *qtTopLevelForHWND(HWND hwnd)
|
||||
{
|
||||
const QList<QWindow*> windows = qApp->topLevelWindows();
|
||||
for (QWindow *window : windows) {
|
||||
if (!window->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hwnd == (HWND)window->winId()) {
|
||||
return DockRegistry::self()->topLevelForHandle(window);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#ifndef KD_DRAGCONTROLLER_P_H
|
||||
#define KD_DRAGCONTROLLER_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
|
||||
#include "TitleBar_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
@@ -25,6 +25,7 @@
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class StateBase;
|
||||
class StateInternalMDIDragging;
|
||||
class DropArea;
|
||||
class Draggable;
|
||||
class FallbackMouseGrabber;
|
||||
@@ -62,6 +63,7 @@ private:
|
||||
class DOCKS_EXPORT DragController : public MinimalStateMachine
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isDragging READ isDragging NOTIFY isDraggingChanged)
|
||||
public:
|
||||
enum State {
|
||||
State_None = 0,
|
||||
@@ -94,8 +96,11 @@ public:
|
||||
Q_SIGNALS:
|
||||
void mousePressed();
|
||||
void manhattanLengthMove();
|
||||
void manhattanLengthMoveMDI();
|
||||
void mdiPopOut();
|
||||
void dragCanceled();
|
||||
void dropped();
|
||||
void isDraggingChanged();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *, QEvent *) override;
|
||||
@@ -105,6 +110,7 @@ private:
|
||||
friend class StateNone;
|
||||
friend class StatePreDrag;
|
||||
friend class StateDragging;
|
||||
friend class StateInternalMDIDragging;
|
||||
friend class StateDropped;
|
||||
friend class StateDraggingWayland;
|
||||
|
||||
@@ -118,11 +124,12 @@ private:
|
||||
|
||||
Draggable::List m_draggables;
|
||||
Draggable *m_draggable = nullptr;
|
||||
QPointer<QWidget> m_draggableGuard; // Just so we know if the draggable was destroyed for some reason
|
||||
QPointer<WidgetType> m_draggableGuard; // Just so we know if the draggable was destroyed for some reason
|
||||
std::unique_ptr<WindowBeingDragged> m_windowBeingDragged;
|
||||
DropArea *m_currentDropArea = nullptr;
|
||||
bool m_nonClientDrag = false;
|
||||
FallbackMouseGrabber *m_fallbackMouseGrabber = nullptr;
|
||||
StateInternalMDIDragging *m_stateDraggingMDI = nullptr;
|
||||
};
|
||||
|
||||
class StateBase : public State
|
||||
@@ -185,6 +192,21 @@ public:
|
||||
bool handleMouseDoubleClick() override;
|
||||
};
|
||||
|
||||
|
||||
/// @brief State when we're moving an MDI dock widget around the main window
|
||||
/// without it becoming floating
|
||||
class StateInternalMDIDragging : public StateBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit StateInternalMDIDragging(DragController *parent);
|
||||
~StateInternalMDIDragging() override;
|
||||
void onEntry() override;
|
||||
bool handleMouseButtonRelease(QPoint globalPos) override;
|
||||
bool handleMouseMove(QPoint globalPos) override;
|
||||
bool handleMouseDoubleClick() override;
|
||||
};
|
||||
|
||||
// Used on wayland only to use QDrag instead of setting geometry on mouse-move.
|
||||
class StateDraggingWayland : public StateDragging
|
||||
{
|
||||
|
||||
@@ -74,8 +74,17 @@ public:
|
||||
* Example: This draggable is a floating window with only 1 dock widget
|
||||
* Example: This draggable is a title bar with two dock widgets -> nullptr
|
||||
*/
|
||||
virtual DockWidgetBase* singleDockWidget() const = 0;
|
||||
virtual DockWidgetBase *singleDockWidget() const = 0;
|
||||
|
||||
///@brief Returns whether this draggable is a MDI window, being dragged internally within a main window
|
||||
virtual bool isMDI() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether this draggable is already a window.
|
||||
*
|
||||
* If true, means the drag will simply move the existing window, and no undocking/untabbing is involved.
|
||||
*/
|
||||
virtual bool isWindow() const = 0;
|
||||
private:
|
||||
class Private;
|
||||
Private *const d;
|
||||
|
||||
@@ -10,16 +10,17 @@
|
||||
*/
|
||||
|
||||
#include "DropArea_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "Draggable_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Config.h"
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "Draggable_p.h"
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "Logging_p.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
// #include "indicators/AnimatedIndicators_p.h"
|
||||
@@ -53,11 +54,6 @@ DropArea::~DropArea()
|
||||
qCDebug(creation) << "~DropArea";
|
||||
}
|
||||
|
||||
int DropArea::numFrames() const
|
||||
{
|
||||
return visibleCount();
|
||||
}
|
||||
|
||||
Frame::List DropArea::frames() const
|
||||
{
|
||||
return findChildren<Frame *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
@@ -104,7 +100,7 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location,
|
||||
return;
|
||||
}
|
||||
|
||||
if ((option.visibility == InitialVisibilityOption::StartHidden) && dw->frame() != nullptr) {
|
||||
if ((option.visibility == InitialVisibilityOption::StartHidden) && dw->d->frame() != nullptr) {
|
||||
// StartHidden is just to be used at startup, not to moving stuff around
|
||||
qWarning() << Q_FUNC_INFO << "Dock widget already exists in the layout";
|
||||
return;
|
||||
@@ -114,15 +110,15 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location,
|
||||
return;
|
||||
|
||||
Frame *frame = nullptr;
|
||||
Frame *relativeToFrame = relativeTo ? relativeTo->frame() : nullptr;
|
||||
Frame *relativeToFrame = relativeTo ? relativeTo->d->frame() : nullptr;
|
||||
|
||||
dw->saveLastFloatingGeometry();
|
||||
dw->d->saveLastFloatingGeometry();
|
||||
|
||||
const bool hadSingleFloatingFrame = hasSingleFloatingFrame();
|
||||
|
||||
// Check if the dock widget already exists in the layout
|
||||
if (containsDockWidget(dw)) {
|
||||
Frame *oldFrame = dw->frame();
|
||||
Frame *oldFrame = dw->d->frame();
|
||||
if (oldFrame->hasSingleDockWidget()) {
|
||||
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
|
||||
@@ -151,7 +147,7 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location,
|
||||
|
||||
bool DropArea::containsDockWidget(DockWidgetBase *dw) const
|
||||
{
|
||||
return dw->frame() && MultiSplitter::containsFrame(dw->frame());
|
||||
return dw->d->frame() && LayoutWidget::containsFrame(dw->d->frame());
|
||||
}
|
||||
|
||||
bool DropArea::hasSingleFloatingFrame() const
|
||||
@@ -173,9 +169,9 @@ QStringList DropArea::affinities() const
|
||||
|
||||
void DropArea::layoutParentContainerEqually(DockWidgetBase *dw)
|
||||
{
|
||||
Layouting::Item *item = itemForFrame(dw->frame());
|
||||
Layouting::Item *item = itemForFrame(dw->d->frame());
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "Item not found for" << dw << dw->frame();
|
||||
qWarning() << Q_FUNC_INFO << "Item not found for" << dw << dw->d->frame();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -261,8 +257,10 @@ bool DropArea::drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame,
|
||||
|
||||
bool result = true;
|
||||
const bool needToFocusNewlyDroppedWidgets = Config::self().flags() & Config::Flag_TitleBarIsFocusable;
|
||||
const DockWidgetBase::List droppedDockWidgets = needToFocusNewlyDroppedWidgets ? droppedWindow->multiSplitter()->dockWidgets()
|
||||
: DockWidgetBase::List(); // just so save some memory allocations for the case where this variable isn't used
|
||||
const DockWidgetBase::List droppedDockWidgets = needToFocusNewlyDroppedWidgets
|
||||
? droppedWindow->layoutWidget()->dockWidgets()
|
||||
: DockWidgetBase::List(); // just so save some memory allocations for the case where this
|
||||
// variable isn't used
|
||||
|
||||
switch (droploc) {
|
||||
case DropIndicatorOverlayInterface::DropLocation_Left:
|
||||
@@ -298,7 +296,7 @@ bool DropArea::drop(WindowBeingDragged *draggedWindow, Frame *acceptingFrame,
|
||||
// Let's also focus the newly dropped dock widget
|
||||
if (!droppedDockWidgets.isEmpty()) {
|
||||
// If more than 1 was dropped, we only focus the first one
|
||||
Frame *frame = droppedDockWidgets.first()->frame();
|
||||
Frame *frame = droppedDockWidgets.first()->d->frame();
|
||||
frame->FocusScope::focus(Qt::MouseFocusReason);
|
||||
} else {
|
||||
// Doesn't happen.
|
||||
|
||||
@@ -48,7 +48,6 @@ public:
|
||||
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;
|
||||
Frame::List frames() const;
|
||||
|
||||
Layouting::Item *centralFrame() const;
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Config.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "DragController_p.h"
|
||||
#include "../LayoutSaver_p.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QWindow>
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
@@ -33,56 +34,16 @@
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
# ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
namespace KDDockWidgets {
|
||||
|
||||
/**
|
||||
* @brief Helper to rediriect WM_NCHITTEST from child widgets to the top-level widget
|
||||
*
|
||||
* To implement aero-snap the top-level window must respond to WM_NCHITTEST, we do that
|
||||
* 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, Qt5Qt6Compat::qintptr *result) override
|
||||
{
|
||||
if (eventType != "windows_generic_MSG" || !m_floatingWindow)
|
||||
return false;
|
||||
|
||||
auto msg = static_cast<MSG *>(message);
|
||||
if (msg->message != WM_NCHITTEST)
|
||||
return false;
|
||||
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 (!isThisWindow) {
|
||||
*result = HTTRANSPARENT;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QPointer<FloatingWindow> m_floatingWindow;
|
||||
};
|
||||
}
|
||||
|
||||
# endif
|
||||
#endif // Q_OS_WIN
|
||||
/** static */
|
||||
Qt::WindowFlags FloatingWindow::s_windowFlagsOverride = {};
|
||||
|
||||
static Qt::WindowFlags windowFlagsToUse()
|
||||
{
|
||||
if (FloatingWindow::s_windowFlagsOverride) {
|
||||
// The user specifically set different flags.
|
||||
return FloatingWindow::s_windowFlagsOverride;
|
||||
}
|
||||
|
||||
if (KDDockWidgets::usesNativeDraggingAndResizing())
|
||||
return Qt::Window;
|
||||
|
||||
@@ -141,11 +102,17 @@ FloatingWindow::FloatingWindow(MainWindowBase *parent)
|
||||
{
|
||||
if (kddwUsesQtWidgets()) {
|
||||
// For QtQuick we do it a bit later, once we have the QQuickWindow
|
||||
setupWindow();
|
||||
#ifdef Q_OS_WIN
|
||||
create();
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
m_nchittestFilter = new NCHITTESTEventFilter(this);
|
||||
qApp->installNativeEventFilter(m_nchittestFilter);
|
||||
#endif
|
||||
WidgetResizeHandler::setupWindow(windowHandle());
|
||||
#endif
|
||||
}
|
||||
|
||||
DockRegistry::self()->registerFloatingWindow(this);
|
||||
qCDebug(creation) << "FloatingWindow()" << this;
|
||||
|
||||
if (Config::self().flags() & Config::Flag_KeepAboveIfNotUtilityWindow)
|
||||
setWindowFlag(Qt::WindowStaysOnTopHint, true);
|
||||
@@ -156,9 +123,12 @@ FloatingWindow::FloatingWindow(MainWindowBase *parent)
|
||||
}
|
||||
|
||||
updateTitleBarVisibility();
|
||||
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::onFrameCountChanged);
|
||||
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::numFramesChanged);
|
||||
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::onVisibleFrameCountChanged);
|
||||
connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged, this,
|
||||
&FloatingWindow::onFrameCountChanged);
|
||||
connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged, this,
|
||||
&FloatingWindow::numFramesChanged);
|
||||
connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged, this,
|
||||
&FloatingWindow::onVisibleFrameCountChanged);
|
||||
m_layoutDestroyedConnection = connect(m_dropArea, &QObject::destroyed, this, &FloatingWindow::scheduleDeleteLater);
|
||||
}
|
||||
|
||||
@@ -180,45 +150,24 @@ FloatingWindow::~FloatingWindow()
|
||||
delete m_nchittestFilter;
|
||||
|
||||
DockRegistry::self()->unregisterFloatingWindow(this);
|
||||
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, Qt5Qt6Compat::qintptr *result)
|
||||
{
|
||||
if (!m_inDtor && !m_deleteScheduled && KDDockWidgets::usesAeroSnapWithCustomDecos()) {
|
||||
if (m_inDtor || m_deleteScheduled)
|
||||
return QWidget::nativeEvent(eventType, message, result);
|
||||
|
||||
if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
|
||||
// To enable aero snap we need to tell Windows where's our custom title bar
|
||||
if (WidgetResizeHandler::handleWindowsNativeEvent(this, eventType, message, result))
|
||||
return true;
|
||||
} else if (KDDockWidgets::usesNativeTitleBar()) {
|
||||
auto msg = static_cast<MSG *>(message);
|
||||
if (msg->message == WM_SIZING) {
|
||||
// Cancel any drag if we're resizing
|
||||
Q_EMIT DragController::instance()->dragCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::nativeEvent(eventType, message, result);
|
||||
@@ -229,7 +178,7 @@ void FloatingWindow::maybeCreateResizeHandler()
|
||||
{
|
||||
if (!KDDockWidgets::usesNativeDraggingAndResizing()) {
|
||||
setFlag(Qt::FramelessWindowHint, true);
|
||||
setWidgetResizeHandler(new WidgetResizeHandler(false, this));
|
||||
setWidgetResizeHandler(new WidgetResizeHandler(/*topLevel=*/ true, this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +210,7 @@ const Frame::List FloatingWindow::frames() const
|
||||
return m_dropArea->frames();
|
||||
}
|
||||
|
||||
void FloatingWindow::setSuggestedGeometry(QRect suggestedRect, bool preserveCenter)
|
||||
void FloatingWindow::setSuggestedGeometry(QRect suggestedRect, SuggestedGeometryHints hint)
|
||||
{
|
||||
const Frame::List frames = this->frames();
|
||||
if (frames.size() == 1) {
|
||||
@@ -276,7 +225,13 @@ void FloatingWindow::setSuggestedGeometry(QRect suggestedRect, bool preserveCent
|
||||
// Resize to new size but preserve center
|
||||
const QPoint originalCenter = suggestedRect.center();
|
||||
suggestedRect.setSize(size);
|
||||
if (preserveCenter)
|
||||
|
||||
if ((hint & SuggestedGeometryHint_GeometryIsFromDocked) && (Config::self().flags() & Config::Flag_NativeTitleBar)) {
|
||||
const QMargins margins = contentMargins();
|
||||
suggestedRect.setHeight(suggestedRect.height() - m_titleBar->height() + margins.top() + margins.bottom());
|
||||
}
|
||||
|
||||
if (hint & SuggestedGeometryHint_PreserveCenter)
|
||||
suggestedRect.moveCenter(originalCenter);
|
||||
}
|
||||
|
||||
@@ -295,14 +250,19 @@ MultiSplitter *FloatingWindow::multiSplitter() const
|
||||
return m_dropArea;
|
||||
}
|
||||
|
||||
LayoutWidget *FloatingWindow::layoutWidget() const
|
||||
{
|
||||
return m_dropArea;
|
||||
}
|
||||
|
||||
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;
|
||||
if (usesAeroSnapWithCustomDecos())
|
||||
return m_lastHitTest == HTCAPTION;
|
||||
#endif
|
||||
|
||||
return dragRect().contains(globalPoint);
|
||||
@@ -328,7 +288,7 @@ bool FloatingWindow::anyNonDockable() const
|
||||
|
||||
bool FloatingWindow::hasSingleFrame() const
|
||||
{
|
||||
return m_dropArea->numFrames() == 1;
|
||||
return m_dropArea->visibleCount() == 1;
|
||||
}
|
||||
|
||||
bool FloatingWindow::hasSingleDockWidget() const
|
||||
@@ -341,6 +301,14 @@ bool FloatingWindow::hasSingleDockWidget() const
|
||||
return frame->dockWidgetCount() == 1;
|
||||
}
|
||||
|
||||
Frame *FloatingWindow::singleFrame() const
|
||||
{
|
||||
const Frame::List frames = this->frames();
|
||||
|
||||
return frames.isEmpty() ? nullptr
|
||||
: frames.first();
|
||||
}
|
||||
|
||||
bool FloatingWindow::beingDeleted() const
|
||||
{
|
||||
if (m_deleteScheduled || m_inDtor)
|
||||
@@ -357,7 +325,6 @@ bool FloatingWindow::beingDeleted() const
|
||||
|
||||
void FloatingWindow::onFrameCountChanged(int count)
|
||||
{
|
||||
qCDebug(docking) << "FloatingWindow::onFrameCountChanged" << count;
|
||||
if (count == 0) {
|
||||
scheduleDeleteLater();
|
||||
} else {
|
||||
@@ -370,7 +337,6 @@ void FloatingWindow::onFrameCountChanged(int count)
|
||||
void FloatingWindow::onVisibleFrameCountChanged(int count)
|
||||
{
|
||||
if (!m_disableSetVisible) {
|
||||
qCDebug(hiding) << "FloatingWindow::onVisibleFrameCountChanged count=" << count;
|
||||
setVisible(count > 0);
|
||||
}
|
||||
}
|
||||
@@ -385,6 +351,9 @@ void FloatingWindow::updateTitleBarVisibility()
|
||||
|
||||
bool visible = true;
|
||||
|
||||
for (Frame *frame : frames())
|
||||
frame->updateTitleBarVisibility();
|
||||
|
||||
if (KDDockWidgets::usesClientTitleBar()) {
|
||||
const auto flags = Config::self().flags();
|
||||
if ((flags & Config::Flag_HideTitleBarWhenTabsVisible) && !(flags & Config::Flag_AlwaysTitleBarWhenFloating)) {
|
||||
@@ -393,8 +362,7 @@ void FloatingWindow::updateTitleBarVisibility()
|
||||
}
|
||||
}
|
||||
|
||||
for (Frame *frame : frames())
|
||||
frame->updateTitleBarVisibility();
|
||||
m_titleBar->updateButtons();
|
||||
} else {
|
||||
visible = false;
|
||||
}
|
||||
@@ -430,8 +398,6 @@ void FloatingWindow::updateTitleAndIcon()
|
||||
|
||||
void FloatingWindow::onCloseEvent(QCloseEvent *e)
|
||||
{
|
||||
qCDebug(closing) << "Frame::closeEvent";
|
||||
|
||||
if (e->spontaneous() && anyNonClosable()) {
|
||||
// Event from the window system won't close us
|
||||
e->ignore();
|
||||
@@ -497,7 +463,75 @@ bool FloatingWindow::event(QEvent *ev)
|
||||
if (ev->type() == QEvent::ActivationChange) {
|
||||
// Since QWidget is missing a signal for window activation
|
||||
Q_EMIT activatedChanged();
|
||||
} else if (ev->type() == QEvent::StatusTip && parent()) {
|
||||
// show status tips in the main window
|
||||
return parent()->event(ev);
|
||||
}
|
||||
|
||||
return QWidgetAdapter::event(ev);
|
||||
}
|
||||
|
||||
bool FloatingWindow::allDockWidgetsHave(DockWidgetBase::Option option) const
|
||||
{
|
||||
const Frame::List frames = this->frames();
|
||||
return std::all_of(frames.begin(), frames.end(), [option] (Frame *frame) {
|
||||
return frame->allDockWidgetsHave(option);
|
||||
});
|
||||
}
|
||||
|
||||
bool FloatingWindow::anyDockWidgetsHas(DockWidgetBase::Option option) const
|
||||
{
|
||||
const Frame::List frames = this->frames();
|
||||
return std::any_of(frames.begin(), frames.end(), [option] (Frame *frame) {
|
||||
return frame->anyDockWidgetsHas(option);
|
||||
});
|
||||
}
|
||||
|
||||
bool FloatingWindow::allDockWidgetsHave(DockWidgetBase::LayoutSaverOption option) const
|
||||
{
|
||||
const Frame::List frames = this->frames();
|
||||
return std::all_of(frames.begin(), frames.end(), [option] (Frame *frame) {
|
||||
return frame->allDockWidgetsHave(option);
|
||||
});
|
||||
}
|
||||
|
||||
bool FloatingWindow::anyDockWidgetsHas(DockWidgetBase::LayoutSaverOption option) const
|
||||
{
|
||||
const Frame::List frames = this->frames();
|
||||
return std::any_of(frames.begin(), frames.end(), [option] (Frame *frame) {
|
||||
return frame->anyDockWidgetsHas(option);
|
||||
});
|
||||
}
|
||||
|
||||
void FloatingWindow::addDockWidget(DockWidgetBase *dw, Location location,
|
||||
DockWidgetBase *relativeTo, InitialOption option)
|
||||
{
|
||||
m_dropArea->addDockWidget(dw, location, relativeTo, option);
|
||||
}
|
||||
|
||||
bool FloatingWindow::isMDI() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FloatingWindow::isWindow() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
MainWindowBase *FloatingWindow::mainWindow() const
|
||||
{
|
||||
return qobject_cast<MainWindowBase*>(parent());
|
||||
}
|
||||
|
||||
QMargins FloatingWindow::contentMargins() const
|
||||
{
|
||||
return { 4, 4, 4, 4 };
|
||||
}
|
||||
|
||||
int FloatingWindow::userType() const
|
||||
{
|
||||
if (Frame *f = singleFrame())
|
||||
return f->userType();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
#ifndef KD_FLOATING_WINDOW_P_H
|
||||
#define KD_FLOATING_WINDOW_P_H
|
||||
|
||||
#include "../docks_export.h"
|
||||
#include "../QWidgetAdapter.h"
|
||||
#include "../LayoutSaver_p.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
#include "kddockwidgets/LayoutSaver.h"
|
||||
#include "kddockwidgets/Qt5Qt6Compat_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "Draggable_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "kddockwidgets/Qt5Qt6Compat_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAbstractNativeEventFilter;
|
||||
@@ -31,6 +31,7 @@ class MainWindowBase;
|
||||
class DropArea;
|
||||
class Frame;
|
||||
class MultiSplitter;
|
||||
class LayoutWidget;
|
||||
|
||||
class DOCKS_EXPORT FloatingWindow
|
||||
: public QWidgetAdapter
|
||||
@@ -50,11 +51,14 @@ public:
|
||||
// Draggable:
|
||||
std::unique_ptr<WindowBeingDragged> makeWindow() override;
|
||||
DockWidgetBase *singleDockWidget() const override;
|
||||
bool isWindow() const override;
|
||||
|
||||
const QVector<DockWidgetBase*> dockWidgets() const;
|
||||
const Frame::List frames() const;
|
||||
DropArea *dropArea() const { return m_dropArea; }
|
||||
|
||||
int userType() const;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void setLastHitTest(int hitTest) {
|
||||
m_lastHitTest = hitTest;
|
||||
@@ -75,7 +79,7 @@ public:
|
||||
* @param preserveCenter, if true, then the center is preserved
|
||||
*
|
||||
*/
|
||||
void setSuggestedGeometry(QRect suggestedRect, bool preserveCenter = false);
|
||||
void setSuggestedGeometry(QRect suggestedRect, SuggestedGeometryHints = SuggestedGeometryHint_None);
|
||||
|
||||
bool anyNonClosable() const;
|
||||
bool anyNonDockable() const;
|
||||
@@ -97,6 +101,9 @@ public:
|
||||
*/
|
||||
bool hasSingleDockWidget() const;
|
||||
|
||||
/// @brief If this floating window has only one Frame, it's returned, otherwise nullptr
|
||||
Frame* singleFrame() const;
|
||||
|
||||
/**
|
||||
* @brief Returns whether a deleteLater has already been issued
|
||||
*/
|
||||
@@ -112,12 +119,19 @@ public:
|
||||
*/
|
||||
MultiSplitter *multiSplitter() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the LayoutWidget
|
||||
*/
|
||||
LayoutWidget *layoutWidget() const;
|
||||
|
||||
/**
|
||||
* @brief Returns whether @p globalPoint is inside the title bar (or, when there's no title-bar, the draggable empty
|
||||
* area of a tab bar)
|
||||
*/
|
||||
bool isInDragArea(QPoint globalPoint) const;
|
||||
|
||||
bool isMDI() const override;
|
||||
|
||||
///@brief updates the title and the icon
|
||||
void updateTitleAndIcon();
|
||||
void updateTitleBarVisibility();
|
||||
@@ -131,12 +145,40 @@ public:
|
||||
*/
|
||||
QRect dragRect() const;
|
||||
|
||||
///@brief Returns whether all dock widgets have the specified option set
|
||||
bool allDockWidgetsHave(DockWidgetBase::Option) const;
|
||||
|
||||
///@brief Returns whether at least one dock widget has the specified option set
|
||||
bool anyDockWidgetsHas(DockWidgetBase::Option) const;
|
||||
|
||||
///@brief Returns whether all dock widgets have the specified layout saver option set
|
||||
bool allDockWidgetsHave(DockWidgetBase::LayoutSaverOption) const;
|
||||
|
||||
///@brief Returns whether at least one dock widget has the specified layout saver option set
|
||||
bool anyDockWidgetsHas(DockWidgetBase::LayoutSaverOption) const;
|
||||
|
||||
/// @brief Adds the dock widget to the specified location
|
||||
void addDockWidget(DockWidgetBase *, KDDockWidgets::Location location,
|
||||
DockWidgetBase *relativeTo, InitialOption = {});
|
||||
|
||||
/// @brief Returns the MainWindow which is the transient parent of this FloatingWindow
|
||||
/// Can be nullptr if you create dock widgets before the main window. Can also be some
|
||||
/// arbitrary value if you have more than one main window.
|
||||
MainWindowBase *mainWindow() const;
|
||||
|
||||
///@brief Returns the contents margins
|
||||
QMargins contentMargins() const;
|
||||
|
||||
///@brief Allows the user app to specify which window flags to use, instead of KDDWs default ones
|
||||
///Bugs caused by this won't be supported, as the amount of combinations that could go wrong can
|
||||
///be open ended
|
||||
static Qt::WindowFlags s_windowFlagsOverride;
|
||||
|
||||
Q_SIGNALS:
|
||||
void activatedChanged();
|
||||
void numFramesChanged();
|
||||
void windowStateChanged(QWindowStateChangeEvent *);
|
||||
protected:
|
||||
void setupWindow();
|
||||
void maybeCreateResizeHandler();
|
||||
|
||||
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
|
||||
|
||||
@@ -16,17 +16,21 @@
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
|
||||
#include "Frame_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Config.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "TabWidget_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "TabWidget_p.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
@@ -47,23 +51,23 @@ static FrameOptions actualOptions(FrameOptions options)
|
||||
}
|
||||
}
|
||||
|
||||
Frame::Frame(QWidgetOrQuick *parent, FrameOptions options)
|
||||
Frame::Frame(QWidgetOrQuick *parent, FrameOptions options, int userType)
|
||||
: LayoutGuestWidget(parent)
|
||||
, FocusScope(this)
|
||||
, m_tabWidget(Config::self().frameworkWidgetFactory()->createTabWidget(this))
|
||||
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
|
||||
, m_options(actualOptions(options))
|
||||
, m_userType(userType)
|
||||
{
|
||||
s_dbg_numFrames++;
|
||||
DockRegistry::self()->registerFrame(this);
|
||||
qCDebug(creation) << "Frame" << ((void*)this) << s_dbg_numFrames;
|
||||
|
||||
connect(this, &Frame::currentDockWidgetChanged, this, &Frame::updateTitleAndIcon);
|
||||
|
||||
connect(m_tabWidget->asWidget(), SIGNAL(currentTabChanged(int)), // clazy:exclude=old-style-connect
|
||||
this, SLOT(onCurrentTabChanged(int)));
|
||||
|
||||
setDropArea(qobject_cast<DropArea *>(QWidgetAdapter::parentWidget()));
|
||||
setLayoutWidget(qobject_cast<LayoutWidget *>(QWidgetAdapter::parentWidget()));
|
||||
m_inCtor = false;
|
||||
}
|
||||
|
||||
@@ -74,11 +78,13 @@ Frame::~Frame()
|
||||
if (m_layoutItem)
|
||||
m_layoutItem->unref();
|
||||
|
||||
qCDebug(creation) << "~Frame" << static_cast<void*>(this);
|
||||
delete m_resizeHandler;
|
||||
m_resizeHandler = nullptr;
|
||||
|
||||
DockRegistry::self()->unregisterFrame(this);
|
||||
|
||||
// Run some disconnects() too, so we don't receive signals during destruction:
|
||||
setDropArea(nullptr);
|
||||
setLayoutWidget(nullptr);
|
||||
}
|
||||
|
||||
void Frame::updateTitleAndIcon()
|
||||
@@ -136,17 +142,13 @@ void Frame::addWidget(FloatingWindow *floatingWindow, InitialOption addingOption
|
||||
|
||||
void Frame::insertWidget(DockWidgetBase *dockWidget, int index, InitialOption addingOption)
|
||||
{
|
||||
qCDebug(addwidget()) << Q_FUNC_INFO << ((void*)this) << "; dockWidget="
|
||||
<< dockWidget << "; oldFrame=" << dockWidget->frame()
|
||||
<< "; initialOption=" << addingOption;
|
||||
|
||||
Q_ASSERT(dockWidget);
|
||||
if (containsDockWidget(dockWidget)) {
|
||||
qWarning() << "Frame::addWidget dockWidget already exists. this=" << this << "; dockWidget=" << dockWidget;
|
||||
return;
|
||||
}
|
||||
if (m_layoutItem)
|
||||
dockWidget->addPlaceholderItem(m_layoutItem);
|
||||
dockWidget->d->addPlaceholderItem(m_layoutItem);
|
||||
|
||||
insertDockWidget(dockWidget, index);
|
||||
|
||||
@@ -181,6 +183,8 @@ FloatingWindow* Frame::detachTab(DockWidgetBase *dockWidget)
|
||||
{
|
||||
if (m_inCtor || m_inDtor) return nullptr;
|
||||
|
||||
dockWidget->d->saveTabIndex();
|
||||
|
||||
QRect r = dockWidget->geometry();
|
||||
removeWidget(dockWidget);
|
||||
|
||||
@@ -192,13 +196,13 @@ FloatingWindow* Frame::detachTab(DockWidgetBase *dockWidget)
|
||||
|
||||
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(newFrame);
|
||||
r.moveTopLeft(globalPoint);
|
||||
floatingWindow->setSuggestedGeometry(r);
|
||||
floatingWindow->setSuggestedGeometry(r, SuggestedGeometryHint_GeometryIsFromDocked);
|
||||
floatingWindow->show();
|
||||
|
||||
return floatingWindow;
|
||||
}
|
||||
|
||||
int Frame::indexOfDockWidget(DockWidgetBase *dw)
|
||||
int Frame::indexOfDockWidget(const DockWidgetBase *dw)
|
||||
{
|
||||
if (m_inCtor || m_inDtor) return -1;
|
||||
|
||||
@@ -268,7 +272,7 @@ void Frame::onDockWidgetCountChanged()
|
||||
|
||||
const DockWidgetBase::List docks = dockWidgets();
|
||||
for (DockWidgetBase *dock : docks)
|
||||
dock->updateFloatAction();
|
||||
dock->d->updateFloatAction();
|
||||
}
|
||||
|
||||
Q_EMIT numDockWidgetsChanged();
|
||||
@@ -316,7 +320,15 @@ void Frame::updateTitleBarVisibility()
|
||||
visible = true;
|
||||
}
|
||||
|
||||
const bool wasVisible = m_titleBar->isVisible();
|
||||
m_titleBar->setVisible(visible);
|
||||
|
||||
if (wasVisible != visible) {
|
||||
Q_EMIT actualTitleBarChanged();
|
||||
for (auto dw : dockWidgets())
|
||||
Q_EMIT dw->actualTitleBarChanged();
|
||||
}
|
||||
|
||||
if (auto fw = floatingWindow()) {
|
||||
// Update the floating window which might be using Flag_HideTitleBarWhenTabsVisible
|
||||
// In that case it might not show title bar depending on the number of tabs that the frame has
|
||||
@@ -328,7 +340,7 @@ void Frame::updateFloatingActions()
|
||||
{
|
||||
const QVector<DockWidgetBase *> widgets = dockWidgets();
|
||||
for (DockWidgetBase *dw : widgets)
|
||||
dw->updateFloatAction();
|
||||
dw->d->updateFloatAction();
|
||||
}
|
||||
|
||||
bool Frame::containsMouse(QPoint globalPos) const
|
||||
@@ -506,10 +518,10 @@ void Frame::setLayoutItem(Layouting::Item *item)
|
||||
m_layoutItem = item;
|
||||
if (item) {
|
||||
for (DockWidgetBase *dw : dockWidgets())
|
||||
dw->addPlaceholderItem(item);
|
||||
dw->d->addPlaceholderItem(item);
|
||||
} else {
|
||||
for (DockWidgetBase *dw : dockWidgets())
|
||||
dw->lastPositions().removePlaceholders();
|
||||
dw->d->lastPositions().removePlaceholders();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,35 +557,40 @@ QStringList Frame::affinities() const
|
||||
}
|
||||
}
|
||||
|
||||
void Frame::setDropArea(DropArea *dt)
|
||||
void Frame::setLayoutWidget(LayoutWidget *dt)
|
||||
{
|
||||
if (dt == m_dropArea)
|
||||
if (dt == m_layoutWidget)
|
||||
return;
|
||||
|
||||
|
||||
qCDebug(docking) << "Frame::setDropArea dt=" << dt;
|
||||
const bool wasInMainWindow = dt && isInMainWindow();
|
||||
if (m_dropArea)
|
||||
const bool wasMDI = isMDI();
|
||||
if (m_layoutWidget)
|
||||
disconnect(m_visibleWidgetCountChangedConnection);
|
||||
|
||||
m_dropArea = dt;
|
||||
m_layoutWidget = dt;
|
||||
delete m_resizeHandler;
|
||||
m_resizeHandler = nullptr;
|
||||
|
||||
if (m_dropArea) {
|
||||
// We keep the connect result so we don't dereference m_dropArea at shutdown
|
||||
m_visibleWidgetCountChangedConnection = connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged,
|
||||
this, &Frame::updateTitleBarVisibility);
|
||||
if (m_layoutWidget) {
|
||||
if (isMDI())
|
||||
m_resizeHandler = new WidgetResizeHandler(/*topLevel=*/ false, this);
|
||||
|
||||
// We keep the connect result so we don't dereference m_layoutWidget at shutdown
|
||||
m_visibleWidgetCountChangedConnection =
|
||||
connect(m_layoutWidget, &LayoutWidget::visibleWidgetCountChanged, this,
|
||||
&Frame::updateTitleBarVisibility);
|
||||
updateTitleBarVisibility();
|
||||
if (wasInMainWindow != isInMainWindow())
|
||||
Q_EMIT isInMainWindowChanged();
|
||||
}
|
||||
|
||||
if (wasMDI != isMDI())
|
||||
Q_EMIT isMDIChanged();
|
||||
}
|
||||
|
||||
bool Frame::isTheOnlyFrame() const
|
||||
{
|
||||
qCDebug(docking) << "Frame::isTheOnlyFrame() m_dropArea=" << m_dropArea << "; numFrames"
|
||||
<< (m_dropArea ? m_dropArea->numFrames() : 0);
|
||||
return m_dropArea && m_dropArea->numFrames() == 1;
|
||||
return m_layoutWidget && m_layoutWidget->visibleCount() == 1;
|
||||
}
|
||||
|
||||
bool Frame::isOverlayed() const
|
||||
@@ -581,6 +598,11 @@ bool Frame::isOverlayed() const
|
||||
return m_options & FrameOption_IsOverlayed;
|
||||
}
|
||||
|
||||
void Frame::unoverlay()
|
||||
{
|
||||
m_options &= ~FrameOption_IsOverlayed;
|
||||
}
|
||||
|
||||
bool Frame::isFloating() const
|
||||
{
|
||||
if (isInMainWindow())
|
||||
@@ -602,10 +624,10 @@ bool Frame::isInMainWindow() const
|
||||
bool Frame::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::ParentChange) {
|
||||
if (auto dropArea = qobject_cast<DropArea *>(QWidgetAdapter::parentWidget())) {
|
||||
setDropArea(dropArea);
|
||||
if (auto layoutWidget = qobject_cast<LayoutWidget *>(QWidgetAdapter::parentWidget())) {
|
||||
setLayoutWidget(layoutWidget);
|
||||
} else {
|
||||
setDropArea(nullptr);
|
||||
setLayoutWidget(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +668,7 @@ LayoutSaver::Frame Frame::serialize() const
|
||||
frame.id = id(); // for coorelation purposes
|
||||
|
||||
for (DockWidgetBase *dock : docks)
|
||||
frame.dockWidgets.push_back(dock->serialize());
|
||||
frame.dockWidgets.push_back(dock->d->serialize());
|
||||
|
||||
return frame;
|
||||
}
|
||||
@@ -705,18 +727,78 @@ QRect Frame::dragRect() const
|
||||
return rect;
|
||||
}
|
||||
|
||||
DropArea *Frame::dropArea() const
|
||||
{
|
||||
return m_dropArea;
|
||||
}
|
||||
|
||||
MainWindowBase *Frame::mainWindow() const
|
||||
{
|
||||
return m_dropArea ? m_dropArea->mainWindow()
|
||||
: nullptr;
|
||||
return m_layoutWidget ? m_layoutWidget->mainWindow() : nullptr;
|
||||
}
|
||||
|
||||
TabWidget *Frame::tabWidget() const
|
||||
{
|
||||
return m_tabWidget;
|
||||
}
|
||||
|
||||
///@brief Returns whether all dock widgets have the specified option set
|
||||
bool Frame::allDockWidgetsHave(DockWidgetBase::Option option) const
|
||||
{
|
||||
const DockWidgetBase::List docks = dockWidgets();
|
||||
return std::all_of(docks.cbegin(), docks.cend(), [option] (DockWidgetBase *dw) {
|
||||
return dw->options() & option;
|
||||
});
|
||||
}
|
||||
|
||||
///@brief Returns whether at least one dock widget has the specified option set
|
||||
bool Frame::anyDockWidgetsHas(DockWidgetBase::Option option) const
|
||||
{
|
||||
const DockWidgetBase::List docks = dockWidgets();
|
||||
return std::any_of(docks.cbegin(), docks.cend(), [option] (DockWidgetBase *dw) {
|
||||
return dw->options() & option;
|
||||
});
|
||||
}
|
||||
|
||||
bool Frame::allDockWidgetsHave(DockWidgetBase::LayoutSaverOption option) const
|
||||
{
|
||||
const DockWidgetBase::List docks = dockWidgets();
|
||||
return std::all_of(docks.cbegin(), docks.cend(), [option] (DockWidgetBase *dw) {
|
||||
return dw->layoutSaverOptions() & option;
|
||||
});
|
||||
}
|
||||
|
||||
bool Frame::anyDockWidgetsHas(DockWidgetBase::LayoutSaverOption option) const
|
||||
{
|
||||
const DockWidgetBase::List docks = dockWidgets();
|
||||
return std::any_of(docks.cbegin(), docks.cend(), [option] (DockWidgetBase *dw) {
|
||||
return dw->layoutSaverOptions() & option;
|
||||
});
|
||||
}
|
||||
|
||||
void Frame::setAllowedResizeSides(CursorPositions sides)
|
||||
{
|
||||
if (sides) {
|
||||
delete m_resizeHandler;
|
||||
m_resizeHandler = new WidgetResizeHandler(/*topLevel=*/ false, this);
|
||||
m_resizeHandler->setAllowedResizeSides(sides);
|
||||
} else {
|
||||
delete m_resizeHandler;
|
||||
m_resizeHandler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Frame::isMDI() const
|
||||
{
|
||||
return mdiLayoutWidget() != nullptr;
|
||||
}
|
||||
|
||||
MDILayoutWidget *Frame::mdiLayoutWidget() const
|
||||
{
|
||||
return qobject_cast<MDILayoutWidget *>(m_layoutWidget);
|
||||
}
|
||||
|
||||
int Frame::userType() const
|
||||
{
|
||||
return m_userType;
|
||||
}
|
||||
|
||||
WidgetResizeHandler *Frame::resizeHandler() const
|
||||
{
|
||||
return m_resizeHandler;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
#include "kddockwidgets/FocusScope.h"
|
||||
#include "../LayoutSaver_p.h"
|
||||
#include "kddockwidgets/DockWidgetBase.h"
|
||||
#include "kddockwidgets/LayoutSaver.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
|
||||
#include <QVector>
|
||||
@@ -35,10 +36,11 @@ namespace KDDockWidgets {
|
||||
|
||||
class TitleBar;
|
||||
class TabWidget;
|
||||
class DropArea;
|
||||
class DockWidgetBase;
|
||||
class FloatingWindow;
|
||||
class MainWindowBase;
|
||||
class MDILayoutWidget;
|
||||
class WidgetResizeHandler;
|
||||
|
||||
/**
|
||||
* @brief A DockWidget wrapper that adds a QTabWidget and a TitleBar
|
||||
@@ -46,9 +48,9 @@ class MainWindowBase;
|
||||
* Frame is the actual widget that goes into the MultiSplitter. It provides a TitleBar which you
|
||||
* can use to detach, and also a QTabWidget so you can tab dock widgets together.
|
||||
*
|
||||
* This class doesn't actually add window frames and it's never a top-level widget. A Frame is always
|
||||
* inside a MultiSplitter (DropArea). Be it a MultiSplitter belonging to a MainWindow or belonging
|
||||
* to a FloatingWindow.
|
||||
* This class doesn't actually add window frames and it's never a top-level widget. A Frame is
|
||||
* always inside a LayoutWidget. Be it a MultiSplitter belonging to a MainWindow or belonging to a
|
||||
* FloatingWindow.
|
||||
*/
|
||||
class DOCKS_EXPORT Frame
|
||||
: public LayoutGuestWidget
|
||||
@@ -56,11 +58,15 @@ class DOCKS_EXPORT Frame
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(KDDockWidgets::TitleBar* titleBar READ titleBar CONSTANT)
|
||||
Q_PROPERTY(KDDockWidgets::TitleBar* actualTitleBar READ actualTitleBar NOTIFY actualTitleBarChanged)
|
||||
Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentDockWidgetChanged)
|
||||
Q_PROPERTY(int userType READ userType CONSTANT)
|
||||
Q_PROPERTY(bool isMDI READ isMDI NOTIFY isMDIChanged)
|
||||
public:
|
||||
typedef QList<Frame *> List;
|
||||
|
||||
explicit Frame(QWidgetOrQuick *parent = nullptr, FrameOptions = FrameOption_None);
|
||||
explicit Frame(QWidgetOrQuick *parent = nullptr, FrameOptions = FrameOption_None,
|
||||
int userType = 0);
|
||||
~Frame() override;
|
||||
|
||||
static Frame *deserialize(const LayoutSaver::Frame &);
|
||||
@@ -83,7 +89,7 @@ public:
|
||||
FloatingWindow *detachTab(DockWidgetBase *);
|
||||
|
||||
///@brief returns the index of the specified dock widget
|
||||
int indexOfDockWidget(DockWidgetBase *);
|
||||
int indexOfDockWidget(const DockWidgetBase *);
|
||||
|
||||
///@brief returns the index of the current tab
|
||||
int currentIndex() const;
|
||||
@@ -120,16 +126,15 @@ public:
|
||||
QIcon icon() const;
|
||||
const QVector<DockWidgetBase *> dockWidgets() const;
|
||||
|
||||
void setDropArea(DropArea *);
|
||||
|
||||
///@brief Returns the drop area this Frame is in.
|
||||
DropArea *dropArea() const;
|
||||
|
||||
bool isTheOnlyFrame() const;
|
||||
|
||||
///@brief Returns whether this frame is overlayed on top of the MainWindow (auto-hide feature);
|
||||
bool isOverlayed() const;
|
||||
|
||||
///@brief clears the FrameOption_IsOverlayed flag.
|
||||
/// For example, if you drag a side-bar overlay, then it becomes a normal floating window
|
||||
void unoverlay();
|
||||
|
||||
/**
|
||||
* @brief Returns whether this frame is floating. A floating frame isn't attached to any other MainWindow,
|
||||
* and if it's attached to a FloatingWindow then it's considered floating if it's the only frame in that Window.
|
||||
@@ -239,6 +244,35 @@ public:
|
||||
*/
|
||||
virtual QRect dragRect() const;
|
||||
|
||||
///@brief Returns whether all dock widgets have the specified option set
|
||||
bool allDockWidgetsHave(DockWidgetBase::Option) const;
|
||||
|
||||
///@brief Returns whether at least one dock widget has the specified option set
|
||||
bool anyDockWidgetsHas(DockWidgetBase::Option) const;
|
||||
|
||||
///@brief Returns whether all dock widgets have the specified layout saver option set
|
||||
bool allDockWidgetsHave(DockWidgetBase::LayoutSaverOption) const;
|
||||
|
||||
///@brief Returns whether at least one dock widget has the specified layout saver option set
|
||||
bool anyDockWidgetsHas(DockWidgetBase::LayoutSaverOption) const;
|
||||
|
||||
/// @brief Usually we do resize via the native window manager, but if a widget is docked like
|
||||
/// in MDI mode, or in overlayed mode then we allow the user to resize with mouse
|
||||
void setAllowedResizeSides(CursorPositions sides);
|
||||
|
||||
/// @brief Returns whether this frame is in a MDI layout
|
||||
/// Usually no, unless you're using an MDI main window
|
||||
bool isMDI() const;
|
||||
|
||||
/// @brief Returns the MDI layout. Or nullptr if this frame isn't in a MDI layout
|
||||
MDILayoutWidget *mdiLayoutWidget() const;
|
||||
|
||||
/// @brief See DockWidgetBase::userType()
|
||||
int userType() const;
|
||||
|
||||
/// @brief Returns the resize handler. Used mostly in MDI mode.
|
||||
WidgetResizeHandler *resizeHandler() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void currentDockWidgetChanged(KDDockWidgets::DockWidgetBase *);
|
||||
void numDockWidgetsChanged();
|
||||
@@ -247,6 +281,8 @@ Q_SIGNALS:
|
||||
void isInMainWindowChanged();
|
||||
void isFocusedChanged();
|
||||
void focusedWidgetChanged();
|
||||
void isMDIChanged();
|
||||
void actualTitleBarChanged();
|
||||
|
||||
protected:
|
||||
void isFocusedChangedCallback() final;
|
||||
@@ -280,7 +316,7 @@ protected:
|
||||
QSize biggestDockWidgetMaxSize() const;
|
||||
|
||||
virtual void removeWidget_impl(DockWidgetBase *) = 0;
|
||||
virtual int indexOfDockWidget_impl(DockWidgetBase *) = 0;
|
||||
virtual int indexOfDockWidget_impl(const DockWidgetBase *) = 0;
|
||||
virtual int currentIndex_impl() const = 0;
|
||||
virtual void setCurrentTabIndex_impl(int index) = 0;
|
||||
virtual void setCurrentDockWidget_impl(DockWidgetBase *) = 0;
|
||||
@@ -288,6 +324,7 @@ protected:
|
||||
virtual DockWidgetBase *dockWidgetAt_impl(int index) const = 0;
|
||||
virtual DockWidgetBase *currentDockWidget_impl() const = 0;
|
||||
virtual int nonContentsHeight() const = 0;
|
||||
|
||||
private:
|
||||
bool m_inCtor = true; // Needs to be initialized early, as pointed out by UBSAN
|
||||
protected:
|
||||
@@ -304,11 +341,16 @@ private:
|
||||
void scheduleDeleteLater();
|
||||
bool event(QEvent *) override;
|
||||
|
||||
DropArea *m_dropArea = nullptr;
|
||||
const FrameOptions m_options;
|
||||
/// @brief Sets the LayoutWidget which this frame is in
|
||||
void setLayoutWidget(LayoutWidget *);
|
||||
|
||||
LayoutWidget *m_layoutWidget = nullptr;
|
||||
WidgetResizeHandler *m_resizeHandler = nullptr;
|
||||
FrameOptions m_options = FrameOption_None;
|
||||
QPointer<Layouting::Item> m_layoutItem;
|
||||
bool m_updatingTitleBar = false;
|
||||
bool m_beingDeleted = false;
|
||||
int m_userType = 0;
|
||||
QMetaObject::Connection m_visibleWidgetCountChangedConnection;
|
||||
};
|
||||
|
||||
|
||||
287
src/private/LayoutWidget.cpp
Normal file
287
src/private/LayoutWidget.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company
|
||||
<info@kdab.com> Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "../LayoutSaver_p.h"
|
||||
#include "Config.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "Position_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
|
||||
LayoutWidget::LayoutWidget(QWidgetOrQuick *parent)
|
||||
: LayoutGuestWidget(parent)
|
||||
{
|
||||
}
|
||||
|
||||
LayoutWidget::~LayoutWidget()
|
||||
{
|
||||
if (m_rootItem->hostWidget()->asQObject() == this)
|
||||
delete m_rootItem;
|
||||
DockRegistry::self()->unregisterLayout(this);
|
||||
}
|
||||
|
||||
bool LayoutWidget::isInMainWindow() const
|
||||
{
|
||||
return mainWindow() != nullptr;
|
||||
}
|
||||
|
||||
MainWindowBase *LayoutWidget::mainWindow() const
|
||||
{
|
||||
if (auto pw = QWidgetAdapter::parentWidget()) {
|
||||
// Note that if pw is a FloatingWindow then pw->parentWidget() can be a MainWindow too, as
|
||||
// it's parented
|
||||
if (pw->objectName() == QLatin1String("MyCentralWidget"))
|
||||
return qobject_cast<MainWindowBase *>(pw->parentWidget());
|
||||
|
||||
if (auto mw = qobject_cast<MainWindowBase *>(pw))
|
||||
return mw;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FloatingWindow *LayoutWidget::floatingWindow() const
|
||||
{
|
||||
return qobject_cast<FloatingWindow *>(QWidgetAdapter::parentWidget());
|
||||
}
|
||||
|
||||
void LayoutWidget::setRootItem(Layouting::ItemContainer *root)
|
||||
{
|
||||
delete m_rootItem;
|
||||
m_rootItem = root;
|
||||
connect(m_rootItem, &Layouting::ItemContainer::numVisibleItemsChanged, this,
|
||||
&MultiSplitter::visibleWidgetCountChanged);
|
||||
connect(m_rootItem, &Layouting::ItemContainer::minSizeChanged, this,
|
||||
[this] { setMinimumSize(layoutMinimumSize()); });
|
||||
}
|
||||
|
||||
QSize LayoutWidget::layoutMinimumSize() const
|
||||
{
|
||||
return m_rootItem->minSize();
|
||||
}
|
||||
|
||||
QSize LayoutWidget::layoutMaximumSizeHint() const
|
||||
{
|
||||
return m_rootItem->maxSizeHint();
|
||||
}
|
||||
|
||||
void LayoutWidget::setLayoutMinimumSize(QSize sz)
|
||||
{
|
||||
if (sz != m_rootItem->minSize()) {
|
||||
setLayoutSize(size().expandedTo(m_rootItem->minSize())); // Increase size in case we need to
|
||||
m_rootItem->setMinSize(sz);
|
||||
}
|
||||
}
|
||||
|
||||
QSize LayoutWidget::size() const
|
||||
{
|
||||
return m_rootItem->size();
|
||||
}
|
||||
|
||||
void LayoutWidget::clearLayout()
|
||||
{
|
||||
m_rootItem->clear();
|
||||
}
|
||||
|
||||
bool LayoutWidget::checkSanity() const
|
||||
{
|
||||
return m_rootItem->checkSanity();
|
||||
}
|
||||
|
||||
void LayoutWidget::dumpLayout() const
|
||||
{
|
||||
m_rootItem->dumpLayout();
|
||||
}
|
||||
|
||||
void LayoutWidget::restorePlaceholder(DockWidgetBase *dw, Layouting::Item *item, int tabIndex)
|
||||
{
|
||||
if (item->isPlaceholder()) {
|
||||
Frame *newFrame = Config::self().frameworkWidgetFactory()->createFrame(this);
|
||||
item->restore(newFrame);
|
||||
}
|
||||
|
||||
auto frame = qobject_cast<Frame *>(item->guestAsQObject());
|
||||
Q_ASSERT(frame);
|
||||
|
||||
if (tabIndex != -1 && frame->dockWidgetCount() >= tabIndex) {
|
||||
frame->insertWidget(dw, tabIndex);
|
||||
} else {
|
||||
frame->addWidget(dw);
|
||||
}
|
||||
|
||||
frame->QWidgetAdapter::setVisible(true);
|
||||
}
|
||||
|
||||
void LayoutWidget::unrefOldPlaceholders(const Frame::List &framesBeingAdded) const
|
||||
{
|
||||
for (Frame *frame : framesBeingAdded) {
|
||||
for (DockWidgetBase *dw : frame->dockWidgets()) {
|
||||
dw->d->lastPositions().removePlaceholders(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutWidget::setLayoutSize(QSize size)
|
||||
{
|
||||
if (size != this->size()) {
|
||||
m_rootItem->setSize_recursive(size);
|
||||
if (!m_inResizeEvent && !LayoutSaver::restoreInProgress())
|
||||
resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
const Layouting::Item::List LayoutWidget::items() const
|
||||
{
|
||||
return m_rootItem->items_recursive();
|
||||
}
|
||||
|
||||
bool LayoutWidget::containsItem(const Layouting::Item *item) const
|
||||
{
|
||||
return m_rootItem->contains_recursive(item);
|
||||
}
|
||||
|
||||
bool LayoutWidget::containsFrame(const Frame *frame) const
|
||||
{
|
||||
return itemForFrame(frame) != nullptr;
|
||||
}
|
||||
|
||||
int LayoutWidget::count() const
|
||||
{
|
||||
return m_rootItem->count_recursive();
|
||||
}
|
||||
|
||||
int LayoutWidget::visibleCount() const
|
||||
{
|
||||
return m_rootItem->visibleCount_recursive();
|
||||
}
|
||||
|
||||
int LayoutWidget::placeholderCount() const
|
||||
{
|
||||
return count() - visibleCount();
|
||||
}
|
||||
|
||||
Layouting::Item *LayoutWidget::itemForFrame(const Frame *frame) const
|
||||
{
|
||||
if (!frame)
|
||||
return nullptr;
|
||||
|
||||
return m_rootItem->itemForWidget(frame);
|
||||
}
|
||||
|
||||
DockWidgetBase::List LayoutWidget::dockWidgets() const
|
||||
{
|
||||
DockWidgetBase::List dockWidgets;
|
||||
const Frame::List frames = this->frames();
|
||||
for (Frame *frame : frames)
|
||||
dockWidgets << frame->dockWidgets();
|
||||
|
||||
return dockWidgets;
|
||||
}
|
||||
|
||||
Frame::List LayoutWidget::framesFrom(QWidgetOrQuick *frameOrMultiSplitter) const
|
||||
{
|
||||
if (auto frame = qobject_cast<Frame *>(frameOrMultiSplitter))
|
||||
return { frame };
|
||||
|
||||
if (auto msw = qobject_cast<MultiSplitter *>(frameOrMultiSplitter))
|
||||
return msw->frames();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Frame::List LayoutWidget::frames() const
|
||||
{
|
||||
const Layouting::Item::List items = m_rootItem->items_recursive();
|
||||
|
||||
Frame::List result;
|
||||
result.reserve(items.size());
|
||||
|
||||
for (Layouting::Item *item : items) {
|
||||
if (auto f = static_cast<Frame *>(item->guestAsQObject()))
|
||||
result.push_back(f);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LayoutWidget::removeItem(Layouting::Item *item)
|
||||
{
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "nullptr item";
|
||||
return;
|
||||
}
|
||||
|
||||
item->parentContainer()->removeItem(item);
|
||||
}
|
||||
|
||||
void LayoutWidget::updateSizeConstraints()
|
||||
{
|
||||
const QSize newMinSize = m_rootItem->minSize();
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "Updating size constraints from" << minimumSize() << "to"
|
||||
<< newMinSize;
|
||||
|
||||
setLayoutMinimumSize(newMinSize);
|
||||
}
|
||||
|
||||
bool LayoutWidget::deserialize(const LayoutSaver::MultiSplitter &l)
|
||||
{
|
||||
QHash<QString, Layouting::Widget *> frames;
|
||||
for (const LayoutSaver::Frame &frame : qAsConst(l.frames)) {
|
||||
Frame *f = Frame::deserialize(frame);
|
||||
Q_ASSERT(!frame.id.isEmpty());
|
||||
frames.insert(frame.id, f);
|
||||
}
|
||||
|
||||
m_rootItem->fillFromVariantMap(l.layout, frames);
|
||||
|
||||
updateSizeConstraints();
|
||||
m_rootItem->setSize_recursive(QWidgetAdapter::size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LayoutWidget::onLayoutRequest()
|
||||
{
|
||||
updateSizeConstraints();
|
||||
}
|
||||
|
||||
bool LayoutWidget::onResize(QSize newSize)
|
||||
{
|
||||
QScopedValueRollback<bool> resizeGuard(m_inResizeEvent, true); // to avoid re-entrancy
|
||||
|
||||
if (!LayoutSaver::restoreInProgress()) {
|
||||
// don't resize anything while we're restoring the layout
|
||||
setLayoutSize(newSize);
|
||||
}
|
||||
|
||||
return false; // So QWidget::resizeEvent is called
|
||||
}
|
||||
|
||||
LayoutSaver::MultiSplitter LayoutWidget::serialize() const
|
||||
{
|
||||
LayoutSaver::MultiSplitter l;
|
||||
l.layout = m_rootItem->toVariantMap();
|
||||
const Layouting::Item::List items = m_rootItem->items_recursive();
|
||||
l.frames.reserve(items.size());
|
||||
for (Layouting::Item *item : items) {
|
||||
if (!item->isContainer()) {
|
||||
if (auto frame = qobject_cast<Frame *>(item->guestAsQObject()))
|
||||
l.frames.insert(frame->id(), frame->serialize());
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
225
src/private/LayoutWidget_p.h
Normal file
225
src/private/LayoutWidget_p.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company
|
||||
<info@kdab.com> Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief A widget that supports an arbitrary number of splitters (called Separators) in any
|
||||
* combination of vertical/horizontal.
|
||||
*
|
||||
* This is a widget wrapper around the multisplitter layout (Layouting::Item)
|
||||
*
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
|
||||
#ifndef KDDOCKWIDGETS_LAYOUTWIDGET_P_H
|
||||
#define KDDOCKWIDGETS_LAYOUTWIDGET_P_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "kddockwidgets/KDDockWidgets.h"
|
||||
#include "kddockwidgets/LayoutSaver.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
namespace Layouting {
|
||||
class Item;
|
||||
class Separator;
|
||||
class Widget_qwidget;
|
||||
}
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class MainWindowBase;
|
||||
class FloatingWindow;
|
||||
class Frame;
|
||||
class DockWidgetBase;
|
||||
|
||||
/**
|
||||
* @brief The widget (QWidget or QQuickItem) which holds a layout of dock widgets.
|
||||
*
|
||||
* Usually this would simply be MultiSplitter, but we've introduced this base class to support
|
||||
* different layouts, like MDI layouts, which are very different than traditional dock widget
|
||||
* layouts.
|
||||
*
|
||||
* This class makes the bridge between the GUI world (QWidget) and Layouting::Item world.
|
||||
* It's suitable to be set as a main window central widget for instance. The actual layouting is
|
||||
* then done by the root Item.
|
||||
*/
|
||||
class DOCKS_EXPORT LayoutWidget : public LayoutGuestWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LayoutWidget(QWidgetOrQuick *parent = nullptr);
|
||||
~LayoutWidget() override;
|
||||
|
||||
bool isInMainWindow() const;
|
||||
MainWindowBase *mainWindow() const;
|
||||
FloatingWindow *floatingWindow() const;
|
||||
|
||||
/**
|
||||
* @brief returns the layout's minimum size
|
||||
* @ref setLayoutMinimumSize
|
||||
*/
|
||||
QSize layoutMinimumSize() const;
|
||||
|
||||
/**
|
||||
* @brief returns the layout's maximum size hint
|
||||
*/
|
||||
QSize layoutMaximumSizeHint() const;
|
||||
|
||||
/**
|
||||
* @brief returns the contents width.
|
||||
* Usually it's the same width as the respective parent MultiSplitter.
|
||||
*/
|
||||
int width() const
|
||||
{
|
||||
return size().width();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns the contents height.
|
||||
* Usually it's the same height as the respective parent MultiSplitter.
|
||||
*/
|
||||
int height() const
|
||||
{
|
||||
return size().height();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getter for the size
|
||||
*/
|
||||
QSize size() const;
|
||||
|
||||
/// @brief Runs some sanity checks. Returns true if everything is OK
|
||||
bool checkSanity() const;
|
||||
|
||||
/// @brief clears the layout
|
||||
void clearLayout();
|
||||
|
||||
/// @brief dumps the layout to stderr
|
||||
void dumpLayout() const;
|
||||
|
||||
/**
|
||||
* @brief setter for the contents size
|
||||
* The "contents size" is just the size() of this layout. However, since resizing
|
||||
* QWidgets is async and we need it to be sync. As sometimes adding widgets will increase
|
||||
* the MultiSplitter size (due to widget's min-size constraints).
|
||||
*/
|
||||
void setLayoutSize(QSize);
|
||||
|
||||
|
||||
/// @brief restores the dockwidget @p dw to its previous position
|
||||
void restorePlaceholder(DockWidgetBase *dw, Layouting::Item *, int tabIndex);
|
||||
|
||||
/**
|
||||
* @brief The list of items in this layout.
|
||||
*/
|
||||
const QVector<Layouting::Item *> items() const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if this layout contains the specified item.
|
||||
*/
|
||||
bool containsItem(const Layouting::Item *) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if this layout contains the specified frame.
|
||||
*/
|
||||
bool containsFrame(const Frame *) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of Item objects in this layout.
|
||||
* This includes non-visible (placeholder) Items too.
|
||||
* @sa visibleCount
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of visible Items in this layout.
|
||||
* Which is @ref count minus @ref placeholderCount
|
||||
* @sa count
|
||||
*/
|
||||
int visibleCount() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of placeholder items in this layout.
|
||||
* This is the same as @ref count minus @ref visibleCount
|
||||
* @sa count, visibleCount
|
||||
*/
|
||||
int placeholderCount() const;
|
||||
|
||||
/**
|
||||
* @brief returns the Item that holds @p frame in this layout
|
||||
*/
|
||||
Layouting::Item *itemForFrame(const Frame *frame) const;
|
||||
|
||||
/**
|
||||
* @brief Returns this list of Frame objects contained in this layout
|
||||
*/
|
||||
QList<Frame *> frames() const;
|
||||
|
||||
/// @brief Returns the list of dock widgets contained in this layout
|
||||
QVector<DockWidgetBase *> dockWidgets() const;
|
||||
|
||||
/**
|
||||
* @brief Removes an item from this MultiSplitter.
|
||||
*/
|
||||
void removeItem(Layouting::Item *item);
|
||||
|
||||
/**
|
||||
* @brief Updates the min size of this layout.
|
||||
*/
|
||||
void updateSizeConstraints();
|
||||
|
||||
virtual bool deserialize(const LayoutSaver::MultiSplitter &);
|
||||
LayoutSaver::MultiSplitter serialize() const;
|
||||
|
||||
protected:
|
||||
void setRootItem(Layouting::ItemContainer *root);
|
||||
/**
|
||||
* @brief setter for the minimum size
|
||||
* @ref minimumSize
|
||||
*/
|
||||
void setLayoutMinimumSize(QSize);
|
||||
|
||||
void onLayoutRequest() override;
|
||||
bool onResize(QSize newSize) override;
|
||||
|
||||
/**
|
||||
* @brief Removes unneeded placeholder items when adding new frames.
|
||||
*
|
||||
* A floating frame A might have a placeholder in the main window (for example to remember its
|
||||
* position on the Left), but then the user might attach it to the right, so the left
|
||||
* placeholder is no longer need. Right before adding the frame to the right we remove the left
|
||||
* placeholder, otherwise it's unrefed while we're adding causing a segfault. So what this does
|
||||
* is making the unrefing happen a bit earlier.
|
||||
*/
|
||||
void unrefOldPlaceholders(const QList<Frame *> &framesBeingAdded) const;
|
||||
|
||||
/**
|
||||
* @brief returns the frames contained in @p frameOrMultiSplitter
|
||||
* If frameOrMultiSplitter is a Frame, it returns a list of 1 element, with that frame
|
||||
* If frameOrMultiSplitter is a MultiSplitter then it returns a list of all frames it contains
|
||||
*/
|
||||
QList<Frame *> framesFrom(QWidgetOrQuick *frameOrMultiSplitter) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void visibleWidgetCountChanged(int count);
|
||||
|
||||
private:
|
||||
bool m_inResizeEvent = false;
|
||||
Layouting::ItemContainer *m_rootItem = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
115
src/private/MDILayoutWidget.cpp
Normal file
115
src/private/MDILayoutWidget.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#include "ItemFreeContainer_p.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "Config.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
MDILayoutWidget::MDILayoutWidget(QWidgetOrQuick *parent)
|
||||
: LayoutWidget(parent)
|
||||
, m_rootItem(new Layouting::ItemFreeContainer(this))
|
||||
{
|
||||
setRootItem(m_rootItem);
|
||||
}
|
||||
|
||||
MDILayoutWidget::~MDILayoutWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void MDILayoutWidget::addDockWidget(DockWidgetBase *dw, QPoint localPt, InitialOption addingOption)
|
||||
{
|
||||
if (!dw) {
|
||||
qWarning() << Q_FUNC_INFO << "Refusing to add null dock widget";
|
||||
return;
|
||||
}
|
||||
|
||||
auto frame = qobject_cast<Frame*>(dw->d->frame());
|
||||
if (itemForFrame(frame) != nullptr) {
|
||||
// Item already exists, remove it. See also comment in MultiSplitter::addWidget().
|
||||
frame->QWidgetAdapter::setParent(nullptr);
|
||||
frame->setLayoutItem(nullptr);
|
||||
}
|
||||
|
||||
Layouting::Item *newItem = new Layouting::Item(this);
|
||||
if (frame) {
|
||||
newItem->setGuestWidget(frame);
|
||||
} else {
|
||||
frame = Config::self().frameworkWidgetFactory()->createFrame(nullptr, FrameOption_None);
|
||||
frame->addWidget(dw, addingOption);
|
||||
|
||||
newItem->setGuestWidget(frame);
|
||||
}
|
||||
|
||||
Q_ASSERT(!newItem->geometry().isEmpty());
|
||||
m_rootItem->addDockWidget(newItem, localPt);
|
||||
|
||||
if (addingOption.startsHidden()) {
|
||||
delete frame;
|
||||
}
|
||||
}
|
||||
|
||||
void MDILayoutWidget::setDockWidgetGeometry(Frame *frame, QRect geometry)
|
||||
{
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
Layouting::Item *item = itemForFrame(frame);
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "Frame not found in the layout" << frame;
|
||||
return;
|
||||
}
|
||||
|
||||
item->setGeometry(geometry);
|
||||
}
|
||||
|
||||
void MDILayoutWidget::moveDockWidget(DockWidgetBase *dw, QPoint pos)
|
||||
{
|
||||
moveDockWidget(dw->d->frame(), pos);
|
||||
}
|
||||
|
||||
void MDILayoutWidget::moveDockWidget(Frame *frame, QPoint pos)
|
||||
{
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
Layouting::Item *item = itemForFrame(frame);
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "Frame not found in the layout" << frame;
|
||||
return;
|
||||
}
|
||||
|
||||
QRect geo = item->geometry();
|
||||
geo.moveTopLeft(pos);
|
||||
item->setGeometry(geo);
|
||||
}
|
||||
|
||||
void MDILayoutWidget::resizeDockWidget(DockWidgetBase *dw, QSize size)
|
||||
{
|
||||
resizeDockWidget(dw->d->frame(), size);
|
||||
}
|
||||
|
||||
void MDILayoutWidget::resizeDockWidget(Frame *frame, QSize size)
|
||||
{
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
Layouting::Item *item = itemForFrame(frame);
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "Frame not found in the layout" << frame;
|
||||
return;
|
||||
}
|
||||
|
||||
item->setSize(size.expandedTo(frame->minimumSize()));
|
||||
}
|
||||
64
src/private/MDILayoutWidget_p.h
Normal file
64
src/private/MDILayoutWidget_p.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef KDDOCKWIDGETS_MDI_LAYOUT_WIDGET_P_H
|
||||
#define KDDOCKWIDGETS_MDI_LAYOUT_WIDGET_P_H
|
||||
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "kddockwidgets/KDDockWidgets.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
|
||||
namespace Layouting {
|
||||
class ItemFreeContainer;
|
||||
}
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
/**
|
||||
* @brief The MDILayoutWidget class implements a layout suitable for MDI style docking.
|
||||
* Where dock widgets are free to be positioned in arbitrary positions, not restricted by layouting.
|
||||
*/
|
||||
class DOCKS_EXPORT MDILayoutWidget : public LayoutWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MDILayoutWidget(QWidgetOrQuick *parent = nullptr);
|
||||
~MDILayoutWidget() override;
|
||||
|
||||
/// @brief docks the dock widgets into this MDI area, at the specified position
|
||||
void addDockWidget(DockWidgetBase *dw, QPoint localPt, InitialOption addingOption);
|
||||
|
||||
/// @brief Moves a dock widget @p dw to point @p pos
|
||||
void moveDockWidget(DockWidgetBase *dw, QPoint pos);
|
||||
|
||||
/// @brief Moves a dock widget @p f to point @p pos
|
||||
/// Convenience overload.
|
||||
void moveDockWidget(Frame *f, QPoint pos);
|
||||
|
||||
/// @brief Sets the size of dock widget @p dw to @p size
|
||||
void resizeDockWidget(DockWidgetBase *dw, QSize size);
|
||||
|
||||
/// @brief Sets the size of dock widget @p f to @p size
|
||||
/// Convenience overload.
|
||||
void resizeDockWidget(Frame *f, QSize size);
|
||||
|
||||
/// @brief sets the size and position of the dock widget @p f
|
||||
void setDockWidgetGeometry(Frame *f, QRect);
|
||||
|
||||
private:
|
||||
Layouting::ItemFreeContainer *const m_rootItem;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -17,28 +17,28 @@
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
|
||||
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "../LayoutSaver_p.h"
|
||||
#include "Config.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "LayoutSaver.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "DockWidgetBase.h"
|
||||
#include "MainWindowBase.h"
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "Config.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "multisplitter/Widget.h"
|
||||
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
MultiSplitter::MultiSplitter(QWidgetOrQuick *parent)
|
||||
: LayoutGuestWidget(parent)
|
||||
: LayoutWidget(parent)
|
||||
{
|
||||
Q_ASSERT(parent);
|
||||
setRootItem(new Layouting::ItemBoxContainer(this));
|
||||
@@ -46,8 +46,6 @@ MultiSplitter::MultiSplitter(QWidgetOrQuick *parent)
|
||||
|
||||
setLayoutSize(parent->size());
|
||||
|
||||
qCDebug(creation) << "MultiSplitter";
|
||||
|
||||
// Initialize min size
|
||||
updateSizeConstraints();
|
||||
|
||||
@@ -56,59 +54,10 @@ MultiSplitter::MultiSplitter(QWidgetOrQuick *parent)
|
||||
|
||||
MultiSplitter::~MultiSplitter()
|
||||
{
|
||||
qCDebug(creation) << "~MultiSplitter" << this;
|
||||
if (m_rootItem->hostWidget()->asQObject() == this)
|
||||
delete m_rootItem;
|
||||
DockRegistry::self()->unregisterLayout(this);
|
||||
}
|
||||
|
||||
void MultiSplitter::onLayoutRequest()
|
||||
{
|
||||
updateSizeConstraints();
|
||||
}
|
||||
|
||||
bool MultiSplitter::onResize(QSize newSize)
|
||||
{
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "; new=" << newSize
|
||||
<< "; window=" << window();
|
||||
|
||||
QScopedValueRollback<bool> resizeGuard(m_inResizeEvent, true); // to avoid re-entrancy
|
||||
|
||||
if (!LayoutSaver::restoreInProgress()) {
|
||||
// don't resize anything while we're restoring the layout
|
||||
setLayoutSize(newSize);
|
||||
}
|
||||
|
||||
return false; // So QWidget::resizeEvent is called
|
||||
}
|
||||
|
||||
bool MultiSplitter::isInMainWindow() const
|
||||
{
|
||||
return mainWindow() != nullptr;
|
||||
}
|
||||
|
||||
MainWindowBase *MultiSplitter::mainWindow() const
|
||||
{
|
||||
if (auto pw = QWidgetAdapter::parentWidget()) {
|
||||
// Note that if pw is a FloatingWindow then pw->parentWidget() can be a MainWindow too, as it's parented
|
||||
if (pw->objectName() == QLatin1String("MyCentralWidget"))
|
||||
return qobject_cast<MainWindowBase*>(pw->parentWidget());
|
||||
|
||||
if (auto mw = qobject_cast<MainWindowBase*>(pw))
|
||||
return mw;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FloatingWindow *MultiSplitter::floatingWindow() const
|
||||
{
|
||||
return qobject_cast<FloatingWindow*>(QWidgetAdapter::parentWidget());
|
||||
}
|
||||
|
||||
bool MultiSplitter::validateInputs(QWidgetOrQuick *widget,
|
||||
Location location,
|
||||
const Frame *relativeToFrame, InitialOption option) const
|
||||
bool MultiSplitter::validateInputs(QWidgetOrQuick *widget, Location location,
|
||||
const Frame *relativeToFrame, InitialOption option) const
|
||||
{
|
||||
if (!widget) {
|
||||
qWarning() << Q_FUNC_INFO << "Widget is null";
|
||||
@@ -164,14 +113,6 @@ void MultiSplitter::addWidget(QWidgetOrQuick *w, Location location,
|
||||
InitialOption option)
|
||||
{
|
||||
auto frame = qobject_cast<Frame*>(w);
|
||||
qCDebug(addwidget) << Q_FUNC_INFO << w
|
||||
<< "; location=" << locationStr(location)
|
||||
<< "; relativeTo=" << relativeToWidget
|
||||
<< "; size=" << size()
|
||||
<< "; w.size=" << w->size()
|
||||
<< "; frame=" << frame
|
||||
<< "; options=" << option;
|
||||
|
||||
if (itemForFrame(frame) != nullptr) {
|
||||
// Item already exists, remove it.
|
||||
// Changing the frame parent will make the item clean itself up. It turns into a placeholder and is removed by unrefOldPlaceholders
|
||||
@@ -232,55 +173,11 @@ void MultiSplitter::addMultiSplitter(MultiSplitter *sourceMultiSplitter, Locatio
|
||||
addWidget(sourceMultiSplitter, location, relativeTo, option);
|
||||
}
|
||||
|
||||
void MultiSplitter::removeItem(Layouting::Item *item)
|
||||
{
|
||||
if (!item) {
|
||||
qWarning() << Q_FUNC_INFO << "nullptr item";
|
||||
return;
|
||||
}
|
||||
|
||||
item->parentContainer()->removeItem(item);
|
||||
}
|
||||
|
||||
bool MultiSplitter::containsItem(const Layouting::Item *item) const
|
||||
{
|
||||
return m_rootItem->contains_recursive(item);
|
||||
}
|
||||
|
||||
bool MultiSplitter::containsFrame(const Frame *frame) const
|
||||
{
|
||||
return itemForFrame(frame) != nullptr;
|
||||
}
|
||||
|
||||
int MultiSplitter::count() const
|
||||
{
|
||||
return m_rootItem->count_recursive();
|
||||
}
|
||||
|
||||
int MultiSplitter::visibleCount() const
|
||||
{
|
||||
return m_rootItem->visibleCount_recursive();
|
||||
}
|
||||
|
||||
int MultiSplitter::placeholderCount() const
|
||||
{
|
||||
return count() - visibleCount();
|
||||
}
|
||||
|
||||
QVector<Layouting::Separator*> MultiSplitter::separators() const
|
||||
{
|
||||
return m_rootItem->separators_recursive();
|
||||
}
|
||||
|
||||
void MultiSplitter::updateSizeConstraints()
|
||||
{
|
||||
const QSize newMinSize = m_rootItem->minSize();
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "Updating size constraints from" << minimumSize()
|
||||
<< "to" << newMinSize;
|
||||
|
||||
setLayoutMinimumSize(newMinSize);
|
||||
}
|
||||
|
||||
int MultiSplitter::availableLengthForOrientation(Qt::Orientation orientation) const
|
||||
{
|
||||
if (orientation == Qt::Vertical)
|
||||
@@ -294,69 +191,6 @@ QSize MultiSplitter::availableSize() const
|
||||
return m_rootItem->availableSize();
|
||||
}
|
||||
|
||||
Layouting::Item *MultiSplitter::itemForFrame(const Frame *frame) const
|
||||
{
|
||||
if (!frame)
|
||||
return nullptr;
|
||||
|
||||
return m_rootItem->itemForWidget(frame);
|
||||
}
|
||||
|
||||
DockWidgetBase::List MultiSplitter::dockWidgets() const
|
||||
{
|
||||
DockWidgetBase::List dockWidgets;
|
||||
const Frame::List frames = this->frames();
|
||||
for (Frame *frame : frames)
|
||||
dockWidgets << frame->dockWidgets();
|
||||
|
||||
return dockWidgets;
|
||||
}
|
||||
|
||||
Frame::List MultiSplitter::framesFrom(QWidgetOrQuick *frameOrMultiSplitter) const
|
||||
{
|
||||
if (auto frame = qobject_cast<Frame*>(frameOrMultiSplitter))
|
||||
return { frame };
|
||||
|
||||
if (auto msw = qobject_cast<MultiSplitter*>(frameOrMultiSplitter))
|
||||
return msw->frames();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Frame::List MultiSplitter::frames() const
|
||||
{
|
||||
const Layouting::Item::List items = m_rootItem->items_recursive();
|
||||
|
||||
Frame::List result;
|
||||
result.reserve(items.size());
|
||||
|
||||
for (Layouting::Item *item : items) {
|
||||
if (auto f = static_cast<Frame*>(item->guestAsQObject()))
|
||||
result.push_back(f);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MultiSplitter::restorePlaceholder(DockWidgetBase *dw, Layouting::Item *item, int tabIndex)
|
||||
{
|
||||
if (item->isPlaceholder()) {
|
||||
Frame *newFrame = Config::self().frameworkWidgetFactory()->createFrame(this);
|
||||
item->restore(newFrame);
|
||||
}
|
||||
|
||||
auto frame = qobject_cast<Frame*>(item->guestAsQObject());
|
||||
Q_ASSERT(frame);
|
||||
|
||||
if (tabIndex != -1 && frame->dockWidgetCount() >= tabIndex) {
|
||||
frame->insertWidget(dw, tabIndex);
|
||||
} else {
|
||||
frame->addWidget(dw);
|
||||
}
|
||||
|
||||
frame->QWidgetAdapter::setVisible(true);
|
||||
}
|
||||
|
||||
void MultiSplitter::layoutEqually()
|
||||
{
|
||||
layoutEqually(m_rootItem);
|
||||
@@ -371,75 +205,10 @@ void MultiSplitter::layoutEqually(Layouting::ItemBoxContainer *container)
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSplitter::clearLayout()
|
||||
{
|
||||
m_rootItem->clear();
|
||||
}
|
||||
|
||||
bool MultiSplitter::checkSanity() const
|
||||
{
|
||||
return m_rootItem->checkSanity();
|
||||
}
|
||||
|
||||
void MultiSplitter::unrefOldPlaceholders(const Frame::List &framesBeingAdded) const
|
||||
{
|
||||
for (Frame *frame : framesBeingAdded) {
|
||||
for (DockWidgetBase *dw : frame->dockWidgets()) {
|
||||
dw->lastPositions().removePlaceholders(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSplitter::dumpLayout() const
|
||||
{
|
||||
m_rootItem->dumpLayout();
|
||||
}
|
||||
|
||||
void MultiSplitter::setLayoutSize(QSize size)
|
||||
{
|
||||
if (size != this->size()) {
|
||||
m_rootItem->setSize_recursive(size);
|
||||
if (!m_inResizeEvent && !LayoutSaver::restoreInProgress())
|
||||
resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (sz != m_rootItem->minSize()) {
|
||||
setLayoutSize(size().expandedTo(m_rootItem->minSize())); // Increase size in case we need to
|
||||
m_rootItem->setMinSize(sz);
|
||||
}
|
||||
|
||||
qCDebug(sizing) << Q_FUNC_INFO << "minSize = " << m_rootItem->minSize();
|
||||
}
|
||||
|
||||
void MultiSplitter::setRootItem(Layouting::ItemBoxContainer *root)
|
||||
{
|
||||
delete m_rootItem;
|
||||
LayoutWidget::setRootItem(root);
|
||||
m_rootItem = root;
|
||||
connect(m_rootItem, &Layouting::ItemBoxContainer::numVisibleItemsChanged,
|
||||
this, &MultiSplitter::visibleWidgetCountChanged);
|
||||
connect(m_rootItem, &Layouting::ItemBoxContainer::minSizeChanged, this, [this] {
|
||||
setMinimumSize(layoutMinimumSize());
|
||||
});
|
||||
}
|
||||
|
||||
const Layouting::Item::List MultiSplitter::items() const
|
||||
{
|
||||
return m_rootItem->items_recursive();
|
||||
}
|
||||
|
||||
Layouting::ItemBoxContainer *MultiSplitter::rootItem() const
|
||||
@@ -467,34 +236,5 @@ QRect MultiSplitter::rectForDrop(const WindowBeingDragged *wbd, Location locatio
|
||||
bool MultiSplitter::deserialize(const LayoutSaver::MultiSplitter &l)
|
||||
{
|
||||
setRootItem(new Layouting::ItemBoxContainer(this));
|
||||
|
||||
QHash<QString, Layouting::Widget*> frames;
|
||||
for (const LayoutSaver::Frame &frame : qAsConst(l.frames)) {
|
||||
Frame *f = Frame::deserialize(frame);
|
||||
Q_ASSERT(!frame.id.isEmpty());
|
||||
frames.insert(frame.id, f);
|
||||
}
|
||||
|
||||
m_rootItem->fillFromVariantMap(l.layout, frames);
|
||||
|
||||
updateSizeConstraints();
|
||||
m_rootItem->setSize_recursive(QWidgetAdapter::size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LayoutSaver::MultiSplitter MultiSplitter::serialize() const
|
||||
{
|
||||
LayoutSaver::MultiSplitter l;
|
||||
l.layout = m_rootItem->toVariantMap();
|
||||
const Layouting::Item::List items = m_rootItem->items_recursive();
|
||||
l.frames.reserve(items.size());
|
||||
for (Layouting::Item *item : items) {
|
||||
if (!item->isContainer()) {
|
||||
if (auto frame = qobject_cast<Frame*>(item->guestAsQObject()))
|
||||
l.frames.insert(frame->id(), frame->serialize());
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
return LayoutWidget::deserialize(l);
|
||||
}
|
||||
|
||||
@@ -22,25 +22,15 @@
|
||||
#ifndef KDDOCKWIDGETS_MULTISPLITTER_P_H
|
||||
#define KDDOCKWIDGETS_MULTISPLITTER_P_H
|
||||
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "kddockwidgets/KDDockWidgets.h"
|
||||
#include "kddockwidgets/private/LayoutSaver_p.h"
|
||||
|
||||
|
||||
namespace Layouting {
|
||||
class Item;
|
||||
class Separator;
|
||||
class Widget_qwidget;
|
||||
}
|
||||
#include "kddockwidgets/QWidgetAdapter.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
|
||||
class TestDocks;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class MainWindowBase;
|
||||
class FloatingWindow;
|
||||
class Frame;
|
||||
struct WindowBeingDragged;
|
||||
|
||||
/**
|
||||
@@ -54,16 +44,12 @@ struct WindowBeingDragged;
|
||||
* It supports adding a widget to the left/top/bottom/right of the whole MultiSplitter or adding
|
||||
* relative to a single widget.
|
||||
*/
|
||||
class DOCKS_EXPORT MultiSplitter
|
||||
: public LayoutGuestWidget
|
||||
class DOCKS_EXPORT MultiSplitter : public LayoutWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MultiSplitter(QWidgetOrQuick *parent = nullptr);
|
||||
~MultiSplitter() override;
|
||||
bool isInMainWindow() const;
|
||||
MainWindowBase* mainWindow() const;
|
||||
FloatingWindow* floatingWindow() const;
|
||||
|
||||
/**
|
||||
* @brief Adds a widget to this MultiSplitter.
|
||||
@@ -82,48 +68,6 @@ public:
|
||||
Frame *relativeTo = nullptr,
|
||||
InitialOption option = DefaultSizeMode::Fair);
|
||||
|
||||
/**
|
||||
* @brief Removes an item from this MultiSplitter.
|
||||
*/
|
||||
void removeItem(Layouting::Item *item);
|
||||
|
||||
/**
|
||||
* @brief Returns true if this layout contains the specified item.
|
||||
*/
|
||||
bool containsItem(const Layouting::Item *) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if this layout contains the specified frame.
|
||||
*/
|
||||
bool containsFrame(const Frame *) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of Item objects in this layout.
|
||||
* This includes non-visible (placeholder) Items too.
|
||||
* @sa visibleCount
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of visible Items in this layout.
|
||||
* Which is @ref count minus @ref placeholderCount
|
||||
* @sa count
|
||||
*/
|
||||
int visibleCount() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of placeholder items in this layout.
|
||||
* This is the same as @ref count minus @ref visibleCount
|
||||
* @sa count, visibleCount
|
||||
*/
|
||||
int placeholderCount() const;
|
||||
|
||||
/**
|
||||
* @brief The list of items in this layout.
|
||||
*/
|
||||
const QVector<Layouting::Item*> items() const;
|
||||
|
||||
|
||||
/**
|
||||
* Called by the indicators, so they draw the drop rubber band at the correct place.
|
||||
* The rect for the rubberband when dropping a widget at the specified location.
|
||||
@@ -133,123 +77,26 @@ public:
|
||||
QRect rectForDrop(const WindowBeingDragged *wbd, KDDockWidgets::Location location,
|
||||
const Layouting::Item *relativeTo) const;
|
||||
|
||||
bool deserialize(const LayoutSaver::MultiSplitter &);
|
||||
LayoutSaver::MultiSplitter serialize() const;
|
||||
bool deserialize(const LayoutSaver::MultiSplitter &) override;
|
||||
|
||||
///@brief returns the list of separators
|
||||
QVector<Layouting::Separator*> separators() const;
|
||||
|
||||
/**
|
||||
* @brief Updates the min size of this layout.
|
||||
*/
|
||||
void updateSizeConstraints();
|
||||
|
||||
/**
|
||||
* @brief setter for the contents size
|
||||
* The "contents size" is just the size() of this layout. However, since resizing
|
||||
* QWidgets is async and we need it to be sync. As sometimes adding widgets will increase
|
||||
* the MultiSplitter size (due to widget's min-size constraints).
|
||||
*/
|
||||
void setLayoutSize(QSize);
|
||||
|
||||
/**
|
||||
* @brief returns the contents width.
|
||||
* Usually it's the same width as the respective parent MultiSplitter.
|
||||
*/
|
||||
int width() const { return size().width(); }
|
||||
|
||||
/**
|
||||
* @brief returns the contents height.
|
||||
* Usually it's the same height as the respective parent MultiSplitter.
|
||||
*/
|
||||
int height() const { return size().height(); }
|
||||
|
||||
/**
|
||||
* @brief returns the layout's minimum size
|
||||
* @ref setLayoutMinimumSize
|
||||
*/
|
||||
QSize layoutMinimumSize() const;
|
||||
|
||||
/**
|
||||
* @brief returns the layout's maximum size hint
|
||||
*/
|
||||
QSize layoutMaximumSizeHint() const;
|
||||
|
||||
/**
|
||||
* @brief getter for the size
|
||||
*/
|
||||
QSize size() const;
|
||||
|
||||
/// @brief Runs some sanity checks. Returns true if everything is OK
|
||||
bool checkSanity() const;
|
||||
|
||||
/// @brief dumps the layout to stderr
|
||||
void dumpLayout() const;
|
||||
|
||||
/**
|
||||
* @brief returns the Item that holds @p frame in this layout
|
||||
*/
|
||||
Layouting::Item *itemForFrame(const Frame *frame) const;
|
||||
|
||||
/**
|
||||
* @brief Returns this list of Frame objects contained in this layout
|
||||
*/
|
||||
QList<Frame*> frames() const;
|
||||
|
||||
/// @brief Returns the list of dock widgets contained in this layout
|
||||
QVector<DockWidgetBase*> dockWidgets() const;
|
||||
|
||||
/// @brief restores the dockwidget @p dw to its previous position
|
||||
void restorePlaceholder(DockWidgetBase *dw, Layouting::Item *, int tabIndex);
|
||||
|
||||
/// @brief See docs for MainWindowBase::layoutEqually()
|
||||
void layoutEqually();
|
||||
|
||||
/// @brief overload that just resizes widgets within a sub-tree
|
||||
void layoutEqually(Layouting::ItemBoxContainer *);
|
||||
|
||||
/// @brief clears the layout
|
||||
void clearLayout();
|
||||
|
||||
Q_SIGNALS:
|
||||
void visibleWidgetCountChanged(int count);
|
||||
|
||||
protected:
|
||||
void onLayoutRequest() override;
|
||||
bool onResize(QSize newSize) override;
|
||||
private:
|
||||
bool m_inResizeEvent = false;
|
||||
|
||||
friend class ::TestDocks;
|
||||
|
||||
/**
|
||||
* @brief returns the frames contained in @p frameOrMultiSplitter
|
||||
* If frameOrMultiSplitter is a Frame, it returns a list of 1 element, with that frame
|
||||
* If frameOrMultiSplitter is a MultiSplitter then it returns a list of all frames it contains
|
||||
*/
|
||||
QList<Frame*> framesFrom(QWidgetOrQuick *frameOrMultiSplitter) const;
|
||||
|
||||
Layouting::ItemBoxContainer *rootItem() const;
|
||||
|
||||
// For debug/hardening
|
||||
bool validateInputs(QWidgetOrQuick *widget, KDDockWidgets::Location location,
|
||||
const Frame *relativeToFrame, InitialOption option) const;
|
||||
|
||||
/**
|
||||
* @brief Removes unneeded placeholder items when adding new frames.
|
||||
*
|
||||
* A floating frame A might have a placeholder in the main window (for example to remember its position on the Left),
|
||||
* but then the user might attach it to the right, so the left placeholder is no longer need.
|
||||
* Right before adding the frame to the right we remove the left placeholder, otherwise it's unrefed while we're adding
|
||||
* causing a segfault. So what this does is making the unrefing happen a bit earlier.
|
||||
*/
|
||||
void unrefOldPlaceholders(const QList<Frame*> &framesBeingAdded) const;
|
||||
|
||||
/**
|
||||
* @brief setter for the minimum size
|
||||
* @ref minimumSize
|
||||
*/
|
||||
void setLayoutMinimumSize(QSize);
|
||||
|
||||
void setRootItem(Layouting::ItemBoxContainer *);
|
||||
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
* @author Sérgio Martins \<sergio.martins@kdab.com\>
|
||||
*/
|
||||
|
||||
#include "Position_p.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "LayoutWidget_p.h"
|
||||
#include "Position_p.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -87,7 +88,7 @@ void Position::removePlaceholders()
|
||||
m_placeholders.clear();
|
||||
}
|
||||
|
||||
void Position::removePlaceholders(const MultiSplitter *ms)
|
||||
void Position::removePlaceholders(const LayoutWidget *ms)
|
||||
{
|
||||
m_placeholders.erase(std::remove_if(m_placeholders.begin(), m_placeholders.end(), [ms] (const std::unique_ptr<ItemRef> &itemref) {
|
||||
return itemref->item->hostWidget() == *ms;
|
||||
@@ -119,17 +120,20 @@ void Position::removePlaceholder(Layouting::Item *placeholder)
|
||||
void Position::deserialize(const LayoutSaver::Position &lp)
|
||||
{
|
||||
for (const auto &placeholder : qAsConst(lp.placeholders)) {
|
||||
MultiSplitter *layout;
|
||||
LayoutWidget *layout;
|
||||
int itemIndex = placeholder.itemIndex;
|
||||
if (placeholder.isFloatingWindow) {
|
||||
const int index = placeholder.indexOfFloatingWindow;
|
||||
if (index == -1) {
|
||||
continue; // Skip
|
||||
} else {
|
||||
const auto floatingWindows = DockRegistry::self()->floatingWindows();
|
||||
if (index >= 0 && index < floatingWindows.size()) {
|
||||
FloatingWindow *fw = floatingWindows.at(index);
|
||||
layout = fw->multiSplitter();
|
||||
auto serializedFw = LayoutSaver::Layout::s_currentLayoutBeingRestored->floatingWindowForIndex(index);
|
||||
if (serializedFw.isValid()) {
|
||||
if (FloatingWindow *fw = serializedFw.floatingWindowInstance) {
|
||||
layout = fw->layoutWidget();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Invalid floating window position to restore" << index;
|
||||
continue;
|
||||
@@ -137,7 +141,7 @@ void Position::deserialize(const LayoutSaver::Position &lp)
|
||||
}
|
||||
} else {
|
||||
MainWindowBase *mainWindow = DockRegistry::self()->mainWindowByName(placeholder.mainWindowUniqueName);
|
||||
layout = mainWindow->multiSplitter();
|
||||
layout = mainWindow->layoutWidget();
|
||||
}
|
||||
|
||||
const Layouting::Item::List &items = layout->items();
|
||||
@@ -162,7 +166,7 @@ LayoutSaver::Position Position::serialize() const
|
||||
LayoutSaver::Placeholder p;
|
||||
|
||||
Layouting::Item *item = itemRef->item;
|
||||
MultiSplitter *layout = DockRegistry::self()->layoutForItem(item);
|
||||
LayoutWidget *layout = DockRegistry::self()->layoutForItem(item);
|
||||
const auto itemIndex = layout->items().indexOf(item);
|
||||
|
||||
auto fw = layout->floatingWindow();
|
||||
@@ -202,3 +206,18 @@ ItemRef::~ItemRef()
|
||||
item->unref();
|
||||
}
|
||||
}
|
||||
|
||||
LayoutSaver::Position LastPositions::serialize()
|
||||
{
|
||||
LayoutSaver::Position result = lastPosition->serialize();
|
||||
result.lastFloatingGeometry = lastFloatingGeometry();
|
||||
result.lastOverlayedGeometries = m_lastOverlayedGeometries;
|
||||
return result;
|
||||
}
|
||||
|
||||
void LastPositions::deserialize(const LayoutSaver::Position &p)
|
||||
{
|
||||
m_lastFloatingGeometry = p.lastFloatingGeometry;
|
||||
m_lastOverlayedGeometries = p.lastOverlayedGeometries;
|
||||
lastPosition->deserialize(p);
|
||||
}
|
||||
|
||||
@@ -18,13 +18,15 @@
|
||||
#ifndef KDDOCKWIDGETS_POSITION_P_H
|
||||
#define KDDOCKWIDGETS_POSITION_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
|
||||
#include "Logging_p.h"
|
||||
#include "LayoutSaver_p.h"
|
||||
#include "LayoutSaver.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
|
||||
#include <QScopedValueRollback>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -34,7 +36,7 @@ class Item;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class MultiSplitter;
|
||||
class LayoutWidget;
|
||||
|
||||
// Just a RAII class so we don't forget to unref
|
||||
struct ItemRef
|
||||
@@ -103,7 +105,7 @@ public:
|
||||
const std::vector<std::unique_ptr<ItemRef>>& placeholders() const { return m_placeholders; }
|
||||
|
||||
///@brief Removes the placeholders that belong to this multisplitter
|
||||
void removePlaceholders(const MultiSplitter *);
|
||||
void removePlaceholders(const LayoutWidget *);
|
||||
|
||||
///@brief Removes the placeholders that reference a FloatingWindow
|
||||
void removeNonMainWindowPlaceholders();
|
||||
@@ -143,19 +145,19 @@ struct LastPositions
|
||||
return m_lastFloatingGeometry;
|
||||
}
|
||||
|
||||
LayoutSaver::Position serialize()
|
||||
QRect lastOverlayedGeometry(SideBarLocation loc) const
|
||||
{
|
||||
LayoutSaver::Position result = lastPosition->serialize();
|
||||
result.lastFloatingGeometry = lastFloatingGeometry();
|
||||
return result;
|
||||
return m_lastOverlayedGeometries.value(loc);
|
||||
}
|
||||
|
||||
void deserialize(const LayoutSaver::Position &p)
|
||||
void setLastOverlayedGeometry(SideBarLocation loc, QRect rect)
|
||||
{
|
||||
m_lastFloatingGeometry = p.lastFloatingGeometry;
|
||||
lastPosition->deserialize(p);
|
||||
m_lastOverlayedGeometries[loc] = rect;
|
||||
}
|
||||
|
||||
LayoutSaver::Position serialize();
|
||||
void deserialize(const LayoutSaver::Position &p);
|
||||
|
||||
Layouting::Item* lastItem() const {
|
||||
return lastPosition->layoutItem();
|
||||
}
|
||||
@@ -174,7 +176,8 @@ struct LastPositions
|
||||
lastPosition->removePlaceholders();
|
||||
}
|
||||
|
||||
void removePlaceholders(const MultiSplitter *hostWidget) const {
|
||||
void removePlaceholders(const LayoutWidget *hostWidget) const
|
||||
{
|
||||
lastPosition->removePlaceholders(hostWidget);
|
||||
}
|
||||
|
||||
@@ -184,6 +187,7 @@ struct LastPositions
|
||||
|
||||
private:
|
||||
QRect m_lastFloatingGeometry;
|
||||
QHash<SideBarLocation, QRect> m_lastOverlayedGeometries;
|
||||
|
||||
friend inline QDebug operator<<(QDebug d, const KDDockWidgets::LastPositions &);
|
||||
Position::Ptr lastPosition = std::make_shared<Position>();
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
#ifndef KD_SIDEBAR_P_H
|
||||
#define KD_SIDEBAR_P_H
|
||||
|
||||
#include "docks_export.h"
|
||||
#include "kddockwidgets/docks_export.h"
|
||||
|
||||
#include "KDDockWidgets.h"
|
||||
#include "QWidgetAdapter.h"
|
||||
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
*/
|
||||
|
||||
#include "TabWidget_p.h"
|
||||
#include "Config.h"
|
||||
#include "DockWidgetBase_p.h"
|
||||
#include "DragController_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "Frame_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "Config.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
#ifdef QT_WIDGETS_LIB
|
||||
# include <QTabWidget>
|
||||
@@ -93,6 +94,12 @@ std::unique_ptr<WindowBeingDragged> TabBar::makeWindow()
|
||||
return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(floatingWindow, draggable));
|
||||
}
|
||||
|
||||
bool TabBar::isWindow() const
|
||||
{
|
||||
// Same semantics as tab widget, no need to duplicate logic
|
||||
return m_tabWidget->isWindow();
|
||||
}
|
||||
|
||||
void TabBar::onMousePress(QPoint localPos)
|
||||
{
|
||||
m_lastPressedDockWidget = dockWidgetAt(localPos);
|
||||
@@ -130,6 +137,12 @@ DockWidgetBase *TabBar::singleDockWidget() const
|
||||
return m_tabWidget->singleDockWidget();
|
||||
}
|
||||
|
||||
bool TabBar::isMDI() const
|
||||
{
|
||||
Frame *f = frame();
|
||||
return f && f->isMDI();
|
||||
}
|
||||
|
||||
Frame *TabBar::frame() const
|
||||
{
|
||||
return m_tabWidget->frame();
|
||||
@@ -172,7 +185,7 @@ bool TabWidget::insertDockWidget(DockWidgetBase *dock, int index)
|
||||
return false;
|
||||
}
|
||||
|
||||
QPointer<Frame> oldFrame = dock->frame();
|
||||
QPointer<Frame> oldFrame = dock->d->frame();
|
||||
insertDockWidget(index, dock, dock->icon(DockWidgetBase::IconPlace::TabBar), dock->title());
|
||||
setCurrentDockWidget(index);
|
||||
|
||||
@@ -224,12 +237,22 @@ std::unique_ptr<WindowBeingDragged> TabWidget::makeWindow()
|
||||
|
||||
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(m_frame);
|
||||
r.moveTopLeft(globalPoint);
|
||||
floatingWindow->setSuggestedGeometry(r);
|
||||
floatingWindow->setSuggestedGeometry(r, SuggestedGeometryHint_GeometryIsFromDocked);
|
||||
floatingWindow->show();
|
||||
|
||||
return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(floatingWindow, this));
|
||||
}
|
||||
|
||||
bool TabWidget::isWindow() const
|
||||
{
|
||||
if (auto floatingWindow = qobject_cast<FloatingWindow*>(asWidget()->window())) {
|
||||
// Case of dragging via the tab widget when the title bar is hidden
|
||||
return floatingWindow->hasSingleFrame();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DockWidgetBase *TabWidget::singleDockWidget() const
|
||||
{
|
||||
if (m_frame->hasSingleDockWidget())
|
||||
@@ -238,6 +261,11 @@ DockWidgetBase *TabWidget::singleDockWidget() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TabWidget::isMDI() const
|
||||
{
|
||||
return m_frame && m_frame->isMDI();
|
||||
}
|
||||
|
||||
void TabWidget::onTabInserted()
|
||||
{
|
||||
m_frame->onDockWidgetCountChanged();
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
|
||||
// Draggable
|
||||
std::unique_ptr<WindowBeingDragged> makeWindow() override;
|
||||
bool isWindow() const override;
|
||||
|
||||
void onMousePress(QPoint localPos);
|
||||
void onMouseDoubleClick(QPoint localPos);
|
||||
@@ -80,8 +81,14 @@ public:
|
||||
|
||||
DockWidgetBase *singleDockWidget() const override;
|
||||
|
||||
/// @reimp
|
||||
bool isMDI() const override;
|
||||
|
||||
Frame *frame() const;
|
||||
|
||||
/// Like QTabBar::moveTab(from, to)
|
||||
virtual void moveTabTo(int from, int to) = 0;
|
||||
|
||||
private:
|
||||
TabWidget *const m_tabWidget;
|
||||
QPointer<DockWidgetBase> m_lastPressedDockWidget = nullptr;
|
||||
@@ -109,7 +116,7 @@ public:
|
||||
/**
|
||||
* @brief Returns the index of the dock widget, or -1 if it doesn't exist
|
||||
*/
|
||||
virtual int indexOfDockWidget(DockWidgetBase *) const = 0;
|
||||
virtual int indexOfDockWidget(const DockWidgetBase *) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Sets the current dock widget index
|
||||
@@ -169,6 +176,10 @@ public:
|
||||
// Draggable interface
|
||||
std::unique_ptr<WindowBeingDragged> makeWindow() override;
|
||||
DockWidgetBase *singleDockWidget() const override;
|
||||
bool isWindow() const override;
|
||||
|
||||
/// @reimp
|
||||
bool isMDI() const override;
|
||||
|
||||
//Q_SIGNALS: // Not a OQbject
|
||||
virtual void currentTabChanged(int index) = 0;
|
||||
|
||||
@@ -51,10 +51,7 @@ TitleBar::TitleBar(FloatingWindow *parent)
|
||||
, m_floatingWindow(parent)
|
||||
, m_supportsAutoHide(Config::self().flags() & Config::Flag_AutoHideSupport)
|
||||
{
|
||||
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateCloseButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateFloatButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateMaximizeButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateMinimizeButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateButtons);
|
||||
connect(m_floatingWindow, &FloatingWindow::windowStateChanged, this, &TitleBar::updateMaximizeButton);
|
||||
connect(m_floatingWindow, &FloatingWindow::activatedChanged , this, &TitleBar::isFocusedChanged);
|
||||
init();
|
||||
@@ -63,14 +60,14 @@ TitleBar::TitleBar(FloatingWindow *parent)
|
||||
|
||||
void TitleBar::init()
|
||||
{
|
||||
qCDebug(creation) << "TitleBar" << this;
|
||||
setFixedHeight(30);
|
||||
setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
|
||||
|
||||
connect(this, &TitleBar::isFocusedChanged, this, [this] {
|
||||
// repaint
|
||||
update();
|
||||
});
|
||||
updateCloseButton();
|
||||
updateFloatButton();
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
TitleBar::~TitleBar()
|
||||
@@ -91,6 +88,35 @@ bool TitleBar::onDoubleClicked()
|
||||
return false;
|
||||
}
|
||||
|
||||
MainWindowBase *TitleBar::mainWindow() const
|
||||
{
|
||||
if (m_floatingWindow)
|
||||
return nullptr;
|
||||
|
||||
if (m_frame)
|
||||
return m_frame->mainWindow();
|
||||
|
||||
qWarning() << Q_FUNC_INFO << "null frame and null floating window";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TitleBar::isMDI() const
|
||||
{
|
||||
if (auto mw = mainWindow())
|
||||
return mw->isMDI();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TitleBar::updateButtons()
|
||||
{
|
||||
updateCloseButton();
|
||||
updateFloatButton();
|
||||
updateMaximizeButton();
|
||||
updateMinimizeButton();
|
||||
updateAutoHideButton();
|
||||
}
|
||||
|
||||
void TitleBar::updateCloseButton()
|
||||
{
|
||||
|
||||
@@ -172,8 +198,9 @@ std::unique_ptr<WindowBeingDragged> TitleBar::makeWindow()
|
||||
if (!isVisible() && window()->isVisible()) {
|
||||
qWarning() << "TitleBar::makeWindow shouldn't be called on invisible title bar"
|
||||
<< this << window()->isVisible();
|
||||
|
||||
if (m_floatingWindow) {
|
||||
if (m_frame) {
|
||||
qWarning() << "this=" << this << "; actual=" << m_frame->actualTitleBar();
|
||||
} else if (m_floatingWindow) {
|
||||
qWarning() << "Has floating window with titlebar=" << m_floatingWindow->titleBar()
|
||||
<< "; fw->isVisible=" << m_floatingWindow->isVisible();
|
||||
}
|
||||
@@ -187,7 +214,6 @@ std::unique_ptr<WindowBeingDragged> TitleBar::makeWindow()
|
||||
return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(m_floatingWindow, this));
|
||||
}
|
||||
|
||||
qCDebug(hovering) << "TitleBar::makeWindow: isFloating=" << floatingWindow() << "; isTheOnlyFrame=" << m_frame->isTheOnlyFrame() << "; frame=" << m_frame;
|
||||
if (FloatingWindow *fw = QWidgetAdapter::floatingWindow()) { // Already floating
|
||||
if (m_frame->isTheOnlyFrame()) { // We dont' detach. This one drags the entire window instead.
|
||||
qCDebug(hovering) << "TitleBar::makeWindow no detach needed";
|
||||
@@ -196,13 +222,11 @@ std::unique_ptr<WindowBeingDragged> TitleBar::makeWindow()
|
||||
}
|
||||
|
||||
QRect r = m_frame->QWidgetAdapter::geometry();
|
||||
qCDebug(hovering) << "TitleBar::makeWindow original geometry" << r;
|
||||
r.moveTopLeft(m_frame->mapToGlobal(QPoint(0, 0)));
|
||||
|
||||
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(m_frame);
|
||||
floatingWindow->setSuggestedGeometry(r);
|
||||
floatingWindow->setSuggestedGeometry(r, SuggestedGeometryHint_GeometryIsFromDocked);
|
||||
floatingWindow->show();
|
||||
qCDebug(hovering) << "TitleBar::makeWindow setting geometry" << r << "actual=" << floatingWindow->geometry();
|
||||
|
||||
auto draggable = KDDockWidgets::usesNativeTitleBar() ? static_cast<Draggable*>(floatingWindow)
|
||||
: static_cast<Draggable*>(this);
|
||||
@@ -284,16 +308,40 @@ QIcon TitleBar::icon() const
|
||||
|
||||
void TitleBar::onCloseClicked()
|
||||
{
|
||||
const bool closeOnlyCurrentTab = Config::self().flags() & Config::Flag_CloseOnlyCurrentTab;
|
||||
|
||||
if (m_frame) {
|
||||
if (m_frame->isTheOnlyFrame() && !m_frame->isInMainWindow()) {
|
||||
m_frame->window()->close();
|
||||
if (closeOnlyCurrentTab) {
|
||||
if (DockWidgetBase *dw = m_frame->currentDockWidget()) {
|
||||
dw->close();
|
||||
} else {
|
||||
// Doesn't happen
|
||||
qWarning() << Q_FUNC_INFO << "Frame with no dock widgets";
|
||||
}
|
||||
} else {
|
||||
m_frame->close();
|
||||
if (m_frame->isTheOnlyFrame() && !m_frame->isInMainWindow()) {
|
||||
m_frame->window()->close();
|
||||
} else {
|
||||
m_frame->close();
|
||||
}
|
||||
}
|
||||
} else if (m_floatingWindow) {
|
||||
|
||||
if (closeOnlyCurrentTab) {
|
||||
if (Frame *f = m_floatingWindow->singleFrame()) {
|
||||
if (DockWidgetBase *dw = f->currentDockWidget()) {
|
||||
dw->close();
|
||||
} else {
|
||||
// Doesn't happen
|
||||
qWarning() << Q_FUNC_INFO << "Frame with no dock widgets";
|
||||
}
|
||||
} else {
|
||||
m_floatingWindow->close();
|
||||
}
|
||||
} else {
|
||||
m_floatingWindow->close();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_floatingWindow)
|
||||
m_floatingWindow->close();
|
||||
}
|
||||
|
||||
bool TitleBar::isFloating() const
|
||||
@@ -419,3 +467,8 @@ void TitleBar::updateFloatButton()
|
||||
setFloatButtonToolTip(floatingWindow() ? tr("Dock window") : tr("Undock window"));
|
||||
setFloatButtonVisible(supportsFloatingButton());
|
||||
}
|
||||
|
||||
bool TitleBar::isWindow() const
|
||||
{
|
||||
return m_floatingWindow != nullptr;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user