Compare commits
304 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f696ea36a | ||
|
|
ce1e8c8beb | ||
|
|
98ebdbea50 | ||
|
|
418d0740d2 | ||
|
|
50c3066eaa | ||
|
|
29ebc83b35 | ||
|
|
03bd4a4505 | ||
|
|
407af06a4a | ||
|
|
9af9e43a5d | ||
|
|
4c928071af | ||
|
|
ea03b988e0 | ||
|
|
e1044c3e91 | ||
|
|
8057d25f35 | ||
|
|
592193fc91 | ||
|
|
5cf4aa77d8 | ||
|
|
616e50c3f5 | ||
|
|
1de42a9766 | ||
|
|
f07fcddd78 | ||
|
|
225ab943bb | ||
|
|
3fe31ca62d | ||
|
|
d1f17e60f7 | ||
|
|
8f78e608d1 | ||
|
|
a5e8011222 | ||
|
|
0305d8a221 | ||
|
|
25e8d8691f | ||
|
|
084c5c5995 | ||
|
|
65c080ae8e | ||
|
|
f9927cef29 | ||
|
|
5778dfe929 | ||
|
|
c33c09eab1 | ||
|
|
2150ebf45e | ||
|
|
6021ee8094 | ||
|
|
eebb2a6297 | ||
|
|
0fb1363b1a | ||
|
|
2ca03cc56d | ||
|
|
4a2768015c | ||
|
|
861ce67725 | ||
|
|
c530a4a4ec | ||
|
|
2378f46067 | ||
|
|
ea707369a0 | ||
|
|
7640e9bdcf | ||
|
|
4a0266bc76 | ||
|
|
6d1f97649e | ||
|
|
2af4b1f75c | ||
|
|
c0cde1e31e | ||
|
|
ee809da7a7 | ||
|
|
a253e4a0b5 | ||
|
|
779c4b928c | ||
|
|
056f04d408 | ||
|
|
e085a29484 | ||
|
|
ffd35cbce3 | ||
|
|
8c1f065f3f | ||
|
|
5af6b4e324 | ||
|
|
b47a777f5c | ||
|
|
5b3a0a28df | ||
|
|
02143eac71 | ||
|
|
5e230d8874 | ||
|
|
a45a035bb3 | ||
|
|
05f8ce15a2 | ||
|
|
45af8867b2 | ||
|
|
8e522ce311 | ||
|
|
178603e3ba | ||
|
|
552cee514d | ||
|
|
4105f70089 | ||
|
|
0bd34a5a6e | ||
|
|
a5dd566b37 | ||
|
|
1724f7f5ec | ||
|
|
6cd09addae | ||
|
|
93382350db | ||
|
|
db90e5415f | ||
|
|
9679fd67cc | ||
|
|
c84c98f49a | ||
|
|
716acd5f68 | ||
|
|
e782b4813b | ||
|
|
b27a24b3c4 | ||
|
|
18c65cdf34 | ||
|
|
e049cb0353 | ||
|
|
8d42e7777d | ||
|
|
e682ab8ea5 | ||
|
|
c6ff7f5230 | ||
|
|
309fe1a14a | ||
|
|
6b45274686 | ||
|
|
0f72fabe67 | ||
|
|
d3ad17d2c6 | ||
|
|
a8e0f1904f | ||
|
|
2ee7deb6d5 | ||
|
|
2e88d8651e | ||
|
|
232b6b9a61 | ||
|
|
5978aaaedc | ||
|
|
3332f6050e | ||
|
|
a1de28c969 | ||
|
|
8af53b4199 | ||
|
|
bddf4c417d | ||
|
|
e345773cfc | ||
|
|
c1816bf507 | ||
|
|
4f97e07eb6 | ||
|
|
2fe542c3ef | ||
|
|
07f9c6d016 | ||
|
|
8ea7c265a7 | ||
|
|
3cd12ce1d3 | ||
|
|
1be8f2861d | ||
|
|
e15af4101a | ||
|
|
4504457da2 | ||
|
|
f497944d2c | ||
|
|
aee9fb1c95 | ||
|
|
316d9a00b5 | ||
|
|
b353c210ee | ||
|
|
490e853435 | ||
|
|
7393addf64 | ||
|
|
a2b9650469 | ||
|
|
ca39ab0b44 | ||
|
|
ae997d3d75 | ||
|
|
c48cf3875d | ||
|
|
46fb18fc58 | ||
|
|
8da6904dcd | ||
|
|
2a51359159 | ||
|
|
ec48140309 | ||
|
|
fe64f407c0 | ||
|
|
136d6d966c | ||
|
|
05ff005613 | ||
|
|
3ff154aff1 | ||
|
|
de645b3cca | ||
|
|
f6174faebb | ||
|
|
0d3ec46095 | ||
|
|
53fed8b765 | ||
|
|
5752bfb58b | ||
|
|
5378d90ba7 | ||
|
|
ae96bbc0a0 | ||
|
|
c10ff7c688 | ||
|
|
d2fb1579a5 | ||
|
|
156cc71040 | ||
|
|
909c189d7f | ||
|
|
50c529b77f | ||
|
|
84b501205a | ||
|
|
664a1674ab | ||
|
|
0c5ef5e158 | ||
|
|
b776fc24a6 | ||
|
|
c5e7104413 | ||
|
|
2c7764ecf7 | ||
|
|
bed99eacc2 | ||
|
|
dae677e479 | ||
|
|
a05078c947 | ||
|
|
3fcf05fb29 | ||
|
|
cdca8c2ac0 | ||
|
|
53ec8b896a | ||
|
|
6e6c1512a6 | ||
|
|
8e0ea57319 | ||
|
|
9bd55cc15a | ||
|
|
c8d4487a95 | ||
|
|
12b0182337 | ||
|
|
a2b07fd97f | ||
|
|
078905181e | ||
|
|
7c9ed9b624 | ||
|
|
ac164c3a97 | ||
|
|
2b7232c9b3 | ||
|
|
6cc7d79832 | ||
|
|
0b88843d76 | ||
|
|
554f26a614 | ||
|
|
10fbb6f302 | ||
|
|
bf27207dd9 | ||
|
|
97f02d39e6 | ||
|
|
64231d037d | ||
|
|
6eb869014e | ||
|
|
a564ca5ce5 | ||
|
|
365b989364 | ||
|
|
a3baf7dcf6 | ||
|
|
538e690c22 | ||
|
|
b1309da89a | ||
|
|
d2f751ef87 | ||
|
|
35c1b04c58 | ||
|
|
0de1a9ccae | ||
|
|
c45327aafd | ||
|
|
8853c751d6 | ||
|
|
e978a32a09 | ||
|
|
ca5683f5bf | ||
|
|
c630a59afe | ||
|
|
b9b8ff9c76 | ||
|
|
e2c5204d00 | ||
|
|
5ee94d7602 | ||
|
|
69894f3f88 | ||
|
|
641946bff5 | ||
|
|
27dd7a1b75 | ||
|
|
5425f2b9e1 | ||
|
|
4320e350c8 | ||
|
|
8351aa11e7 | ||
|
|
e98fd5bcb3 | ||
|
|
a012af2aac | ||
|
|
df285dd385 | ||
|
|
a6ed4354a9 | ||
|
|
1fccb943fe | ||
|
|
7bd3765fa7 | ||
|
|
9b56ca08e1 | ||
|
|
49a7682e74 | ||
|
|
e25bf2eac2 | ||
|
|
f7c8384b73 | ||
|
|
9bd06401d9 | ||
|
|
b44a7e75ca | ||
|
|
c9645ef85b | ||
|
|
fd09a681c4 | ||
|
|
e113790bbe | ||
|
|
957dce5d1f | ||
|
|
e352ce559b | ||
|
|
0c3ef64d3e | ||
|
|
f72e2ce058 | ||
|
|
befdcce343 | ||
|
|
6fc8964ffc | ||
|
|
6cb1f33451 | ||
|
|
ee616c2541 | ||
|
|
7dd2a3c83c | ||
|
|
9db502e652 | ||
|
|
1ad6caeb8a | ||
|
|
4dde545c8f | ||
|
|
b7a5918974 | ||
|
|
ddfa6c2a43 | ||
|
|
275520ae29 | ||
|
|
1078387f5d | ||
|
|
c33dddbd47 | ||
|
|
2570a880af | ||
|
|
40a8d9e6b4 | ||
|
|
9af6622466 | ||
|
|
4fa89374c4 | ||
|
|
1aaa56ef29 | ||
|
|
d298a47bda | ||
|
|
146b65206a | ||
|
|
616ad9f86e | ||
|
|
aa9762718c | ||
|
|
f26bee6677 | ||
|
|
fb18de4868 | ||
|
|
e204e10113 | ||
|
|
a06a14d6cd | ||
|
|
88d4bea2c1 | ||
|
|
b8ad2f7577 | ||
|
|
32e5d599f7 | ||
|
|
48382ccd82 | ||
|
|
e37e4fdf57 | ||
|
|
c9a97534a8 | ||
|
|
8f54dd2a82 | ||
|
|
c0d6f959ec | ||
|
|
8570139cd1 | ||
|
|
b38919e909 | ||
|
|
b19cc98c84 | ||
|
|
f3f5b668e5 | ||
|
|
82d15fbe29 | ||
|
|
01533a9f85 | ||
|
|
fb9f1d851b | ||
|
|
6fb80fdeb7 | ||
|
|
e94cf9bcb7 | ||
|
|
da0ec6dd4b | ||
|
|
80efed693e | ||
|
|
653f475e72 | ||
|
|
87e3777e37 | ||
|
|
71f66ea6dc | ||
|
|
0b3f419c80 | ||
|
|
f69af82a49 | ||
|
|
854f542164 | ||
|
|
b9265fccec | ||
|
|
b3a272110a | ||
|
|
316e5324ad | ||
|
|
6843703484 | ||
|
|
115a9a5b3d | ||
|
|
a4838a41ac | ||
|
|
74b9d35c7b | ||
|
|
c973482b2b | ||
|
|
188624440b | ||
|
|
72ec61a043 | ||
|
|
0ac19ebdfb | ||
|
|
bc6ffcc02c | ||
|
|
a9246f7ce4 | ||
|
|
3f5697554a | ||
|
|
5e6c82b68d | ||
|
|
268f8655a1 | ||
|
|
1dfabb3bef | ||
|
|
6617cf6f19 | ||
|
|
81523b0346 | ||
|
|
927be9a7d9 | ||
|
|
ada3d6b3b5 | ||
|
|
30bbd26d0a | ||
|
|
8637c89a6b | ||
|
|
11e5f9c95a | ||
|
|
9bfb3fbea1 | ||
|
|
9c95e34df5 | ||
|
|
ceebda7431 | ||
|
|
75288af88c | ||
|
|
7c67d71f68 | ||
|
|
548dfb363a | ||
|
|
9fec2bd515 | ||
|
|
fc04aa2411 | ||
|
|
c3a5e3ef21 | ||
|
|
0e85431405 | ||
|
|
b3b6d20d96 | ||
|
|
272bbe275e | ||
|
|
496aec211e | ||
|
|
b9b72df9d4 | ||
|
|
fcb1846bf5 | ||
|
|
9f1b2c122a | ||
|
|
6ec38b48ef | ||
|
|
b93e723a83 | ||
|
|
1a47918bdb | ||
|
|
ff9d965726 | ||
|
|
77d2cebe39 | ||
|
|
5d380708e1 | ||
|
|
aa7b36dbd1 | ||
|
|
c9123c3640 | ||
|
|
67199a81f4 |
160
.appveyor.yml
Normal file
@@ -0,0 +1,160 @@
|
||||
version: '2.3.2.{build}'
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
image: Visual Studio 2015
|
||||
clone_depth: 1
|
||||
environment:
|
||||
global:
|
||||
# Appveyor doesn't have Qt 12 yet
|
||||
LatestLTSQtVersion: 5.9
|
||||
LatestQtVersion: 5.11
|
||||
matrix:
|
||||
# Latest version of Qt, dll, 64bit, MSVC 2015, qmake
|
||||
- QT5: C:\Qt\%LatestQtVersion%\msvc2015_64
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: amd64
|
||||
use_mingw: "false"
|
||||
use_static: "false"
|
||||
use_cmake: "false"
|
||||
# 32 bit builds
|
||||
# MSVC 2015 builds
|
||||
# Dynamic Library builds
|
||||
# LTS version of Qt, dll, 32bit, MSVC 2015, qmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: x86
|
||||
use_mingw: "false"
|
||||
use_static: "false"
|
||||
use_cmake: "false"
|
||||
# LTS version of Qt, dll, 32bit, MSVC 2015, cmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: x86
|
||||
use_mingw: "false"
|
||||
use_static: "false"
|
||||
use_cmake: "true"
|
||||
# end Dynamic Library builds
|
||||
# Static Library builds
|
||||
# LTS version of Qt, static, 32bit, MSVC 2015, qmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: x86
|
||||
use_mingw: "false"
|
||||
use_static: "true"
|
||||
use_cmake: "false"
|
||||
# LTS version of Qt, static, 32bit, MSVC 2015, cmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: x86
|
||||
use_mingw: "false"
|
||||
use_static: "true"
|
||||
use_cmake: "true"
|
||||
# end Static Library builds
|
||||
# end MSVC 2015 builds
|
||||
# MinGW builds
|
||||
# Dynamic Library builds
|
||||
# LTS version of Qt, dll, 32bit, MinGW, qmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\mingw53_32
|
||||
COMPILER: C:\Qt\Tools\mingw530_32
|
||||
targetPlatform: x86
|
||||
use_mingw: "true"
|
||||
use_static: "false"
|
||||
use_cmake: "false"
|
||||
# LTS version of Qt, dll, 32bit, MinGW, cmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\mingw53_32
|
||||
COMPILER: C:\Qt\Tools\mingw530_32
|
||||
targetPlatform: x86
|
||||
use_mingw: "true"
|
||||
use_static: "false"
|
||||
use_cmake: "true"
|
||||
# end Dynamic Library builds
|
||||
# Static Library builds
|
||||
# LTS version of Qt, static, 32bit, MinGW, qmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\mingw53_32
|
||||
COMPILER: C:\Qt\Tools\mingw530_32
|
||||
targetPlatform: x86
|
||||
use_mingw: "true"
|
||||
use_static: "true"
|
||||
use_cmake: "false"
|
||||
# LTS version of Qt, static, 32bit, MinGW, cmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\mingw53_32
|
||||
COMPILER: C:\Qt\Tools\mingw530_32
|
||||
targetPlatform: x86
|
||||
use_mingw: "true"
|
||||
use_static: "true"
|
||||
use_cmake: "true"
|
||||
# end Static Library builds
|
||||
# end MinGW builds
|
||||
# end 32 bit builds
|
||||
# 64 bit builds
|
||||
# MSVC 2015 builds
|
||||
# Dynamic Library builds
|
||||
# LTS version of Qt, dll, 64bit, MSVC 2015, qmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015_64
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: amd64
|
||||
use_mingw: "false"
|
||||
use_static: "false"
|
||||
use_cmake: "false"
|
||||
# LTS version of Qt, dll, 64bit, MSVC 2015, cmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015_64
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: amd64
|
||||
use_mingw: "false"
|
||||
use_static: "false"
|
||||
use_cmake: "true"
|
||||
# end Dynamic Library builds
|
||||
# Static Library builds
|
||||
# LTS version of Qt, static, 64bit, MSVC 2015, qmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015_64
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: amd64
|
||||
use_mingw: "false"
|
||||
use_static: "true"
|
||||
use_cmake: "false"
|
||||
# LTS version of Qt, static, 64bit, MSVC 2015, cmake
|
||||
- QT5: C:\Qt\%LatestLTSQtVersion%\msvc2015_64
|
||||
COMPILER: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
|
||||
targetPlatform: amd64
|
||||
use_mingw: "false"
|
||||
use_static: "true"
|
||||
use_cmake: "true"
|
||||
# end Static Library builds
|
||||
# end MSVC 2015 builds
|
||||
# end 64 bit builds
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
before_build:
|
||||
- set PATH=%COMPILER%\bin;%QT5%\bin;%PATH%
|
||||
- set originalWD=%CD%
|
||||
- call "%QT5%\bin\qtenv2.bat"
|
||||
- cd %originalWD%
|
||||
- if %use_mingw%==false call "%COMPILER%\vcvarsall.bat" %targetPlatform%
|
||||
- if %use_static%==true (set USESTATIC=ON) else (set USESTATIC=OFF)
|
||||
- if %use_mingw%==true (set CMAKEGENERATOR="MinGW Makefiles") else (set CMAKEGENERATOR="NMake Makefiles")
|
||||
- if %use_mingw%==true (set MAKEENGINE=mingw32-make) else (set MAKEENGINE=nmake)
|
||||
- if %use_mingw%==true set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
|
||||
|
||||
build_script:
|
||||
- if %use_cmake%==true mkdir .\build
|
||||
- if %use_cmake%==true cd .\build
|
||||
- if %use_cmake%==true cmake --version
|
||||
- if %use_cmake%==true cmake -G %CMAKEGENERATOR% -DCMAKE_BUILD_TYPE=DEBUG -DBUILD_EXAMPLES=ON -DCMAKE_DEBUG_POSTFIX=d -DBUILD_STATIC=%USESTATIC% -DCMAKE_INSTALL_PREFIX="./installed" ../
|
||||
- if %use_cmake%==true cmake --build .
|
||||
- if %use_cmake%==true cmake --build . --target install
|
||||
- if %use_cmake%==true cmake -G %CMAKEGENERATOR% -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=ON -DBUILD_STATIC=%USESTATIC% -DCMAKE_INSTALL_PREFIX="./installed" ../
|
||||
- if %use_cmake%==true cmake --build .
|
||||
- if %use_cmake%==true cmake --build . --target install
|
||||
- if %use_cmake%==false if %use_static%==true qmake "CONFIG+=adsBuildStatic"
|
||||
- if %use_cmake%==false if %use_static%==false qmake
|
||||
- if %use_cmake%==false %MAKEENGINE% debug
|
||||
- if %use_cmake%==false %MAKEENGINE% install
|
||||
- if %use_cmake%==false %MAKEENGINE% release
|
||||
- if %use_cmake%==false %MAKEENGINE% install
|
||||
|
||||
after_build:
|
||||
- if %use_mingw%==true set PATH=C:\Program Files\Git\usr\bin;%PATH%
|
||||
50
.cproject
@@ -83,6 +83,7 @@
|
||||
</target>
|
||||
<target name="Clean" path=" build" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>make</buildCommand>
|
||||
<buildArguments/>
|
||||
<buildTarget>clean</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>true</useDefaultCommand>
|
||||
@@ -99,7 +100,6 @@
|
||||
<target name="qmake" path=" build" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>qmake</buildCommand>
|
||||
<buildArguments>-recursive ../ads.pro</buildArguments>
|
||||
<buildTarget/>
|
||||
<stopOnError>true</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
@@ -122,7 +122,6 @@
|
||||
</target>
|
||||
<target name="Clean" path=" build/src" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>make</buildCommand>
|
||||
<buildArguments/>
|
||||
<buildTarget>clean</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>true</useDefaultCommand>
|
||||
@@ -139,7 +138,6 @@
|
||||
<target name="qmake" path=" build/src" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>qmake</buildCommand>
|
||||
<buildArguments>-recursive ../../src/src.pro</buildArguments>
|
||||
<buildTarget/>
|
||||
<stopOnError>true</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
@@ -152,6 +150,46 @@
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
</target>
|
||||
<target name="Build all" path=" build/example" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>mingw32-make</buildCommand>
|
||||
<buildArguments>-j</buildArguments>
|
||||
<buildTarget>all</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
</target>
|
||||
<target name="Clean" path=" build/example" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>make</buildCommand>
|
||||
<buildArguments/>
|
||||
<buildTarget>clean</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>true</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
</target>
|
||||
<target name="Debug Build" path=" build/example" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>mingw32-make</buildCommand>
|
||||
<buildArguments>-j6</buildArguments>
|
||||
<buildTarget>debug</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
</target>
|
||||
<target name="qmake" path=" build/example" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>qmake</buildCommand>
|
||||
<buildArguments>-recursive ../../example/example.pro</buildArguments>
|
||||
<buildTarget/>
|
||||
<stopOnError>true</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
</target>
|
||||
<target name="Release Build" path=" build/example" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>mingw32-make</buildCommand>
|
||||
<buildArguments>-j4</buildArguments>
|
||||
<buildTarget>release</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
</target>
|
||||
<target name="Build all" path=" build/demo" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>mingw32-make</buildCommand>
|
||||
<buildArguments>-j</buildArguments>
|
||||
@@ -162,7 +200,6 @@
|
||||
</target>
|
||||
<target name="Clean" path=" build/demo" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>make</buildCommand>
|
||||
<buildArguments/>
|
||||
<buildTarget>clean</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>true</useDefaultCommand>
|
||||
@@ -179,7 +216,6 @@
|
||||
<target name="qmake" path=" build/demo" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>qmake</buildCommand>
|
||||
<buildArguments>-recursive ../../demo/demo.pro</buildArguments>
|
||||
<buildTarget/>
|
||||
<stopOnError>true</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
@@ -202,6 +238,7 @@
|
||||
</target>
|
||||
<target name="Clean" path=" build/AdvancedDockingSystemDemo" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>make</buildCommand>
|
||||
<buildArguments/>
|
||||
<buildTarget>clean</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>true</useDefaultCommand>
|
||||
@@ -240,6 +277,7 @@
|
||||
</target>
|
||||
<target name="Clean" path=" build/AdvancedDockingSystemDemo_v2" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>make</buildCommand>
|
||||
<buildArguments/>
|
||||
<buildTarget>clean</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>true</useDefaultCommand>
|
||||
@@ -278,6 +316,7 @@
|
||||
</target>
|
||||
<target name="Clean" path=" build/AdvancedDockingSystem" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>make</buildCommand>
|
||||
<buildArguments/>
|
||||
<buildTarget>clean</buildTarget>
|
||||
<stopOnError>false</stopOnError>
|
||||
<useDefaultCommand>true</useDefaultCommand>
|
||||
@@ -294,7 +333,6 @@
|
||||
<target name="qmake" path=" build/AdvancedDockingSystem" targetID="org.eclipse.cdt.build.MakeTargetBuilder">
|
||||
<buildCommand>qmake</buildCommand>
|
||||
<buildArguments>-recursive ../../AdvancedDockingSystem/src.pro</buildArguments>
|
||||
<buildTarget/>
|
||||
<stopOnError>true</stopOnError>
|
||||
<useDefaultCommand>false</useDefaultCommand>
|
||||
<runAllBuilders>false</runAllBuilders>
|
||||
|
||||
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
PyQtAds/_version.py export-subst
|
||||
22
.github/workflows/linux-builds.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: linux-builds
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, ubuntu-18.04, ubuntu-16.04]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: install qt
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get install qt5-default
|
||||
- name: qmake
|
||||
run: qmake
|
||||
- name: make
|
||||
run: make -j4
|
||||
19
.gitignore
vendored
@@ -1,2 +1,19 @@
|
||||
*.pro.user
|
||||
/ build
|
||||
/build
|
||||
*.o
|
||||
*.dylib
|
||||
*.app
|
||||
qrc_*
|
||||
moc_*
|
||||
ui_*
|
||||
Makefile
|
||||
|
||||
# IDEs
|
||||
.idea
|
||||
|
||||
# Python
|
||||
.eggs
|
||||
*.pyc
|
||||
*.pyd
|
||||
__pycache__
|
||||
PyQtAds/rc.py
|
||||
|
||||
155
.travis.yml
Normal file
@@ -0,0 +1,155 @@
|
||||
language: cpp
|
||||
# gcc is clang on mac
|
||||
compiler: gcc
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- name: Ubuntu qmake Qt5.5.1
|
||||
os: linux
|
||||
dist: trusty
|
||||
group: stable
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt551-trusty'
|
||||
update: true
|
||||
packages:
|
||||
- qt55base
|
||||
- qt55tools
|
||||
- gcc-6
|
||||
- g++-6
|
||||
- libc6-i386
|
||||
script:
|
||||
- PATH="/opt/qt55/bin:$PATH"
|
||||
- CXX="g++-6"
|
||||
- CC="gcc-6"
|
||||
- qt55-env.sh
|
||||
- qmake
|
||||
- make
|
||||
- make install
|
||||
- name: Ubuntu qmake dll
|
||||
os: linux
|
||||
dist: xenial
|
||||
group: stable
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt-5.12.0-xenial'
|
||||
update: true
|
||||
packages:
|
||||
- qt512base
|
||||
- qt512tools
|
||||
- gcc-6
|
||||
- g++-6
|
||||
- libc6-i386
|
||||
- libgl-dev
|
||||
- libgl1-mesa-dev
|
||||
- mesa-common-dev
|
||||
script:
|
||||
- PATH="/opt/qt512/bin:$PATH"
|
||||
- CXX="g++-6"
|
||||
- CC="gcc-6"
|
||||
- qt512-env.sh
|
||||
- qmake
|
||||
- make
|
||||
- make install
|
||||
- name: Ubuntu qmake static
|
||||
os: linux
|
||||
dist: xenial
|
||||
group: stable
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:beineri/opt-qt-5.12.0-xenial'
|
||||
update: true
|
||||
packages:
|
||||
- qt512base
|
||||
- qt512tools
|
||||
- gcc-6
|
||||
- g++-6
|
||||
- libc6-i386
|
||||
- libgl-dev
|
||||
- libgl1-mesa-dev
|
||||
- mesa-common-dev
|
||||
script:
|
||||
- PATH="/opt/qt512/bin:$PATH"
|
||||
- CXX="g++-6"
|
||||
- CC="gcc-6"
|
||||
- qt512-env.sh
|
||||
- qmake "CONFIG+=adsBuildStatic"
|
||||
- make
|
||||
- make install
|
||||
- name: macOS CMake dll
|
||||
os: osx
|
||||
osx_image: xcode10.1
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- qt
|
||||
update: true
|
||||
script:
|
||||
- PATH="/usr/local/opt/qt5/bin:$PATH"
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- cmake --version
|
||||
- cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_DEBUG_POSTFIX=_debug -DBUILD_EXAMPLES=ON -DBUILD_STATIC=OFF -DCMAKE_INSTALL_PREFIX="./installed" ../
|
||||
- cmake --build .
|
||||
- cmake --build . --target install
|
||||
- cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=ON -DBUILD_STATIC=OFF -DCMAKE_INSTALL_PREFIX="./installed" ../
|
||||
- cmake --build .
|
||||
- cmake --build . --target install
|
||||
- name: macOS CMake static
|
||||
os: osx
|
||||
osx_image: xcode10.1
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- qt
|
||||
update: true
|
||||
script:
|
||||
- PATH="/usr/local/opt/qt5/bin:$PATH"
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- cmake --version
|
||||
- cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_DEBUG_POSTFIX=_debug -DBUILD_EXAMPLES=ON -DBUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX="./installed" ../
|
||||
- cmake --build .
|
||||
- cmake --build . --target install
|
||||
- cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=ON -DBUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX="./installed" ../
|
||||
- cmake --build .
|
||||
- cmake --build . --target install
|
||||
- name: macOS qmake dll
|
||||
os: osx
|
||||
osx_image: xcode10.1
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- qt
|
||||
update: true
|
||||
script:
|
||||
- PATH="/usr/local/opt/qt5/bin:$PATH"
|
||||
- qmake
|
||||
- make
|
||||
- make install
|
||||
- name: macOS qmake static
|
||||
os: osx
|
||||
osx_image: xcode10.1
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- qt
|
||||
update: true
|
||||
script:
|
||||
- PATH="/usr/local/opt/qt5/bin:$PATH"
|
||||
- qmake "CONFIG+=adsBuildStatic"
|
||||
- make
|
||||
- make install
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
127
CMakeLists.txt
Normal file
@@ -0,0 +1,127 @@
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
set(ads_VERSION "2.3.2")
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
project(QtAdvancedDockingSystem VERSION ${ads_VERSION})
|
||||
option(BUILD_STATIC "Build the static library" OFF)
|
||||
option(BUILD_EXAMPLES "Build the examples" ON)
|
||||
set(REQUIRED_QT_VERSION 5.5.0)
|
||||
find_package(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_package(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
message(STATUS "Found Qt ${Qt5Core_VERSION}")
|
||||
set(ads_INCLUDE ${ads_INCLUDE} ${Qt5Core_INCLUDE_DIRS})
|
||||
set(ads_INCLUDE ${ads_INCLUDE} "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
set(ads_LIBS ${ads_LIBS} ${Qt5Core_LIBRARIES})
|
||||
set(ads_COMPILE_DEFINE ${ads_COMPILE_DEFINE} ${Qt5Core_COMPILE_DEFINITIONS})
|
||||
set(ads_LIBS ${ads_LIBS} ${Qt5Gui_LIBRARIES})
|
||||
set(ads_INCLUDE ${ads_INCLUDE} ${Qt5Gui_INCLUDE_DIRS})
|
||||
set(ads_COMPILE_DEFINE ${ads_COMPILE_DEFINE} ${Qt5Gui_COMPILE_DEFINITIONS})
|
||||
set(ads_LIBS ${ads_LIBS} ${Qt5Widgets_LIBRARIES})
|
||||
set(ads_INCLUDE ${ads_INCLUDE} ${Qt5Widgets_INCLUDE_DIRS})
|
||||
set(ads_COMPILE_DEFINE ${ads_COMPILE_DEFINE} ${Qt5Widgets_COMPILE_DEFINITIONS})
|
||||
if(BUILD_STATIC)
|
||||
set(CMAKE_STATIC_LIBRARY_SUFFIX "_static${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
endif()
|
||||
set(ads_SRCS
|
||||
src/ads_globals.cpp
|
||||
src/DockAreaTabBar.cpp
|
||||
src/DockAreaTitleBar.cpp
|
||||
src/DockAreaWidget.cpp
|
||||
src/DockContainerWidget.cpp
|
||||
src/DockManager.cpp
|
||||
src/DockOverlay.cpp
|
||||
src/DockSplitter.cpp
|
||||
src/DockWidget.cpp
|
||||
src/DockWidgetTab.cpp
|
||||
src/DockingStateReader.cpp
|
||||
src/ElidingLabel.cpp
|
||||
src/FloatingDockContainer.cpp
|
||||
src/FloatingDragPreview.cpp
|
||||
src/IconProvider.cpp
|
||||
src/ads.qrc
|
||||
src/linux/FloatingWidgetTitleBar.cpp
|
||||
)
|
||||
set(ads_INSTALL_INCLUDE
|
||||
src/ads_globals.h
|
||||
src/DockAreaTabBar.h
|
||||
src/DockAreaTitleBar.h
|
||||
src/DockAreaWidget.h
|
||||
src/DockContainerWidget.h
|
||||
src/DockManager.h
|
||||
src/DockOverlay.h
|
||||
src/DockSplitter.h
|
||||
src/DockWidget.h
|
||||
src/DockWidgetTab.h
|
||||
src/DockingStateReader.h
|
||||
src/ElidingLabel.h
|
||||
src/FloatingDockContainer.h
|
||||
src/FloatingDragPreview.h
|
||||
src/IconProvider.h
|
||||
src/linux/FloatingWidgetTitleBar.h
|
||||
)
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
|
||||
set(ads_PlatformDir "x86")
|
||||
else()
|
||||
set(ads_PlatformDir "x64")
|
||||
endif()
|
||||
if(BUILD_STATIC)
|
||||
add_library(qtadvanceddocking STATIC ${ads_SRCS})
|
||||
target_compile_definitions(qtadvanceddocking PUBLIC ADS_STATIC)
|
||||
else()
|
||||
add_library(qtadvanceddocking SHARED ${ads_SRCS})
|
||||
set(ads_COMPILE_DEFINE ${ads_COMPILE_DEFINE} ADS_SHARED_EXPORT)
|
||||
endif()
|
||||
install(FILES ${ads_INSTALL_INCLUDE}
|
||||
DESTINATION include
|
||||
COMPONENT headers
|
||||
)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/gnu-lgpl-v2.1.md"
|
||||
DESTINATION license
|
||||
COMPONENT license
|
||||
)
|
||||
install(TARGETS qtadvanceddocking
|
||||
EXPORT adsTargets
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
INCLUDES DESTINATION include
|
||||
)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file("adsConfigVersion.cmake"
|
||||
VERSION ${ads_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
install(EXPORT adsTargets
|
||||
FILE adsTargets.cmake
|
||||
NAMESPACE ads::
|
||||
DESTINATION lib/cmake/ads
|
||||
)
|
||||
install(FILES "adsConfig.cmake" "${CMAKE_BINARY_DIR}/adsConfigVersion.cmake"
|
||||
DESTINATION lib/cmake/ads
|
||||
)
|
||||
|
||||
target_include_directories(qtadvanceddocking PUBLIC
|
||||
"$<BUILD_INTERFACE:${ads_INCLUDE}>"
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
target_link_libraries(qtadvanceddocking PUBLIC ${ads_LIBS})
|
||||
target_compile_definitions(qtadvanceddocking PRIVATE ${ads_COMPILE_DEFINE})
|
||||
set_target_properties(qtadvanceddocking PROPERTIES
|
||||
VERSION ${ads_VERSION}
|
||||
EXPORT_NAME "QtAdvancedDockingSystem"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
|
||||
)
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(example)
|
||||
add_subdirectory(demo)
|
||||
endif()
|
||||
|
||||
2
MANIFEST.in
Normal file
@@ -0,0 +1,2 @@
|
||||
include versioneer.py
|
||||
include PyQtAds/_version.py
|
||||
10
PyQtAds/QtAds/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from .ads import ads
|
||||
from .._version import *
|
||||
|
||||
import inspect
|
||||
|
||||
for name, member in inspect.getmembers(ads):
|
||||
if not name.startswith('_'):
|
||||
globals()[name] = member
|
||||
|
||||
del ads
|
||||
9
PyQtAds/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from .rc import *
|
||||
from ._version import get_versions
|
||||
__version__ = get_versions()['version']
|
||||
short_version = __version__
|
||||
version = __version__
|
||||
full_version = __version__
|
||||
git_revision = get_versions()['full-revisionid']
|
||||
release = not get_versions()['dirty']
|
||||
del get_versions
|
||||
520
PyQtAds/_version.py
Normal file
@@ -0,0 +1,520 @@
|
||||
|
||||
# This file helps to compute a version number in source trees obtained from
|
||||
# git-archive tarball (such as those provided by githubs download-from-tag
|
||||
# feature). Distribution tarballs (built by setup.py sdist) and build
|
||||
# directories (produced by setup.py build) will contain a much shorter file
|
||||
# that just contains the computed version number.
|
||||
|
||||
# This file is released into the public domain. Generated by
|
||||
# versioneer-0.18 (https://github.com/warner/python-versioneer)
|
||||
|
||||
"""Git implementation of _version.py."""
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def get_keywords():
|
||||
"""Get the keywords needed to look up the version information."""
|
||||
# these strings will be replaced by git during git-archive.
|
||||
# setup.py/versioneer.py will grep for the variable names, so they must
|
||||
# each be defined on a line of their own. _version.py will just call
|
||||
# get_keywords().
|
||||
git_refnames = "$Format:%d$"
|
||||
git_full = "$Format:%H$"
|
||||
git_date = "$Format:%ci$"
|
||||
keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
|
||||
return keywords
|
||||
|
||||
|
||||
class VersioneerConfig:
|
||||
"""Container for Versioneer configuration parameters."""
|
||||
|
||||
|
||||
def get_config():
|
||||
"""Create, populate and return the VersioneerConfig() object."""
|
||||
# these strings are filled in when 'setup.py versioneer' creates
|
||||
# _version.py
|
||||
cfg = VersioneerConfig()
|
||||
cfg.VCS = "git"
|
||||
cfg.style = "pep440"
|
||||
cfg.tag_prefix = ""
|
||||
cfg.parentdir_prefix = "None"
|
||||
cfg.versionfile_source = "PyQtAds/_version.py"
|
||||
cfg.verbose = False
|
||||
return cfg
|
||||
|
||||
|
||||
class NotThisMethod(Exception):
|
||||
"""Exception raised if a method is not valid for the current scenario."""
|
||||
|
||||
|
||||
LONG_VERSION_PY = {}
|
||||
HANDLERS = {}
|
||||
|
||||
|
||||
def register_vcs_handler(vcs, method): # decorator
|
||||
"""Create decorator to mark a method as the handler of a VCS."""
|
||||
def decorate(f):
|
||||
"""Store f in HANDLERS[vcs][method]."""
|
||||
if vcs not in HANDLERS:
|
||||
HANDLERS[vcs] = {}
|
||||
HANDLERS[vcs][method] = f
|
||||
return f
|
||||
return decorate
|
||||
|
||||
|
||||
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
|
||||
env=None):
|
||||
"""Call the given command(s)."""
|
||||
assert isinstance(commands, list)
|
||||
p = None
|
||||
for c in commands:
|
||||
try:
|
||||
dispcmd = str([c] + args)
|
||||
# remember shell=False, so use git.cmd on windows, not just git
|
||||
p = subprocess.Popen([c] + args, cwd=cwd, env=env,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=(subprocess.PIPE if hide_stderr
|
||||
else None))
|
||||
break
|
||||
except EnvironmentError:
|
||||
e = sys.exc_info()[1]
|
||||
if e.errno == errno.ENOENT:
|
||||
continue
|
||||
if verbose:
|
||||
print("unable to run %s" % dispcmd)
|
||||
print(e)
|
||||
return None, None
|
||||
else:
|
||||
if verbose:
|
||||
print("unable to find command, tried %s" % (commands,))
|
||||
return None, None
|
||||
stdout = p.communicate()[0].strip()
|
||||
if sys.version_info[0] >= 3:
|
||||
stdout = stdout.decode()
|
||||
if p.returncode != 0:
|
||||
if verbose:
|
||||
print("unable to run %s (error)" % dispcmd)
|
||||
print("stdout was %s" % stdout)
|
||||
return None, p.returncode
|
||||
return stdout, p.returncode
|
||||
|
||||
|
||||
def versions_from_parentdir(parentdir_prefix, root, verbose):
|
||||
"""Try to determine the version from the parent directory name.
|
||||
|
||||
Source tarballs conventionally unpack into a directory that includes both
|
||||
the project name and a version string. We will also support searching up
|
||||
two directory levels for an appropriately named parent directory
|
||||
"""
|
||||
rootdirs = []
|
||||
|
||||
for i in range(3):
|
||||
dirname = os.path.basename(root)
|
||||
if dirname.startswith(parentdir_prefix):
|
||||
return {"version": dirname[len(parentdir_prefix):],
|
||||
"full-revisionid": None,
|
||||
"dirty": False, "error": None, "date": None}
|
||||
else:
|
||||
rootdirs.append(root)
|
||||
root = os.path.dirname(root) # up a level
|
||||
|
||||
if verbose:
|
||||
print("Tried directories %s but none started with prefix %s" %
|
||||
(str(rootdirs), parentdir_prefix))
|
||||
raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
|
||||
|
||||
|
||||
@register_vcs_handler("git", "get_keywords")
|
||||
def git_get_keywords(versionfile_abs):
|
||||
"""Extract version information from the given file."""
|
||||
# the code embedded in _version.py can just fetch the value of these
|
||||
# keywords. When used from setup.py, we don't want to import _version.py,
|
||||
# so we do it with a regexp instead. This function is not used from
|
||||
# _version.py.
|
||||
keywords = {}
|
||||
try:
|
||||
f = open(versionfile_abs, "r")
|
||||
for line in f.readlines():
|
||||
if line.strip().startswith("git_refnames ="):
|
||||
mo = re.search(r'=\s*"(.*)"', line)
|
||||
if mo:
|
||||
keywords["refnames"] = mo.group(1)
|
||||
if line.strip().startswith("git_full ="):
|
||||
mo = re.search(r'=\s*"(.*)"', line)
|
||||
if mo:
|
||||
keywords["full"] = mo.group(1)
|
||||
if line.strip().startswith("git_date ="):
|
||||
mo = re.search(r'=\s*"(.*)"', line)
|
||||
if mo:
|
||||
keywords["date"] = mo.group(1)
|
||||
f.close()
|
||||
except EnvironmentError:
|
||||
pass
|
||||
return keywords
|
||||
|
||||
|
||||
@register_vcs_handler("git", "keywords")
|
||||
def git_versions_from_keywords(keywords, tag_prefix, verbose):
|
||||
"""Get version information from git keywords."""
|
||||
if not keywords:
|
||||
raise NotThisMethod("no keywords at all, weird")
|
||||
date = keywords.get("date")
|
||||
if date is not None:
|
||||
# git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
|
||||
# datestamp. However we prefer "%ci" (which expands to an "ISO-8601
|
||||
# -like" string, which we must then edit to make compliant), because
|
||||
# it's been around since git-1.5.3, and it's too difficult to
|
||||
# discover which version we're using, or to work around using an
|
||||
# older one.
|
||||
date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
|
||||
refnames = keywords["refnames"].strip()
|
||||
if refnames.startswith("$Format"):
|
||||
if verbose:
|
||||
print("keywords are unexpanded, not using")
|
||||
raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
|
||||
refs = set([r.strip() for r in refnames.strip("()").split(",")])
|
||||
# starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
|
||||
# just "foo-1.0". If we see a "tag: " prefix, prefer those.
|
||||
TAG = "tag: "
|
||||
tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
|
||||
if not tags:
|
||||
# Either we're using git < 1.8.3, or there really are no tags. We use
|
||||
# a heuristic: assume all version tags have a digit. The old git %d
|
||||
# expansion behaves like git log --decorate=short and strips out the
|
||||
# refs/heads/ and refs/tags/ prefixes that would let us distinguish
|
||||
# between branches and tags. By ignoring refnames without digits, we
|
||||
# filter out many common branch names like "release" and
|
||||
# "stabilization", as well as "HEAD" and "master".
|
||||
tags = set([r for r in refs if re.search(r'\d', r)])
|
||||
if verbose:
|
||||
print("discarding '%s', no digits" % ",".join(refs - tags))
|
||||
if verbose:
|
||||
print("likely tags: %s" % ",".join(sorted(tags)))
|
||||
for ref in sorted(tags):
|
||||
# sorting will prefer e.g. "2.0" over "2.0rc1"
|
||||
if ref.startswith(tag_prefix):
|
||||
r = ref[len(tag_prefix):]
|
||||
if verbose:
|
||||
print("picking %s" % r)
|
||||
return {"version": r,
|
||||
"full-revisionid": keywords["full"].strip(),
|
||||
"dirty": False, "error": None,
|
||||
"date": date}
|
||||
# no suitable tags, so version is "0+unknown", but full hex is still there
|
||||
if verbose:
|
||||
print("no suitable tags, using unknown + full revision id")
|
||||
return {"version": "0+unknown",
|
||||
"full-revisionid": keywords["full"].strip(),
|
||||
"dirty": False, "error": "no suitable tags", "date": None}
|
||||
|
||||
|
||||
@register_vcs_handler("git", "pieces_from_vcs")
|
||||
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
|
||||
"""Get version from 'git describe' in the root of the source tree.
|
||||
|
||||
This only gets called if the git-archive 'subst' keywords were *not*
|
||||
expanded, and _version.py hasn't already been rewritten with a short
|
||||
version string, meaning we're inside a checked out source tree.
|
||||
"""
|
||||
GITS = ["git"]
|
||||
if sys.platform == "win32":
|
||||
GITS = ["git.cmd", "git.exe"]
|
||||
|
||||
out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
|
||||
hide_stderr=True)
|
||||
if rc != 0:
|
||||
if verbose:
|
||||
print("Directory %s not under git control" % root)
|
||||
raise NotThisMethod("'git rev-parse --git-dir' returned error")
|
||||
|
||||
# if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
|
||||
# if there isn't one, this yields HEX[-dirty] (no NUM)
|
||||
describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
|
||||
"--always", "--long",
|
||||
"--match", "%s*" % tag_prefix],
|
||||
cwd=root)
|
||||
# --long was added in git-1.5.5
|
||||
if describe_out is None:
|
||||
raise NotThisMethod("'git describe' failed")
|
||||
describe_out = describe_out.strip()
|
||||
full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
|
||||
if full_out is None:
|
||||
raise NotThisMethod("'git rev-parse' failed")
|
||||
full_out = full_out.strip()
|
||||
|
||||
pieces = {}
|
||||
pieces["long"] = full_out
|
||||
pieces["short"] = full_out[:7] # maybe improved later
|
||||
pieces["error"] = None
|
||||
|
||||
# parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
|
||||
# TAG might have hyphens.
|
||||
git_describe = describe_out
|
||||
|
||||
# look for -dirty suffix
|
||||
dirty = git_describe.endswith("-dirty")
|
||||
pieces["dirty"] = dirty
|
||||
if dirty:
|
||||
git_describe = git_describe[:git_describe.rindex("-dirty")]
|
||||
|
||||
# now we have TAG-NUM-gHEX or HEX
|
||||
|
||||
if "-" in git_describe:
|
||||
# TAG-NUM-gHEX
|
||||
mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
|
||||
if not mo:
|
||||
# unparseable. Maybe git-describe is misbehaving?
|
||||
pieces["error"] = ("unable to parse git-describe output: '%s'"
|
||||
% describe_out)
|
||||
return pieces
|
||||
|
||||
# tag
|
||||
full_tag = mo.group(1)
|
||||
if not full_tag.startswith(tag_prefix):
|
||||
if verbose:
|
||||
fmt = "tag '%s' doesn't start with prefix '%s'"
|
||||
print(fmt % (full_tag, tag_prefix))
|
||||
pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
|
||||
% (full_tag, tag_prefix))
|
||||
return pieces
|
||||
pieces["closest-tag"] = full_tag[len(tag_prefix):]
|
||||
|
||||
# distance: number of commits since tag
|
||||
pieces["distance"] = int(mo.group(2))
|
||||
|
||||
# commit: short hex revision ID
|
||||
pieces["short"] = mo.group(3)
|
||||
|
||||
else:
|
||||
# HEX: no tags
|
||||
pieces["closest-tag"] = None
|
||||
count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
|
||||
cwd=root)
|
||||
pieces["distance"] = int(count_out) # total number of commits
|
||||
|
||||
# commit date: see ISO-8601 comment in git_versions_from_keywords()
|
||||
date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
|
||||
cwd=root)[0].strip()
|
||||
pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
|
||||
|
||||
return pieces
|
||||
|
||||
|
||||
def plus_or_dot(pieces):
|
||||
"""Return a + if we don't already have one, else return a ."""
|
||||
if "+" in pieces.get("closest-tag", ""):
|
||||
return "."
|
||||
return "+"
|
||||
|
||||
|
||||
def render_pep440(pieces):
|
||||
"""Build up version string, with post-release "local version identifier".
|
||||
|
||||
Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
|
||||
get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
|
||||
|
||||
Exceptions:
|
||||
1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"] or pieces["dirty"]:
|
||||
rendered += plus_or_dot(pieces)
|
||||
rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dirty"
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0+untagged.%d.g%s" % (pieces["distance"],
|
||||
pieces["short"])
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dirty"
|
||||
return rendered
|
||||
|
||||
|
||||
def render_pep440_pre(pieces):
|
||||
"""TAG[.post.devDISTANCE] -- No -dirty.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. 0.post.devDISTANCE
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"]:
|
||||
rendered += ".post.dev%d" % pieces["distance"]
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0.post.dev%d" % pieces["distance"]
|
||||
return rendered
|
||||
|
||||
|
||||
def render_pep440_post(pieces):
|
||||
"""TAG[.postDISTANCE[.dev0]+gHEX] .
|
||||
|
||||
The ".dev0" means dirty. Note that .dev0 sorts backwards
|
||||
(a dirty tree will appear "older" than the corresponding clean one),
|
||||
but you shouldn't be releasing software with -dirty anyways.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. 0.postDISTANCE[.dev0]
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"] or pieces["dirty"]:
|
||||
rendered += ".post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
rendered += plus_or_dot(pieces)
|
||||
rendered += "g%s" % pieces["short"]
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0.post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
rendered += "+g%s" % pieces["short"]
|
||||
return rendered
|
||||
|
||||
|
||||
def render_pep440_old(pieces):
|
||||
"""TAG[.postDISTANCE[.dev0]] .
|
||||
|
||||
The ".dev0" means dirty.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. 0.postDISTANCE[.dev0]
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"] or pieces["dirty"]:
|
||||
rendered += ".post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0.post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
return rendered
|
||||
|
||||
|
||||
def render_git_describe(pieces):
|
||||
"""TAG[-DISTANCE-gHEX][-dirty].
|
||||
|
||||
Like 'git describe --tags --dirty --always'.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. HEX[-dirty] (note: no 'g' prefix)
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"]:
|
||||
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
|
||||
else:
|
||||
# exception #1
|
||||
rendered = pieces["short"]
|
||||
if pieces["dirty"]:
|
||||
rendered += "-dirty"
|
||||
return rendered
|
||||
|
||||
|
||||
def render_git_describe_long(pieces):
|
||||
"""TAG-DISTANCE-gHEX[-dirty].
|
||||
|
||||
Like 'git describe --tags --dirty --always -long'.
|
||||
The distance/hash is unconditional.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. HEX[-dirty] (note: no 'g' prefix)
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
|
||||
else:
|
||||
# exception #1
|
||||
rendered = pieces["short"]
|
||||
if pieces["dirty"]:
|
||||
rendered += "-dirty"
|
||||
return rendered
|
||||
|
||||
|
||||
def render(pieces, style):
|
||||
"""Render the given version pieces into the requested style."""
|
||||
if pieces["error"]:
|
||||
return {"version": "unknown",
|
||||
"full-revisionid": pieces.get("long"),
|
||||
"dirty": None,
|
||||
"error": pieces["error"],
|
||||
"date": None}
|
||||
|
||||
if not style or style == "default":
|
||||
style = "pep440" # the default
|
||||
|
||||
if style == "pep440":
|
||||
rendered = render_pep440(pieces)
|
||||
elif style == "pep440-pre":
|
||||
rendered = render_pep440_pre(pieces)
|
||||
elif style == "pep440-post":
|
||||
rendered = render_pep440_post(pieces)
|
||||
elif style == "pep440-old":
|
||||
rendered = render_pep440_old(pieces)
|
||||
elif style == "git-describe":
|
||||
rendered = render_git_describe(pieces)
|
||||
elif style == "git-describe-long":
|
||||
rendered = render_git_describe_long(pieces)
|
||||
else:
|
||||
raise ValueError("unknown style '%s'" % style)
|
||||
|
||||
return {"version": rendered, "full-revisionid": pieces["long"],
|
||||
"dirty": pieces["dirty"], "error": None,
|
||||
"date": pieces.get("date")}
|
||||
|
||||
|
||||
def get_versions():
|
||||
"""Get version information or return default if unable to do so."""
|
||||
# I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
|
||||
# __file__, we can work backwards from there to the root. Some
|
||||
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
|
||||
# case we can only use expanded keywords.
|
||||
|
||||
cfg = get_config()
|
||||
verbose = cfg.verbose
|
||||
|
||||
try:
|
||||
return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
|
||||
verbose)
|
||||
except NotThisMethod:
|
||||
pass
|
||||
|
||||
try:
|
||||
root = os.path.realpath(__file__)
|
||||
# versionfile_source is the relative path from the top of the source
|
||||
# tree (where the .git directory might live) to this file. Invert
|
||||
# this to find the root from __file__.
|
||||
for i in cfg.versionfile_source.split('/'):
|
||||
root = os.path.dirname(root)
|
||||
except NameError:
|
||||
return {"version": "0+unknown", "full-revisionid": None,
|
||||
"dirty": None,
|
||||
"error": "unable to find root of source tree",
|
||||
"date": None}
|
||||
|
||||
try:
|
||||
pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
|
||||
return render(pieces, cfg.style)
|
||||
except NotThisMethod:
|
||||
pass
|
||||
|
||||
try:
|
||||
if cfg.parentdir_prefix:
|
||||
return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
|
||||
except NotThisMethod:
|
||||
pass
|
||||
|
||||
return {"version": "0+unknown", "full-revisionid": None,
|
||||
"dirty": None,
|
||||
"error": "unable to compute version", "date": None}
|
||||
184
README.md
@@ -1,10 +1,16 @@
|
||||
# Advanced Docking System for Qt
|
||||
# Advanced Docking System for Qt
|
||||
[](https://travis-ci.org/githubuser0xFFFF/Qt-Advanced-Docking-System)
|
||||
[](https://ci.appveyor.com/project/githubuser0xFFFF/qt-advanced-docking-system/branch/master)
|
||||
[](gnu-lgpl-v2.1.md)
|
||||
|
||||
Qt Advanced Docking System lets you create customizable layouts using a full
|
||||
featured window docking system similar to what is found in many popular
|
||||
integrated development environements (IDEs) such as Visual Studio.
|
||||
integrated development environments (IDEs) such as Visual Studio.
|
||||
|
||||
[](https://www.youtube.com/watch?v=7pdNfafg3Qc)
|
||||
|
||||
Everything is implemented with standard Qt functionality without any
|
||||
platform specific code. Basic usage of QWidgets an QLayouts and using basic
|
||||
platform specific code. Basic usage of QWidgets and QLayouts and using basic
|
||||
styles as much as possible.
|
||||
|
||||
This work is based on and inspired by the
|
||||
@@ -14,27 +20,42 @@ code quality, readibility and to fix all issues from the issue tracker
|
||||
of his docking system project.
|
||||
|
||||
## Features
|
||||
### Overview
|
||||
- [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)
|
||||
- [Docking inside floating windows](#docking-inside-floating-windows)
|
||||
- [Grouped dragging](#grouped-dragging)
|
||||
- [Perspectives for fast switching of the complete main window layout](#perspectives-for-fast-switching-of-the-complete-main-window-layout)
|
||||
- [Opaque and non-opaque splitter resizing](#opaque-and-non-opaque-splitter-resizing)
|
||||
- [Opaque and non-opaque undocking](#opaque-and-non-opaque-undocking)
|
||||
- [Tab-menu for easy handling of many tabbed dock widgets](#tab-menu-for-easy-handling-of-many-tabbed-dock-widgets)
|
||||
- [Many different ways to detach dock widgets](#many-different-ways-to-detach-dock-widgets)
|
||||
- [Supports deletion of dynamically created dock widgets](#supports-deletion-of-dynamically-created-dock-widgets)
|
||||
|
||||
### Docking everywhere - no central widget
|
||||
There is no central widget like in the Qt docking system. You can dock on every
|
||||
border of the main window or you can dock into each dock area - so you are
|
||||
free to dock almost everywhere.
|
||||
|
||||

|
||||
|
||||

|
||||
\
|
||||
\
|
||||

|
||||
|
||||
### Docking inside floating windows
|
||||
There is no difference between the main window and a floating window. Docking
|
||||
into floating windows is supported.
|
||||
|
||||

|
||||
\
|
||||
\
|
||||

|
||||
|
||||
### Grouped dragging
|
||||
When dragging the titlebar of a dock, all the tabs that are tabbed with it are
|
||||
going to be dragged. So you can move complete groups of tabbed widgets into
|
||||
a floating widget or from one dock area to another one.
|
||||
|
||||

|
||||
\
|
||||
\
|
||||

|
||||
|
||||
### Perspectives for fast switching of the complete main window layout
|
||||
A perspective defines the set and layout of dock windows in the main
|
||||
@@ -43,19 +64,162 @@ perspective to make your own custom perspective. Later you can simply
|
||||
select a perspective from the perspective list to quickly switch the complete
|
||||
main window layout.
|
||||
|
||||

|
||||
\
|
||||
\
|
||||

|
||||
|
||||
### Opaque and non-opaque splitter resizing
|
||||
The advanced docking system uses standard QSplitters as resize separators and thus supports opaque and non-opaque resizing functionality of QSplitter. In some rare cases, for very complex widgets or on slow machines resizing via separator on the fly may cause flicking and glaring of rendered content inside a widget. The global dock manager flag `OpaqueSplitterResize` configures the resizing behaviour of the splitters. If this flag is set, then widgets are resized dynamically (opaquely) while interactively moving the splitters.
|
||||
|
||||

|
||||
|
||||
If this flag is cleared, the widget resizing is deferred until the mouse button is released - this is some kind of lazy resizing separator.
|
||||
|
||||

|
||||
|
||||
### Opaque and non-opaque undocking
|
||||
By default, opaque undocking is active. That means, as soon as you drag a dock widget or a dock area with a number of dock widgets it will be undocked and moved into a floating widget and then the floating widget will be dragged around. That means undocking will take place immediatelly. You can compare this with opaque splitter resizing. If the flag `OpaqueUndocking` is cleared, then non-opaque undocking is active. In this mode, undocking is more like a standard drag and drop operation. That means, the dragged dock widget or dock area is not undocked immediatelly. Instead, a drag preview widget is created and dragged around to indicate the future position of the dock widget or dock area. The actual dock operation is only executed when the mouse button is released. That makes it possible, to cancel an active drag operation with the escape key.
|
||||
|
||||
The drag preview widget can be configured by a number of global dock manager flags:
|
||||
- `DragPreviewIsDynamic`: if this flag is enabled, the preview will be adjusted dynamically to the drop area
|
||||
- `DragPreviewShowsContentPixmap`: the created drag preview window shows a static copy of the content of the dock widget / dock are that is dragged
|
||||
- `DragPreviewHasWindowFrame`: this flag configures if the drag preview is frameless like a QRubberBand or looks like a real window
|
||||
|
||||
The best way to test non-opaque undocking is to set the standard flags: `CDockManager::setConfigFlags(CDockManager::DefaultNonOpaqueConfig)`.
|
||||
|
||||
### Tab-menu for easy handling of many tabbed dock widgets
|
||||
Tabs are a good way to quickly switch between dockwidgets in a dockarea. However, if the number of dockwidgets in a dockarea is too large, this may affect the usability of the tab bar. To keep track in this situation, you can use the tab menu. The menu allows you to quickly select the dockwidget you want to activate from a drop down menu.
|
||||
|
||||

|
||||
|
||||
### Many different ways to detach dock widgets
|
||||
You can detach dock widgets and also dock areas in the following ways:
|
||||
- by dragging the dock widget tab or the dock area title bar
|
||||
- by double clicking the tab or title bar
|
||||
- by using the detach menu entry from the tab and title bar drop down menu
|
||||
|
||||
### Supports deletion of dynamically created dock widgets
|
||||
Normally clicking the close button of a dock widget will just hide the widget and the user can show it again using the toggleView() action of the dock widget. This is meant for user interfaces with a static amount of widgets. But the advanced docking system also supports dynamic dock widgets that will get deleted on close. If you set the dock widget flag `DockWidgetDeleteOnClose` for a certain dock widget, then it will be deleted as soon as you close this dock widget. This enables the implementation of user interfaces with dynamically created editors, like in word processing applications or source code development tools.
|
||||
|
||||
## Tested Compatible Environments
|
||||
- Windows 10
|
||||
### Windows
|
||||
Windows 10 [](https://ci.appveyor.com/project/githubuser0xFFFF/qt-advanced-docking-system/branch/master)
|
||||
|
||||
The library was developed on and for Windows. It is used in a commercial Windows application and is therefore constantly tested.
|
||||
|
||||
### macOS
|
||||
macOS [](https://travis-ci.org/githubuser0xFFFF/Qt-Advanced-Docking-System)
|
||||
|
||||
The application can be compiled for macOS. A user reported, that the library works on macOS. If have not tested it.
|
||||
|
||||

|
||||
|
||||
### Linux
|
||||
Ubuntu [](https://travis-ci.org/githubuser0xFFFF/Qt-Advanced-Docking-System)
|
||||
[](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/actions?query=workflow%3Alinux-builds)
|
||||
|
||||
The application can be compiled for Linux and has been developed and tested with **Kubuntu 18.04** and **Kubuntu 19.10**.
|
||||
|
||||

|
||||
|
||||
and with **Ubuntu 19.10**
|
||||
|
||||

|
||||
|
||||
## Build
|
||||
Open the `ads.pro` with QtCreator and start the build, that's it.
|
||||
You can run the demo project and test it yourself.
|
||||
|
||||
## Getting started / Example
|
||||
The following example shows the minimum code required to use the advanced Qt docking system.
|
||||
|
||||
*MainWindow.h*
|
||||
|
||||
```cpp
|
||||
#include <QMainWindow>
|
||||
#include "DockManager.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
// The main container for docking
|
||||
ads::CDockManager* m_DockManager;
|
||||
};
|
||||
```
|
||||
*MainWindow.cpp*
|
||||
```cpp
|
||||
#include "MainWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Create the dock manager. Because the parent parameter is a QMainWindow
|
||||
// the dock manager registers itself as the central widget.
|
||||
m_DockManager = new ads::CDockManager(this);
|
||||
|
||||
// Create example content label - this can be any application specific
|
||||
// widget
|
||||
QLabel* l = new QLabel();
|
||||
l->setWordWrap(true);
|
||||
l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
|
||||
|
||||
// Create a dock widget with the title Label 1 and set the created label
|
||||
// as the dock widget content
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget("Label 1");
|
||||
DockWidget->setWidget(l);
|
||||
|
||||
// Add the toggleViewAction of the dock widget to the menu to give
|
||||
// the user the possibility to show the dock widget if it has been closed
|
||||
ui->menuView->addAction(DockWidget->toggleViewAction());
|
||||
|
||||
// Add the dock widget to the top dock widget area
|
||||
m_DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
```
|
||||
|
||||
## Developers
|
||||
- Uwe Kindler, Project Maintainer
|
||||
- Manuel Freiholz
|
||||
|
||||
## License information
|
||||
[](gnu-lgpl-v2.1.md)
|
||||
This project uses the [LGPLv2.1 license](gnu-lgpl-v2.1.md)
|
||||
|
||||
## Alternative Docking System Implementations
|
||||
If this Qt Advanced Docking System does not fit to your needs you may consider some of the alternative docking system solutions for Qt.
|
||||
|
||||
### KDDockWidgets
|
||||
This is an advanced docking framework for Qt from [KDAB](https://www.kdab.com/). The interesting thing is, that they separated GUI code from logic, so they can easily provide a QtQuick backend in the future.
|
||||
|
||||
- [Blog post about KDDockWidgets](https://www.kdab.com/kddockwidgets/)
|
||||
- [GitHub project](https://github.com/KDAB/KDDockWidgets)
|
||||
|
||||
|
||||
### QtitanDocking
|
||||
This is a commercial component from [Developer Machines](https://www.devmachines.com/) for Qt Framework that allows to create a Microsoft like dockable user interface. They also offer a lot of other interesting and useful components for Qt.
|
||||
|
||||
- [Product page](https://www.devmachines.com/qtitandocking-overview.html)
|
||||
|
||||
6
ads.pro
@@ -2,4 +2,8 @@ TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = \
|
||||
src \
|
||||
demo
|
||||
demo \
|
||||
example
|
||||
|
||||
demo.depends = src
|
||||
example.depends = src
|
||||
|
||||
5
adsConfig.cmake
Normal file
@@ -0,0 +1,5 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_dependency(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_dependency(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/adsTargets.cmake")
|
||||
316
demo.py
Normal file
@@ -0,0 +1,316 @@
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker,
|
||||
QRect)
|
||||
from PyQt5.QtGui import QGuiApplication
|
||||
from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel,
|
||||
QMenu, QTreeView, QAction, QWidgetAction,
|
||||
QComboBox, QStyle, QSizePolicy, QInputDialog)
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
from PyQtAds import QtAds
|
||||
|
||||
|
||||
class _State:
|
||||
label_count = 0
|
||||
calendar_count = 0
|
||||
file_system_count = 0
|
||||
|
||||
|
||||
def create_long_text_label_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
'''
|
||||
Create long text label dock widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
view_menu : QMenu
|
||||
|
||||
Returns
|
||||
-------
|
||||
value : QtAds.CDockWidget
|
||||
'''
|
||||
label = QLabel()
|
||||
label.setWordWrap(True)
|
||||
label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
label.setText('''\
|
||||
Label {} {} - Lorem ipsum dolor sit amet, consectetuer
|
||||
adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum
|
||||
sociis natoque penatibus et magnis dis parturient montes, nascetur
|
||||
ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium
|
||||
quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla
|
||||
vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut,
|
||||
imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis
|
||||
pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi.
|
||||
Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu,
|
||||
consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra
|
||||
quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
|
||||
'''.format(_State.label_count, str(datetime.datetime.now())))
|
||||
_State.label_count += 1
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count))
|
||||
dock_widget.setWidget(label)
|
||||
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_calendar_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
'''
|
||||
Create calendar dock widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
view_menu : QMenu
|
||||
|
||||
Returns
|
||||
-------
|
||||
value : QtAds.CDockWidget
|
||||
'''
|
||||
widget = QCalendarWidget()
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count))
|
||||
_State.calendar_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow)
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
def create_file_system_tree_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
|
||||
'''
|
||||
Create file system tree dock widget
|
||||
|
||||
Parameters
|
||||
----------
|
||||
view_menu : QMenu
|
||||
|
||||
Returns
|
||||
-------
|
||||
value : QtAds.CDockWidget
|
||||
'''
|
||||
widget = QTreeView()
|
||||
widget.setFrameShape(QFrame.NoFrame)
|
||||
|
||||
m = QFileSystemModel(widget)
|
||||
m.setRootPath(QDir.currentPath())
|
||||
widget.setModel(m)
|
||||
|
||||
dock_widget = QtAds.CDockWidget("Filesystem {}".format(_State.file_system_count))
|
||||
_State.file_system_count += 1
|
||||
dock_widget.setWidget(widget)
|
||||
view_menu.addAction(dock_widget.toggleViewAction())
|
||||
return dock_widget
|
||||
|
||||
|
||||
class MainWindow(QtWidgets.QMainWindow):
|
||||
save_perspective_action: QAction
|
||||
perspective_list_action: QWidgetAction
|
||||
perspective_combo_box: QComboBox
|
||||
dock_manager: QtAds.CDockManager
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.save_perspective_action = None
|
||||
self.perspective_list_action = None
|
||||
self.perspective_combo_box = None
|
||||
self.dock_manager = None
|
||||
|
||||
self.setup_ui()
|
||||
|
||||
self.dock_manager = QtAds.CDockManager(self)
|
||||
self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
|
||||
self.create_content()
|
||||
self.resize(800, 600)
|
||||
self.restore_state()
|
||||
self.restore_perspectives()
|
||||
|
||||
def setup_ui(self):
|
||||
self.setObjectName("MainWindow")
|
||||
self.resize(400, 300)
|
||||
self.setDockOptions(QtWidgets.QMainWindow.AllowTabbedDocks)
|
||||
self.centralWidget = QtWidgets.QWidget(self)
|
||||
self.centralWidget.setObjectName("centralWidget")
|
||||
self.setCentralWidget(self.centralWidget)
|
||||
self.status_bar = QtWidgets.QStatusBar(self)
|
||||
self.status_bar.setObjectName("statusBar")
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.menu_bar = QtWidgets.QMenuBar(self)
|
||||
self.menu_bar.setGeometry(QRect(0, 0, 400, 21))
|
||||
self.menu_bar.setObjectName("menuBar")
|
||||
self.menu_file = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_file.setObjectName("menuFile")
|
||||
self.menu_view = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_view.setObjectName("menuView")
|
||||
self.menu_about = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_about.setObjectName("menuAbout")
|
||||
self.setMenuBar(self.menu_bar)
|
||||
self.tool_bar = QtWidgets.QToolBar(self)
|
||||
self.tool_bar.setObjectName("toolBar")
|
||||
self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
|
||||
self.action_exit = QtWidgets.QAction(self)
|
||||
self.action_exit.setObjectName("actionExit")
|
||||
self.action_save_state = QtWidgets.QAction(self)
|
||||
self.action_save_state.setObjectName("actionSaveState")
|
||||
self.action_save_state.triggered.connect(self.saveState)
|
||||
|
||||
self.action_restore_state = QtWidgets.QAction(self)
|
||||
self.action_restore_state.setObjectName("actionRestoreState")
|
||||
self.action_restore_state.triggered.connect(self.restore_state)
|
||||
|
||||
self.menu_file.addAction(self.action_exit)
|
||||
self.menu_file.addAction(self.action_save_state)
|
||||
self.menu_file.addAction(self.action_restore_state)
|
||||
self.menu_bar.addAction(self.menu_file.menuAction())
|
||||
self.menu_bar.addAction(self.menu_view.menuAction())
|
||||
self.menu_bar.addAction(self.menu_about.menuAction())
|
||||
|
||||
self.setWindowTitle("MainWindow")
|
||||
self.menu_file.setTitle("File")
|
||||
self.menu_view.setTitle("View")
|
||||
self.menu_about.setTitle("About")
|
||||
self.tool_bar.setWindowTitle("toolBar")
|
||||
self.action_exit.setText("Exit")
|
||||
self.action_save_state.setText("Save State")
|
||||
self.action_restore_state.setText("Restore State")
|
||||
self.create_actions()
|
||||
|
||||
def create_actions(self):
|
||||
'''
|
||||
Creates the toolbar actions
|
||||
'''
|
||||
self.tool_bar.addAction(self.action_save_state)
|
||||
self.action_save_state.setIcon(self.style().standardIcon(QStyle.SP_DialogSaveButton))
|
||||
self.tool_bar.addAction(self.action_restore_state)
|
||||
self.action_restore_state.setIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton))
|
||||
self.save_perspective_action = QAction("Save Perspective", self)
|
||||
self.save_perspective_action.triggered.connect(self.save_perspective)
|
||||
|
||||
self.perspective_list_action = QWidgetAction(self)
|
||||
self.perspective_combo_box = QComboBox(self)
|
||||
self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
||||
self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
||||
self.perspective_list_action.setDefaultWidget(self.perspective_combo_box)
|
||||
self.tool_bar.addSeparator()
|
||||
self.tool_bar.addAction(self.perspective_list_action)
|
||||
self.tool_bar.addAction(self.save_perspective_action)
|
||||
|
||||
def create_content(self):
|
||||
'''
|
||||
Fill the dock manager with dock widgets
|
||||
'''
|
||||
# Test container docking
|
||||
view_menu = self.menu_view
|
||||
dock_widget = create_calendar_dock_widget(view_menu)
|
||||
dock_widget.setIcon(self.style().standardIcon(QStyle.SP_DialogOpenButton))
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
|
||||
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
|
||||
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, create_long_text_label_dock_widget(view_menu))
|
||||
file_system_widget = create_file_system_tree_dock_widget(view_menu)
|
||||
tool_bar = file_system_widget.createDefaultToolBar()
|
||||
tool_bar.addAction(self.action_save_state)
|
||||
tool_bar.addAction(self.action_restore_state)
|
||||
self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget)
|
||||
file_system_widget = create_file_system_tree_dock_widget(view_menu)
|
||||
tool_bar = file_system_widget.createDefaultToolBar()
|
||||
tool_bar.addAction(self.action_save_state)
|
||||
tool_bar.addAction(self.action_restore_state)
|
||||
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
|
||||
top_dock_area = self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, file_system_widget)
|
||||
dock_widget = create_calendar_dock_widget(view_menu)
|
||||
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
|
||||
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
|
||||
self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
|
||||
|
||||
# Test dock area docking
|
||||
right_dock_area = self.dock_manager.addDockWidget(
|
||||
QtAds.RightDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), top_dock_area)
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.TopDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
|
||||
bottom_dock_area = self.dock_manager.addDockWidget(
|
||||
QtAds.BottomDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.RightDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), right_dock_area)
|
||||
self.dock_manager.addDockWidget(
|
||||
QtAds.CenterDockWidgetArea,
|
||||
create_long_text_label_dock_widget(view_menu), bottom_dock_area)
|
||||
|
||||
def save_state(self):
|
||||
'''
|
||||
Saves the dock manager state and the main window geometry
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
settings.setValue("mainWindow/Geometry", self.saveGeometry())
|
||||
settings.setValue("mainWindow/State", self.saveState())
|
||||
settings.setValue("mainWindow/DockingState", self.dock_manager.saveState())
|
||||
|
||||
def save_perspectives(self):
|
||||
'''
|
||||
Save the list of perspectives
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
self.dock_manager.savePerspectives(settings)
|
||||
|
||||
def restore_state(self):
|
||||
'''
|
||||
Restores the dock manager state
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
geom = settings.value("mainWindow/Geometry")
|
||||
if geom is not None:
|
||||
self.restoreGeometry(geom)
|
||||
|
||||
state = settings.value("mainWindow/State")
|
||||
if state is not None:
|
||||
self.restoreState(state)
|
||||
|
||||
state = settings.value("mainWindow/DockingState")
|
||||
if state is not None:
|
||||
self.dock_manager.restore_state(state)
|
||||
|
||||
def restore_perspectives(self):
|
||||
'''
|
||||
Restore the perspective listo of the dock manager
|
||||
'''
|
||||
settings = QSettings("Settings.ini", QSettings.IniFormat)
|
||||
self.dock_manager.loadPerspectives(settings)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
|
||||
def save_perspective(self):
|
||||
perspective_name, ok = QInputDialog.getText(self, 'Save perspective', 'Enter unique name:')
|
||||
if ok and perspective_name:
|
||||
self.dock_manager.addPerspective(perspective_name)
|
||||
_ = QSignalBlocker(self.perspective_combo_box)
|
||||
self.perspective_combo_box.clear()
|
||||
self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
|
||||
self.perspective_combo_box.setCurrentText(perspective_name)
|
||||
self.save_perspectives()
|
||||
|
||||
|
||||
def main(app_):
|
||||
main_window = MainWindow()
|
||||
main_window.show()
|
||||
state = main_window.dock_manager.saveState()
|
||||
# print('This is what the saved state looks like in XML:')
|
||||
# print(str(state, 'utf-8'))
|
||||
# print()
|
||||
# main_window.dock_manager.restore_state(state)
|
||||
return main_window
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# logging.basicConfig(level='DEBUG')
|
||||
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
||||
QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
||||
app = QtWidgets.QApplication([])
|
||||
window = main(app)
|
||||
window.show()
|
||||
app.exec_()
|
||||
54
demo/CMakeLists.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
project(ads_demo VERSION "1.0")
|
||||
set(REQUIRED_QT_VERSION 5.5.0)
|
||||
find_package(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_package(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
set(ads_demo_LIBS ${ads_demo_LIBS} ${Qt5Core_LIBRARIES})
|
||||
set(ads_demo_INCLUDE ${ads_demo_INCLUDE} ${Qt5Core_INCLUDE_DIRS})
|
||||
set(ads_demo_COMPILE_DEFINE ${ads_demo_COMPILE_DEFINE} ${Qt5Core_COMPILE_DEFINITIONS} )
|
||||
set(ads_demo_LIBS ${ads_demo_LIBS} ${Qt5Gui_LIBRARIES})
|
||||
set(ads_demo_INCLUDE ${ads_demo_INCLUDE} ${Qt5Gui_INCLUDE_DIRS})
|
||||
set(ads_demo_COMPILE_DEFINE ${ads_demo_COMPILE_DEFINE} ${Qt5Gui_COMPILE_DEFINITIONS})
|
||||
set(ads_demo_LIBS ${ads_demo_LIBS} ${Qt5Widgets_LIBRARIES})
|
||||
set(ads_demo_INCLUDE ${ads_demo_INCLUDE} ${Qt5Widgets_INCLUDE_DIRS})
|
||||
set(ads_demo_COMPILE_DEFINE ${ads_demo_COMPILE_DEFINE} ${Qt5Widgets_COMPILE_DEFINITIONS})
|
||||
if(WIN32)
|
||||
find_package(Qt5AxContainer ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
set(ads_demo_LIBS ${ads_demo_LIBS} ${Qt5AxContainer_LIBRARIES})
|
||||
set(ads_demo_INCLUDE ${ads_demo_INCLUDE} ${Qt5AxContainer_INCLUDE_DIRS})
|
||||
set(ads_demo_COMPILE_DEFINE ${ads_demo_COMPILE_DEFINE} ${Qt5AxContainer_COMPILE_DEFINITIONS})
|
||||
endif()
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(ads_demo_SRCS
|
||||
main.cpp
|
||||
MainWindow.cpp
|
||||
mainwindow.ui
|
||||
demo.qrc
|
||||
)
|
||||
add_executable(AdvancedDockingSystemDemo WIN32 ${ads_demo_SRCS})
|
||||
if(BUILD_STATIC)
|
||||
set(ads_demo_DEFINE ${ads_demo_DEFINE} ADS_STATIC)
|
||||
endif()
|
||||
add_dependencies(AdvancedDockingSystemDemo qtadvanceddocking)
|
||||
target_include_directories(AdvancedDockingSystemDemo PUBLIC
|
||||
$<BUILD_INTERFACE:${ads_demo_INCLUDE}>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
target_include_directories(AdvancedDockingSystemDemo PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src" ${ads_demo_INCLUDE})
|
||||
target_link_libraries(AdvancedDockingSystemDemo PRIVATE qtadvanceddocking ${ads_demo_LIBS})
|
||||
target_compile_definitions(AdvancedDockingSystemDemo PRIVATE ${ads_demo_DEFINE})
|
||||
set_target_properties(AdvancedDockingSystemDemo PROPERTIES
|
||||
VERSION "1.0"
|
||||
SOVERSION 1
|
||||
EXPORT_NAME "Qt Advanced Docking System Demo"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
|
||||
)
|
||||
@@ -50,6 +50,16 @@
|
||||
#include <QWidgetAction>
|
||||
#include <QComboBox>
|
||||
#include <QInputDialog>
|
||||
#include <QRubberBand>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QTableWidget>
|
||||
#include <QScreen>
|
||||
#include <QStyle>
|
||||
#include <QMessageBox>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QAxWidget>
|
||||
#endif
|
||||
|
||||
#include <QMap>
|
||||
#include <QElapsedTimer>
|
||||
@@ -57,6 +67,7 @@
|
||||
#include "DockManager.h"
|
||||
#include "DockWidget.h"
|
||||
#include "DockAreaWidget.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
|
||||
|
||||
//============================================================================
|
||||
@@ -88,6 +99,44 @@ static ads::CDockWidget* createLongTextLabelDockWidget(QMenu* ViewMenu)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function returns a features string with closable (c), movable (m) and floatable (f)
|
||||
* features. i.e. The following string is for a not closable but movable and floatable
|
||||
* widget: c- m+ f+
|
||||
*/
|
||||
static QString featuresString(ads::CDockWidget* DockWidget)
|
||||
{
|
||||
auto f = DockWidget->features();
|
||||
return QString("c%1 m%2 f%3")
|
||||
.arg(f.testFlag(ads::CDockWidget::DockWidgetClosable) ? "+" : "-")
|
||||
.arg(f.testFlag(ads::CDockWidget::DockWidgetMovable) ? "+" : "-")
|
||||
.arg(f.testFlag(ads::CDockWidget::DockWidgetFloatable) ? "+" : "-");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the string returned by featuresString() to the window title of
|
||||
* the given DockWidget
|
||||
*/
|
||||
static void appendFeaturStringToWindowTitle(ads::CDockWidget* DockWidget)
|
||||
{
|
||||
DockWidget->setWindowTitle(DockWidget->windowTitle()
|
||||
+ QString(" (%1)").arg(featuresString(DockWidget)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create an SVG icon
|
||||
*/
|
||||
static QIcon svgIcon(const QString& File)
|
||||
{
|
||||
// This is a workaround, because because in item views SVG icons are not
|
||||
// properly scaled an look blurry or pixelate
|
||||
QIcon SvgIcon(File);
|
||||
SvgIcon.addPixmap(SvgIcon.pixmap(92));
|
||||
return SvgIcon;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
static ads::CDockWidget* createCalendarDockWidget(QMenu* ViewMenu)
|
||||
{
|
||||
@@ -96,6 +145,7 @@ static ads::CDockWidget* createCalendarDockWidget(QMenu* ViewMenu)
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
|
||||
DockWidget->setWidget(w);
|
||||
DockWidget->setToggleViewActionMode(ads::CDockWidget::ActionModeShow);
|
||||
DockWidget->setIcon(svgIcon(":/adsdemo/images/date_range.svg"));
|
||||
ViewMenu->addAction(DockWidget->toggleViewAction());
|
||||
return DockWidget;
|
||||
}
|
||||
@@ -110,12 +160,67 @@ static ads::CDockWidget* createFileSystemTreeDockWidget(QMenu* ViewMenu)
|
||||
QFileSystemModel* m = new QFileSystemModel(w);
|
||||
m->setRootPath(QDir::currentPath());
|
||||
w->setModel(m);
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1").arg(FileSystemCount++));
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1")
|
||||
.arg(FileSystemCount++));
|
||||
DockWidget->setWidget(w);
|
||||
ViewMenu->addAction(DockWidget->toggleViewAction());
|
||||
return DockWidget;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
static ads::CDockWidget* createEditorWidget(QMenu* ViewMenu)
|
||||
{
|
||||
static int EditorCount = 0;
|
||||
QPlainTextEdit* w = new QPlainTextEdit();
|
||||
w->setPlaceholderText("This is an editor. If you close the editor, it will be "
|
||||
"deleted. Enter your text here.");
|
||||
w->setStyleSheet("border: none");
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Editor %1").arg(EditorCount++));
|
||||
DockWidget->setWidget(w);
|
||||
DockWidget->setIcon(svgIcon(":/adsdemo/images/edit.svg"));
|
||||
DockWidget->setFeature(ads::CDockWidget::CustomCloseHandling, true);
|
||||
ViewMenu->addAction(DockWidget->toggleViewAction());
|
||||
return DockWidget;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
static ads::CDockWidget* createTableWidget(QMenu* ViewMenu)
|
||||
{
|
||||
static int TableCount = 0;
|
||||
QTableWidget* w = new QTableWidget();
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Table %1").arg(TableCount++));
|
||||
static int colCount = 5;
|
||||
static int rowCount = 30;
|
||||
w->setColumnCount(colCount);
|
||||
w->setRowCount(rowCount);
|
||||
for (int col = 0; col < colCount; ++col)
|
||||
{
|
||||
w->setHorizontalHeaderItem(col, new QTableWidgetItem(QString("Col %1").arg(col+1)));
|
||||
for (int row = 0; row < rowCount; ++row)
|
||||
{
|
||||
w->setItem(row, col, new QTableWidgetItem(QString("T %1-%2").arg(row + 1).arg(col+1)));
|
||||
}
|
||||
}
|
||||
DockWidget->setWidget(w);
|
||||
DockWidget->setIcon(svgIcon(":/adsdemo/images/grid_on.svg"));
|
||||
ViewMenu->addAction(DockWidget->toggleViewAction());
|
||||
return DockWidget;
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
//============================================================================
|
||||
static ads::CDockWidget* createActiveXWidget(QMenu* ViewMenu, QWidget* parent = nullptr)
|
||||
{
|
||||
static int ActiveXCount = 0;
|
||||
QAxWidget* w = new QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent);
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Active X %1").arg(ActiveXCount++));
|
||||
DockWidget->setWidget(w);
|
||||
ViewMenu->addAction(DockWidget->toggleViewAction());
|
||||
return DockWidget;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//============================================================================
|
||||
/**
|
||||
@@ -127,7 +232,7 @@ struct MainWindowPrivate
|
||||
Ui::MainWindow ui;
|
||||
QAction* SavePerspectiveAction = nullptr;
|
||||
QWidgetAction* PerspectiveListAction = nullptr;
|
||||
QComboBox* PerspectiveComboBox = nullptr;;
|
||||
QComboBox* PerspectiveComboBox = nullptr;
|
||||
ads::CDockManager* DockManager = nullptr;
|
||||
|
||||
MainWindowPrivate(CMainWindow* _public) : _this(_public) {}
|
||||
@@ -170,25 +275,50 @@ void MainWindowPrivate::createContent()
|
||||
// Test container docking
|
||||
QMenu* ViewMenu = ui.menuView;
|
||||
auto DockWidget = createCalendarDockWidget(ViewMenu);
|
||||
DockWidget->setIcon(_this->style()->standardIcon(QStyle::SP_DialogOpenButton));
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
|
||||
DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
|
||||
DockManager->addDockWidget(ads::LeftDockWidgetArea, createLongTextLabelDockWidget(ViewMenu));
|
||||
DockManager->addDockWidget(ads::BottomDockWidgetArea, createFileSystemTreeDockWidget(ViewMenu));
|
||||
|
||||
auto FileSystemWidget = createFileSystemTreeDockWidget(ViewMenu);
|
||||
auto ToolBar = FileSystemWidget->createDefaultToolBar();
|
||||
ToolBar->addAction(ui.actionSaveState);
|
||||
ToolBar->addAction(ui.actionRestoreState);
|
||||
DockManager->addDockWidget(ads::BottomDockWidgetArea, FileSystemWidget);
|
||||
|
||||
FileSystemWidget = createFileSystemTreeDockWidget(ViewMenu);
|
||||
ToolBar = FileSystemWidget->createDefaultToolBar();
|
||||
ToolBar->addAction(ui.actionSaveState);
|
||||
ToolBar->addAction(ui.actionRestoreState);
|
||||
FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetMovable, false);
|
||||
FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetFloatable, false);
|
||||
appendFeaturStringToWindowTitle(FileSystemWidget);
|
||||
auto TopDockArea = DockManager->addDockWidget(ads::TopDockWidgetArea, FileSystemWidget);
|
||||
DockWidget = createCalendarDockWidget(ViewMenu);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
|
||||
DockWidget->setTabToolTip(QString("Tab ToolTip\nHodie est dies magna"));
|
||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, TopDockArea);
|
||||
|
||||
// Test dock area docking
|
||||
auto RighDockArea = DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), TopDockArea);
|
||||
DockManager->addDockWidget(ads::TopDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
|
||||
auto BottomDockArea = DockManager->addDockWidget(ads::BottomDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
|
||||
DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
|
||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
|
||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), BottomDockArea);
|
||||
|
||||
auto Action = ui.menuView->addAction(QString("Set %1 floating").arg(DockWidget->windowTitle()));
|
||||
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setFloating()));
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (!DockManager->configFlags().testFlag(ads::CDockManager::OpaqueUndocking))
|
||||
{
|
||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, createActiveXWidget(ViewMenu), RighDockArea);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto DockWidget : DockManager->dockWidgetsMap())
|
||||
{
|
||||
_this->connect(DockWidget, SIGNAL(viewToggled(bool)), SLOT(onViewToggled(bool)));
|
||||
_this->connect(DockWidget, SIGNAL(visibilityChanged(bool)), SLOT(onViewVisibilityChanged(bool)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,11 +326,13 @@ void MainWindowPrivate::createContent()
|
||||
void MainWindowPrivate::createActions()
|
||||
{
|
||||
ui.toolBar->addAction(ui.actionSaveState);
|
||||
ui.actionSaveState->setIcon(_this->style()->standardIcon(QStyle::SP_DialogSaveButton));
|
||||
ui.toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
||||
ui.actionSaveState->setIcon(svgIcon(":/adsdemo/images/save.svg"));
|
||||
ui.toolBar->addAction(ui.actionRestoreState);
|
||||
ui.actionRestoreState->setIcon(_this->style()->standardIcon(QStyle::SP_DialogOpenButton));
|
||||
ui.actionRestoreState->setIcon(svgIcon(":/adsdemo/images/restore.svg"));
|
||||
|
||||
SavePerspectiveAction = new QAction("Save Perspective", _this);
|
||||
SavePerspectiveAction = new QAction("Create Perspective", _this);
|
||||
SavePerspectiveAction->setIcon(svgIcon(":/adsdemo/images/picture_in_picture.svg"));
|
||||
_this->connect(SavePerspectiveAction, SIGNAL(triggered()), SLOT(savePerspective()));
|
||||
PerspectiveListAction = new QWidgetAction(_this);
|
||||
PerspectiveComboBox = new QComboBox(_this);
|
||||
@@ -210,6 +342,16 @@ void MainWindowPrivate::createActions()
|
||||
ui.toolBar->addSeparator();
|
||||
ui.toolBar->addAction(PerspectiveListAction);
|
||||
ui.toolBar->addAction(SavePerspectiveAction);
|
||||
|
||||
QAction* a = ui.toolBar->addAction("Create Editor");
|
||||
a->setToolTip("Creates floating dynamic dockable editor windows that are deleted on close");
|
||||
a->setIcon(svgIcon(":/adsdemo/images/note_add.svg"));
|
||||
_this->connect(a, SIGNAL(triggered()), SLOT(createEditor()));
|
||||
|
||||
a = ui.toolBar->addAction("Create Table");
|
||||
a->setToolTip("Creates floating dynamic dockable table with millions of entries");
|
||||
a->setIcon(svgIcon(":/adsdemo/images/grid_on.svg"));
|
||||
_this->connect(a, SIGNAL(triggered()), SLOT(createTable()));
|
||||
}
|
||||
|
||||
|
||||
@@ -258,19 +400,42 @@ CMainWindow::CMainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
d(new MainWindowPrivate(this))
|
||||
{
|
||||
using namespace ads;
|
||||
d->ui.setupUi(this);
|
||||
d->createActions();
|
||||
|
||||
// uncomment the following line if the tab close button should be
|
||||
// a QToolButton instead of a QPushButton
|
||||
// CDockManager::setConfigFlags(CDockManager::configFlags() | CDockManager::TabCloseButtonIsToolButton);
|
||||
|
||||
// comment the following line if you want to use opaque undocking and
|
||||
// opaque splitter resizing
|
||||
CDockManager::setConfigFlags(CDockManager::DefaultNonOpaqueConfig);
|
||||
|
||||
// uncomment the following line if you want a fixed tab width that does
|
||||
// not change if the visibility of the close button changes
|
||||
//CDockManager::setConfigFlag(CDockManager::RetainTabSizeWhenCloseButtonHidden, true);
|
||||
|
||||
|
||||
// Now create the dock manager and its content
|
||||
d->DockManager = new ads::CDockManager(this);
|
||||
d->DockManager = new CDockManager(this);
|
||||
|
||||
// uncomment the following line to have the old style where the dock
|
||||
// area close button closes the active tab
|
||||
// CDockManager::setConfigFlags({CDockManager::DockAreaHasCloseButton
|
||||
// | CDockManager::DockAreaCloseButtonClosesTab});
|
||||
connect(d->PerspectiveComboBox, SIGNAL(activated(const QString&)),
|
||||
d->DockManager, SLOT(openPerspective(const QString&)));
|
||||
|
||||
d->createContent();
|
||||
// Default window geometry
|
||||
resize(800, 600);
|
||||
// Default window geometry - center on screen
|
||||
resize(1280, 720);
|
||||
setGeometry(QStyle::alignedRect(
|
||||
Qt::LeftToRight, Qt::AlignCenter, frameSize(),
|
||||
QGuiApplication::primaryScreen()->availableGeometry()
|
||||
));
|
||||
|
||||
d->restoreState();
|
||||
//d->restoreState();
|
||||
d->restorePerspectives();
|
||||
}
|
||||
|
||||
@@ -309,7 +474,6 @@ void CMainWindow::on_actionRestoreState_triggered(bool)
|
||||
//============================================================================
|
||||
void CMainWindow::savePerspective()
|
||||
{
|
||||
std::cout << "savePerspective" << std::endl;
|
||||
QString PerspectiveName = QInputDialog::getText(this, "Save Perspective", "Enter unique name:");
|
||||
if (PerspectiveName.isEmpty())
|
||||
{
|
||||
@@ -325,3 +489,64 @@ void CMainWindow::savePerspective()
|
||||
d->savePerspectives();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CMainWindow::onViewToggled(bool Open)
|
||||
{
|
||||
auto DockWidget = qobject_cast<ads::CDockWidget*>(sender());
|
||||
if (!DockWidget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")";
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CMainWindow::onViewVisibilityChanged(bool Visible)
|
||||
{
|
||||
auto DockWidget = qobject_cast<ads::CDockWidget*>(sender());
|
||||
if (!DockWidget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << DockWidget->objectName() << " visibilityChanged(" << Visible << ")";
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CMainWindow::createEditor()
|
||||
{
|
||||
auto DockWidget = createEditorWidget(d->ui.menuView);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
|
||||
auto FloatingWidget = d->DockManager->addDockWidgetFloating(DockWidget);
|
||||
FloatingWidget->move(QPoint(20, 20));
|
||||
connect(DockWidget, SIGNAL(closeRequested()), SLOT(onEditorCloseRequested()));
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CMainWindow::onEditorCloseRequested()
|
||||
{
|
||||
auto DockWidget = qobject_cast<ads::CDockWidget*>(sender());
|
||||
int Result = QMessageBox::question(this, "Close Editor", QString("Editor %1 "
|
||||
"contains unsaved changes? Would you like to close it?")
|
||||
.arg(DockWidget->windowTitle()));
|
||||
if (QMessageBox::Yes == Result)
|
||||
{
|
||||
DockWidget->closeDockWidget();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CMainWindow::createTable()
|
||||
{
|
||||
auto DockWidget = createTableWidget(d->ui.menuView);
|
||||
DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
|
||||
auto FloatingWidget = d->DockManager->addDockWidgetFloating(DockWidget);
|
||||
FloatingWidget->move(QPoint(40, 40));
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,11 @@ private slots:
|
||||
void on_actionSaveState_triggered(bool);
|
||||
void on_actionRestoreState_triggered(bool);
|
||||
void savePerspective();
|
||||
void onViewToggled(bool Open);
|
||||
void onViewVisibilityChanged(bool Visible);
|
||||
void createEditor();
|
||||
void createTable();
|
||||
void onEditorCloseRequested();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
@@ -1,29 +1,51 @@
|
||||
ADS_ROOT = $${PWD}/..
|
||||
ADS_OUT_ROOT = $${OUT_PWD}/..
|
||||
|
||||
TARGET = AdvancedDockingSystemDemo
|
||||
DESTDIR = $${ADS_OUT_ROOT}/lib
|
||||
QT += core gui widgets
|
||||
CONFIG *= c++14
|
||||
|
||||
win32 {
|
||||
QT += axcontainer
|
||||
}
|
||||
|
||||
CONFIG += c++14
|
||||
CONFIG += debug_and_release
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
adsBuildStatic {
|
||||
DEFINES += ADS_STATIC
|
||||
}
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
MainWindow.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
MainWindow.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
RESOURCES += demo.qrc
|
||||
|
||||
|
||||
LIBS += -L$${ADS_OUT_ROOT}/lib
|
||||
|
||||
# Dependency: AdvancedDockingSystem (shared)
|
||||
win32:CONFIG(release, debug|release): LIBS += -lAdvancedDockingSystem
|
||||
else:win32:CONFIG(debug, debug|release): LIBS += -lAdvancedDockingSystemd
|
||||
else:unix: LIBS += -lAdvancedDockingSystem
|
||||
CONFIG(debug, debug|release){
|
||||
win32 {
|
||||
LIBS += -lqtadvanceddockingd
|
||||
}
|
||||
else:mac {
|
||||
LIBS += -lqtadvanceddocking_debug
|
||||
}
|
||||
else {
|
||||
LIBS += -lqtadvanceddocking
|
||||
}
|
||||
}
|
||||
else{
|
||||
LIBS += -lqtadvanceddocking
|
||||
}
|
||||
|
||||
INCLUDEPATH += ../src
|
||||
DEPENDPATH += ../src
|
||||
|
||||
13
demo/demo.qrc
Normal file
@@ -0,0 +1,13 @@
|
||||
<RCC>
|
||||
<qresource prefix="/adsdemo">
|
||||
<file>images/folder.svg</file>
|
||||
<file>images/folder_open.svg</file>
|
||||
<file>images/note_add.svg</file>
|
||||
<file>images/picture_in_picture.svg</file>
|
||||
<file>images/restore.svg</file>
|
||||
<file>images/save.svg</file>
|
||||
<file>images/date_range.svg</file>
|
||||
<file>images/edit.svg</file>
|
||||
<file>images/grid_on.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
6
demo/images/date_range.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>date_range icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M896,256v597.33c0,46.93 -38.4,85.34 -85.33,85.34h-597.34c-47.36,0 -85.33,-38.41 -85.33,-85.34l0.43,-597.33c0,-46.93 37.54,-85.33 84.9,-85.33h42.67v-85.34h85.33v85.34h341.34v-85.34h85.33v85.34h42.67c46.93,0 85.33,38.4 85.33,85.33zM810.67,384h-597.34v469.33h597.34zM384,554.67h-85.33v-85.34h85.33zM554.67,554.67h-85.34v-85.34h85.34zM725.33,554.67h-85.33v-85.34h85.33z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 783 B |
6
demo/images/edit.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>create icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M599.89,264.11l160,160l-471.89,471.89h-160v-160zM805.55,378.45l-160,-160l78.08,-78.08c16.64,-16.64 43.52,-16.64 60.16,0l99.84,99.84c16.64,16.64 16.64,43.52 0,60.16z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 578 B |
6
demo/images/folder.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>folder icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M512,256h341.33c46.93,0 85.34,38.4 85.34,85.33v426.67c0,46.93 -38.41,85.33 -85.34,85.33h-682.66c-46.93,0 -85.34,-38.4 -85.34,-85.33l0.43,-512c0,-46.93 37.98,-85.33 84.91,-85.33h256z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 595 B |
6
demo/images/folder_open.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>folder_open icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M938.67,341.33v426.67c0,46.93 -38.41,85.33 -85.34,85.33h-682.66c-46.93,0 -85.34,-38.4 -85.34,-85.33l0.43,-512c0,-46.93 37.98,-85.33 84.91,-85.33h256l85.33,85.33h341.33c46.93,0 85.34,38.4 85.34,85.33zM853.33,341.33h-682.66v426.67h682.66z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 655 B |
6
demo/images/grid_on.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>grid_on icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M938.67,170.67v682.66c0,46.93 -38.41,85.34 -85.34,85.34h-682.66c-46.93,0 -85.34,-38.41 -85.34,-85.34v-682.66c0,-46.93 38.41,-85.34 85.34,-85.34h682.66c46.93,0 85.34,38.41 85.34,85.34zM341.33,170.67h-170.66v170.66h170.66zM341.33,682.67h-170.66v170.66h170.66zM341.33,426.67h-170.66v170.66h170.66zM597.33,170.67h-170.66v170.66h170.66zM853.33,170.67h-170.66v170.66h170.66zM597.33,682.67h-170.66v170.66h170.66zM597.33,426.67h-170.66v170.66h170.66zM853.33,682.67h-170.66v170.66h170.66zM853.33,426.67h-170.66v170.66h170.66z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 931 B |
211
demo/images/material_icons_license.txt
Normal file
@@ -0,0 +1,211 @@
|
||||
The Google Material icons and modifications can be used free of charge for
|
||||
commerical and non-commerical projects according to the Apache License 2.0.
|
||||
|
||||
An attribution to https://material.io/icons/ and/or https://iconfu.com on
|
||||
your website or in your app's "about" screen would be wonderful.
|
||||
|
||||
Please do not re-sell the icons.
|
||||
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
6
demo/images/note_add.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>note_add icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M853.33,341.33v512c0,46.93 -38.4,85.34 -85.33,85.34h-512.43c-46.93,0 -84.9,-38.41 -84.9,-85.34l0.42,-682.66c0,-46.93 37.98,-85.34 84.91,-85.34h341.33zM682.67,597.33h-128v-128h-85.34v128h-128v85.34h128v128h85.34v-128h128zM789.33,384l-234.66,-234.67v234.67z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 671 B |
6
demo/images/picture_in_picture.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>picture_in_picture icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M981.33,213.33v597.34c0,46.93 -38.4,84.48 -85.33,84.48h-768c-46.93,0 -85.33,-37.55 -85.33,-84.48v-597.34c0,-46.93 38.4,-85.33 85.33,-85.33h768c46.93,0 85.33,38.4 85.33,85.33zM896,212.48h-768v598.61h768zM810.67,554.67h-341.34v-256h341.34z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 663 B |
6
demo/images/restore.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>restore icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M938.67,512c0,212.05 -171.95,384 -384,384c-106.24,0 -201.81,-43.09 -271.36,-112.64l60.58,-60.59c53.76,54.19 128.43,87.9 210.78,87.9c165.12,0 298.66,-133.55 298.66,-298.67c0,-165.12 -133.54,-298.67 -298.66,-298.67c-165.12,0 -298.67,133.55 -298.67,298.67h128l-172.37,171.95l-2.99,-5.98l-165.97,-165.97h128c0,-212.05 171.95,-384 384,-384c212.05,0 384,171.95 384,384zM576,341.33v181.34l149.33,88.74l-30.72,51.63l-182.61,-108.37v-213.34z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 847 B |
6
demo/images/save.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0,0,1024,1024">
|
||||
<desc>save icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.)</desc>
|
||||
<g fill="#03b8e5" fill-rule="nonzero" style="mix-blend-mode: normal">
|
||||
<path d="M896,298.67v512c0,46.93 -38.4,85.33 -85.33,85.33h-597.34c-47.36,0 -85.33,-38.4 -85.33,-85.33v-597.34c0,-46.93 37.97,-85.33 85.33,-85.33h512zM640,213.33h-426.67v170.67h426.67zM640,682.67c0,-70.83 -57.17,-128 -128,-128c-70.83,0 -128,57.17 -128,128c0,70.83 57.17,128 128,128c70.83,0 128,-57.17 128,-128z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 712 B |
@@ -35,6 +35,10 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#if QT_VERSION >= 0x050600
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
std::shared_ptr<int> b;
|
||||
QApplication a(argc, argv);
|
||||
a.setQuitOnLastWindowClosed(true);
|
||||
|
||||
BIN
doc/TabMenu.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
doc/TabMenu_dark.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
doc/advanced-docking_video.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
doc/floating-widget-dragndrop.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
doc/floating-widget-dragndrop_dark.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
doc/grouped-dragging.gif
Normal file
|
After Width: | Height: | Size: 523 KiB |
BIN
doc/grouped-dragging.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
doc/grouped-dragging_dark.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
doc/linux_kubuntu_1804.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
doc/linux_ubuntu_1910.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
doc/macos.png
Normal file
|
After Width: | Height: | Size: 571 KiB |
BIN
doc/non_opaque_resizing.gif
Normal file
|
After Width: | Height: | Size: 322 KiB |
BIN
doc/opaque_resizing.gif
Normal file
|
After Width: | Height: | Size: 389 KiB |
BIN
doc/perspectives.gif
Normal file
|
After Width: | Height: | Size: 316 KiB |
BIN
doc/perspectives.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
doc/perspectives_dark.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
doc/preview-dragndrop.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
doc/preview-dragndrop_dark.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
doc/preview_dark.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
doc/tab_menu.gif
Normal file
|
After Width: | Height: | Size: 311 KiB |
46
example/CMakeLists.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
project(ads_example VERSION "1.0")
|
||||
set(REQUIRED_QT_VERSION 5.5.0)
|
||||
find_package(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_package(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
find_package(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
|
||||
set(ads_example_LIBS ${ads_example_LIBS} ${Qt5Core_LIBRARIES})
|
||||
set(ads_example_INCLUDE ${ads_example_INCLUDE} ${Qt5Core_INCLUDE_DIRS})
|
||||
set(ads_example_COMPILE_DEFINE ${ads_example_COMPILE_DEFINE} ${Qt5Core_COMPILE_DEFINITIONS} )
|
||||
set(ads_example_LIBS ${ads_example_LIBS} ${Qt5Gui_LIBRARIES})
|
||||
set(ads_example_INCLUDE ${ads_example_INCLUDE} ${Qt5Gui_INCLUDE_DIRS})
|
||||
set(ads_example_COMPILE_DEFINE ${ads_example_COMPILE_DEFINE} ${Qt5Gui_COMPILE_DEFINITIONS})
|
||||
set(ads_example_LIBS ${ads_example_LIBS} ${Qt5Widgets_LIBRARIES})
|
||||
set(ads_example_INCLUDE ${ads_example_INCLUDE} ${Qt5Widgets_INCLUDE_DIRS})
|
||||
set(ads_example_COMPILE_DEFINE ${ads_example_COMPILE_DEFINE} ${Qt5Widgets_COMPILE_DEFINITIONS})
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(ads_example_SRCS
|
||||
main.cpp
|
||||
MainWindow.cpp
|
||||
MainWindow.ui
|
||||
)
|
||||
add_executable(Example1 WIN32 ${ads_example_SRCS})
|
||||
if(BUILD_STATIC)
|
||||
set(ads_example_DEFINE ${ads_example_DEFINE} ADS_STATIC)
|
||||
endif()
|
||||
add_dependencies(Example1 qtadvanceddocking)
|
||||
target_include_directories(Example1 PUBLIC
|
||||
$<BUILD_INTERFACE:${ads_example_INCLUDE}>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
target_include_directories(Example1 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src" ${ads_example_INCLUDE})
|
||||
target_link_libraries(Example1 PRIVATE qtadvanceddocking ${ads_example_LIBS})
|
||||
target_compile_definitions(Example1 PRIVATE ${ads_example_DEFINE})
|
||||
set_target_properties(Example1 PROPERTIES
|
||||
VERSION "1.0"
|
||||
SOVERSION 1
|
||||
EXPORT_NAME "Qt Advanced Docking System Example"
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
|
||||
)
|
||||
39
example/MainWindow.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "MainWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Create the dock manager. Because the parent parameter is a QMainWindow
|
||||
// the dock manager registers itself as the central widget.
|
||||
m_DockManager = new ads::CDockManager(this);
|
||||
|
||||
// Create example content label - this can be any application specific
|
||||
// widget
|
||||
QLabel* l = new QLabel();
|
||||
l->setWordWrap(true);
|
||||
l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||
l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
|
||||
|
||||
// Create a dock widget with the title Label 1 and set the created label
|
||||
// as the dock widget content
|
||||
ads::CDockWidget* DockWidget = new ads::CDockWidget("Label 1");
|
||||
DockWidget->setWidget(l);
|
||||
|
||||
// Add the toggleViewAction of the dock widget to the menu to give
|
||||
// the user the possibility to show the dock widget if it has been closed
|
||||
ui->menuView->addAction(DockWidget->toggleViewAction());
|
||||
|
||||
// Add the dock widget to the top dock widget area
|
||||
m_DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
24
example/MainWindow.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "DockManager.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
ads::CDockManager* m_DockManager;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
38
example/MainWindow.ui
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget"/>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menuView"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
47
example/example.pro
Normal file
@@ -0,0 +1,47 @@
|
||||
ADS_OUT_ROOT = $${OUT_PWD}/..
|
||||
|
||||
QT += core gui widgets
|
||||
|
||||
TARGET = Example1
|
||||
DESTDIR = $${ADS_OUT_ROOT}/lib
|
||||
TEMPLATE = app
|
||||
CONFIG += c++14
|
||||
CONFIG += debug_and_release
|
||||
adsBuildStatic {
|
||||
DEFINES += ADS_STATIC
|
||||
}
|
||||
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
MainWindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
MainWindow.h
|
||||
|
||||
FORMS += \
|
||||
MainWindow.ui
|
||||
|
||||
|
||||
LIBS += -L$${ADS_OUT_ROOT}/lib
|
||||
|
||||
# Dependency: AdvancedDockingSystem (shared)
|
||||
CONFIG(debug, debug|release){
|
||||
win32 {
|
||||
LIBS += -lqtadvanceddockingd
|
||||
}
|
||||
else:mac {
|
||||
LIBS += -lqtadvanceddocking_debug
|
||||
}
|
||||
else {
|
||||
LIBS += -lqtadvanceddocking
|
||||
}
|
||||
}
|
||||
else{
|
||||
LIBS += -lqtadvanceddocking
|
||||
}
|
||||
|
||||
INCLUDEPATH += ../src
|
||||
DEPENDPATH += ../src
|
||||
|
||||
11
example/main.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "MainWindow.h"
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
|
Before Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 41 KiB |
BIN
perspectives.png
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 82 KiB |
BIN
preview.png
|
Before Width: | Height: | Size: 57 KiB |
41
recipes/meta.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
{% set data = load_setup_py_data() %}
|
||||
|
||||
package:
|
||||
name: pyqtads
|
||||
version: {{ data.get('version') }}
|
||||
|
||||
source:
|
||||
path: ../
|
||||
|
||||
build:
|
||||
number: 0
|
||||
script: python setup.py install --single-version-externally-managed --record=record.txt --conda-recipe
|
||||
|
||||
requirements:
|
||||
build:
|
||||
- python
|
||||
- setuptools
|
||||
- pyqt>=5.9
|
||||
- sip>=4.19
|
||||
run:
|
||||
- python
|
||||
- pyqt>=5.9
|
||||
- sip>=4.19
|
||||
- pywin32 [win]
|
||||
|
||||
test:
|
||||
imports:
|
||||
- PyQtAds
|
||||
|
||||
about:
|
||||
home: {{ data.get('url') }}
|
||||
license: {{ data.get('license') }}
|
||||
license_family: LGPL
|
||||
license_file: 'LICENSE.md'
|
||||
summary: {{ data.get('description') }}
|
||||
description: {{ data.get('description') }}
|
||||
doc_url: ''
|
||||
dev_url: {{ data.get('url') }}
|
||||
|
||||
extra:
|
||||
recipe-maintainers: 'nicolas.elie@cnrs.fr'
|
||||
7
setup.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
[versioneer]
|
||||
VCS = git
|
||||
style = pep440
|
||||
versionfile_source = PyQtAds/_version.py
|
||||
versionfile_build = PyQtAds/_version.py
|
||||
tag_prefix =
|
||||
|
||||
294
setup.py
Normal file
@@ -0,0 +1,294 @@
|
||||
import os
|
||||
import sys
|
||||
import shlex
|
||||
import subprocess
|
||||
import glob
|
||||
|
||||
import versioneer
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools.command.build_py import build_py
|
||||
from setuptools.extension import Extension
|
||||
from distutils import sysconfig, dir_util, spawn, log, cmd
|
||||
from distutils.dep_util import newer
|
||||
import sipdistutils
|
||||
import sipconfig
|
||||
from PyQt5.QtCore import PYQT_CONFIGURATION
|
||||
from PyQt5.pyrcc_main import processResourceFile
|
||||
|
||||
MODULE_NAME = "ads"
|
||||
SRC_PATH = "PyQtAds"
|
||||
|
||||
REQUIRE_PYQT = True
|
||||
if "--conda-recipe" in sys.argv:
|
||||
REQUIRE_PYQT = False
|
||||
sys.argv.remove("--conda-recipe")
|
||||
|
||||
|
||||
class HostPythonConfiguration(object):
|
||||
def __init__(self):
|
||||
self.platform = sys.platform
|
||||
self.version = sys.hexversion>>8
|
||||
|
||||
self.inc_dir = sysconfig.get_python_inc()
|
||||
self.venv_inc_dir = sysconfig.get_python_inc(prefix=sys.prefix)
|
||||
self.module_dir = sysconfig.get_python_lib(plat_specific=1)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
self.data_dir = sys.prefix
|
||||
self.lib_dir = sys.prefix +'\\libs'
|
||||
else:
|
||||
self.data_dir = sys.prefix + '/share'
|
||||
self.lib_dir = sys.prefix + '/lib'
|
||||
|
||||
|
||||
class TargetQtConfiguration(object):
|
||||
def __init__(self, qmake):
|
||||
pipe = os.popen(' '.join([qmake, '-query']))
|
||||
|
||||
for l in pipe:
|
||||
l = l.strip()
|
||||
|
||||
tokens = l.split(':', 1)
|
||||
if isinstance(tokens, list):
|
||||
if len(tokens) != 2:
|
||||
error("Unexpected output from qmake: '%s'\n" % l)
|
||||
|
||||
name, value = tokens
|
||||
else:
|
||||
name = tokens
|
||||
value = None
|
||||
|
||||
name = name.replace('/', '_')
|
||||
setattr(self, name, value)
|
||||
|
||||
pipe.close()
|
||||
|
||||
|
||||
class build_ext(sipdistutils.build_ext):
|
||||
|
||||
description = "Builds the " + MODULE_NAME + " module."
|
||||
|
||||
user_options = sipdistutils.build_ext.user_options + [
|
||||
('qmake-bin=', None, "Path to qmake binary"),
|
||||
('sip-bin=', None, "Path to sip binary"),
|
||||
('qt-include-dir=', None, "Path to Qt headers"),
|
||||
('pyqt-sip-dir=', None, "Path to PyQt's SIP files"),
|
||||
('pyqt-sip-flags=', None, "SIP flags used to generate PyQt bindings"),
|
||||
('sip-dir=', None, "Path to module's SIP files"),
|
||||
('inc-dir=', None, "Path to module's include files")
|
||||
]
|
||||
|
||||
def initialize_options (self):
|
||||
super().initialize_options()
|
||||
self.qmake_bin = 'qmake'
|
||||
self.sip_bin = None
|
||||
self.qt_include_dir = None
|
||||
self.qt_libinfix = ''
|
||||
self.pyqt_sip_dir = None
|
||||
self.pyqt_sip_flags = None
|
||||
self.sip_files_dir = None
|
||||
self.sip_inc_dir = None
|
||||
self.inc_dir = None
|
||||
self.pyconfig = HostPythonConfiguration()
|
||||
self.qtconfig = TargetQtConfiguration(self.qmake_bin)
|
||||
self.config = sipconfig.Configuration()
|
||||
self.config.default_mod_dir = ("/usr/local/lib/python%i.%i/dist-packages" %
|
||||
(sys.version_info.major, sys.version_info.minor))
|
||||
|
||||
def finalize_options (self):
|
||||
super().finalize_options()
|
||||
|
||||
if not self.qt_include_dir:
|
||||
self.qt_include_dir = self.qtconfig.QT_INSTALL_HEADERS
|
||||
|
||||
if not self.qt_libinfix:
|
||||
try:
|
||||
with open(os.path.join(self.qtconfig.QT_INSTALL_PREFIX, 'mkspecs', 'qconfig.pri'), 'r') as f:
|
||||
for line in f.readlines():
|
||||
if line.startswith('QT_LIBINFIX'):
|
||||
self.qt_libinfix = line.split('=')[1].strip('\n').strip()
|
||||
except (FileNotFoundError, IndexError):
|
||||
pass
|
||||
|
||||
if not self.pyqt_sip_dir:
|
||||
self.pyqt_sip_dir = os.path.join(self.pyconfig.data_dir, 'sip', 'PyQt5')
|
||||
|
||||
if not self.pyqt_sip_flags:
|
||||
self.pyqt_sip_flags = PYQT_CONFIGURATION.get('sip_flags', '')
|
||||
|
||||
if not self.sip_files_dir:
|
||||
self.sip_files_dir = os.path.abspath(os.path.join(".", "sip"))
|
||||
|
||||
if not self.sip_inc_dir:
|
||||
self.sip_inc_dir = self.pyconfig.venv_inc_dir
|
||||
|
||||
if not self.inc_dir:
|
||||
self.inc_dir = os.path.abspath(os.path.join(".", "src"))
|
||||
|
||||
if not self.qt_include_dir:
|
||||
raise SystemExit('Could not find Qt5 headers. '
|
||||
'Please specify via --qt-include-dir=')
|
||||
|
||||
if not self.pyqt_sip_dir:
|
||||
raise SystemExit('Could not find PyQt SIP files. '
|
||||
'Please specify containing directory via '
|
||||
'--pyqt-sip-dir=')
|
||||
|
||||
if not self.pyqt_sip_flags:
|
||||
raise SystemExit('Could not find PyQt SIP flags. '
|
||||
'Please specify via --pyqt-sip-flags=')
|
||||
|
||||
def _find_sip(self):
|
||||
"""override _find_sip to allow for manually speficied sip path."""
|
||||
return self.sip_bin or super()._find_sip()
|
||||
|
||||
def _sip_compile(self, sip_bin, source, sbf):
|
||||
cmd = [sip_bin]
|
||||
if hasattr(self, 'sip_opts'):
|
||||
cmd += self.sip_opts
|
||||
if hasattr(self, '_sip_sipfiles_dir'):
|
||||
cmd += ['-I', self._sip_sipfiles_dir()]
|
||||
cmd += [
|
||||
"-I", self.sip_files_dir,
|
||||
"-I", self.pyqt_sip_dir,
|
||||
"-I", self.sip_inc_dir,
|
||||
"-I", self.inc_dir,
|
||||
"-c", self._sip_output_dir(),
|
||||
"-b", sbf,
|
||||
"-w", "-o"]
|
||||
|
||||
cmd += shlex.split(self.pyqt_sip_flags) # use same SIP flags as for PyQt5
|
||||
cmd.append(source)
|
||||
self.spawn(cmd)
|
||||
|
||||
def swig_sources (self, sources, extension=None):
|
||||
if not self.extensions:
|
||||
return
|
||||
|
||||
# Add the local include directory to the include path
|
||||
if extension is not None:
|
||||
extension.extra_compile_args += ['-D', 'QT_CORE_LIB',
|
||||
'-D', 'QT_GUI_LIB',
|
||||
'-D', 'QT_WIDGETS_LIB',
|
||||
'-D', 'ADS_SHARED_EXPORT']
|
||||
extension.include_dirs += [self.qt_include_dir, self.inc_dir,
|
||||
os.path.join(self.qt_include_dir, 'QtCore'),
|
||||
os.path.join(self.qt_include_dir, 'QtGui'),
|
||||
os.path.join(self.qt_include_dir, 'QtWidgets')]
|
||||
extension.libraries += ['Qt5Core' + self.qt_libinfix,
|
||||
'Qt5Gui' + self.qt_libinfix,
|
||||
'Qt5Widgets' + self.qt_libinfix]
|
||||
|
||||
if sys.platform == 'win32':
|
||||
extension.library_dirs += [self.qtconfig.QT_INSTALL_LIBS,
|
||||
self.inc_dir, self._sip_output_dir()]
|
||||
elif sys.platform == 'darwin':
|
||||
extension.extra_compile_args += ['-F' + self.qtconfig.QT_INSTALL_LIBS,
|
||||
'-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.9']
|
||||
extension.extra_link_args += ['-F' + self.qtconfig.QT_INSTALL_LIBS,
|
||||
'-mmacosx-version-min=10.9']
|
||||
elif sys.platform == 'linux':
|
||||
extension.extra_compile_args += ['-std=c++11']
|
||||
|
||||
return super().swig_sources(sources, extension)
|
||||
|
||||
def build_extension(self, ext):
|
||||
cppsources = [source for source in ext.sources if source.endswith(".cpp")]
|
||||
|
||||
dir_util.mkpath(self.build_temp, dry_run=self.dry_run)
|
||||
|
||||
# Run moc on all header files.
|
||||
for source in cppsources:
|
||||
header = source.replace(".cpp", ".h")
|
||||
if os.path.exists(header):
|
||||
moc_file = "moc_" + os.path.basename(header).replace(".h", ".cpp")
|
||||
out_file = os.path.join(self.build_temp, moc_file)
|
||||
|
||||
if newer(header, out_file) or self.force:
|
||||
call_arg = ["moc", "-o", out_file, header]
|
||||
spawn.spawn(call_arg, dry_run=self.dry_run)
|
||||
|
||||
if os.path.getsize(out_file) > 0:
|
||||
ext.sources.append(out_file)
|
||||
|
||||
# Add the temp build directory to include path, for compiler to find
|
||||
# the created .moc files
|
||||
ext.include_dirs += [self._sip_output_dir()]
|
||||
|
||||
sipdistutils.build_ext.build_extension(self, ext)
|
||||
|
||||
|
||||
class ProcessResourceCommand(cmd.Command):
|
||||
"""A custom command to compile the resource file into a Python file"""
|
||||
|
||||
description = "Compile the qrc file into a python file"
|
||||
|
||||
def initialize_options(self):
|
||||
return
|
||||
|
||||
def finalize_options(self):
|
||||
return
|
||||
|
||||
def run(self):
|
||||
processResourceFile([os.path.join('src', 'ads.qrc')],
|
||||
os.path.join(SRC_PATH, 'rc.py'), False)
|
||||
|
||||
|
||||
class BuildPyCommand(build_py):
|
||||
"""Custom build command to include ProcessResource command"""
|
||||
|
||||
def run(self):
|
||||
self.run_command("process_resource")
|
||||
build_py.run(self)
|
||||
|
||||
|
||||
setup_requires = ["PyQt5"] if REQUIRE_PYQT else []
|
||||
cpp_sources = glob.glob(os.path.join('src', '*.cpp'))
|
||||
sip_sources = [os.path.join('sip', MODULE_NAME + '.sip')]
|
||||
if sys.platform == 'linux':
|
||||
cpp_sources += glob.glob(os.path.join('src', 'linux', '*.cpp'))
|
||||
ext_modules = [Extension('PyQtAds.QtAds.ads', cpp_sources + sip_sources)]
|
||||
|
||||
install_requires = ["PyQt5"]
|
||||
if sys.platform == 'win32':
|
||||
install_requires.append("pywin32")
|
||||
|
||||
|
||||
with open('README.md', 'r') as f:
|
||||
LONG_DESCRIPTION = f.read()
|
||||
|
||||
setup(
|
||||
name = SRC_PATH,
|
||||
author = "Nicolas Elie",
|
||||
author_email = "nicolas.elie@cnrs.fr",
|
||||
url = "https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System",
|
||||
version = versioneer.get_version(),
|
||||
description = "Advanced Docking System for Qt",
|
||||
long_description = LONG_DESCRIPTION,
|
||||
keywords = ["qt"],
|
||||
license = "LGPLv2+",
|
||||
classifiers = ["Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Environment :: Win32 (MS Windows)",
|
||||
"Environment :: MacOS X",
|
||||
"Environment :: X11 Applications :: Qt",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.2",
|
||||
"Programming Language :: Python :: 3.3",
|
||||
"Programming Language :: Python :: 3.4",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7"],
|
||||
ext_modules = ext_modules,
|
||||
cmdclass = versioneer.get_cmdclass({'process_resource': ProcessResourceCommand,
|
||||
'build_py': BuildPyCommand,
|
||||
'build_ext': build_ext}),
|
||||
packages = find_packages(),
|
||||
setup_requires = setup_requires,
|
||||
install_requires = install_requires,
|
||||
zip_safe=False
|
||||
)
|
||||
82
simple.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import logging
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQtAds import QtAds
|
||||
|
||||
|
||||
class MainWindow(QtWidgets.QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setup_ui()
|
||||
self.dock_manager = QtAds.CDockManager(self)
|
||||
|
||||
self.dock_widgets = []
|
||||
|
||||
for label_text, area in (
|
||||
('1 Top', QtAds.TopDockWidgetArea),
|
||||
('2 Bottom', QtAds.BottomDockWidgetArea),
|
||||
('3 Left', QtAds.LeftDockWidgetArea),
|
||||
('4 Right', QtAds.RightDockWidgetArea),
|
||||
):
|
||||
# Create example content label - this can be any application specific
|
||||
# widget
|
||||
label = QtWidgets.QLabel()
|
||||
label.setWordWrap(True)
|
||||
label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||||
label.setText(f"{label_text}: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
|
||||
|
||||
# Create a dock widget with the title Label 1 and set the created label
|
||||
# as the dock widget content
|
||||
dock_widget = QtAds.CDockWidget(label_text)
|
||||
dock_widget.setWidget(label)
|
||||
self.dock_widgets.append(dock_widget)
|
||||
|
||||
# Add the toggleViewAction of the dock widget to the menu to give
|
||||
# the user the possibility to show the dock widget if it has been closed
|
||||
self.menu_view.addAction(dock_widget.toggleViewAction())
|
||||
|
||||
# Add the dock widget to the top dock widget area
|
||||
self.dock_manager.addDockWidget(area, dock_widget)
|
||||
|
||||
def setup_ui(self):
|
||||
self.setWindowTitle("MainWindow")
|
||||
self.setObjectName("MainWindow")
|
||||
self.resize(400, 300)
|
||||
self.central_widget = QtWidgets.QWidget(self)
|
||||
self.central_widget.setObjectName("central_widget")
|
||||
self.setCentralWidget(self.central_widget)
|
||||
|
||||
self.menu_bar = QtWidgets.QMenuBar(self)
|
||||
self.menu_bar.setGeometry(QtCore.QRect(0, 0, 400, 21))
|
||||
self.menu_bar.setObjectName("menuBar")
|
||||
|
||||
self.menu_view = QtWidgets.QMenu(self.menu_bar)
|
||||
self.menu_view.setObjectName("menu_view")
|
||||
self.menu_view.setTitle("View")
|
||||
self.setMenuBar(self.menu_bar)
|
||||
|
||||
self.status_bar = QtWidgets.QStatusBar(self)
|
||||
self.status_bar.setObjectName("statusBar")
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.menu_bar.addAction(self.menu_view.menuAction())
|
||||
|
||||
|
||||
def main(app):
|
||||
main = MainWindow()
|
||||
main.show()
|
||||
state = main.dock_manager.saveState()
|
||||
print('This is what the saved state looks like in XML:')
|
||||
print(state)
|
||||
print()
|
||||
main.dock_manager.restoreState(state)
|
||||
return main
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(level='DEBUG')
|
||||
app = QtWidgets.QApplication([])
|
||||
window = main(app)
|
||||
window.show()
|
||||
print('shown')
|
||||
app.exec_()
|
||||
57
sip/DockAreaTabBar.sip
Normal file
@@ -0,0 +1,57 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockAreaTabBar : QScrollArea
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <DockAreaTabBar.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual void wheelEvent(QWheelEvent* Event);
|
||||
virtual void mousePressEvent(QMouseEvent* ev);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* ev);
|
||||
virtual void mouseMoveEvent(QMouseEvent* ev);
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
void startFloating(const QPoint& Offset);
|
||||
ads::IFloatingWidget* makeAreaFloating(const QPoint& Offset,
|
||||
ads::eDragState DragState);
|
||||
ads::eDragState dragState() const;
|
||||
|
||||
public:
|
||||
CDockAreaTabBar(ads::CDockAreaWidget* parent /TransferThis/);
|
||||
virtual ~CDockAreaTabBar();
|
||||
void insertTab(int Index, ads::CDockWidgetTab* Tab /Transfer/);
|
||||
void removeTab(ads::CDockWidgetTab* Tab) /TransferBack/;
|
||||
int count() const;
|
||||
int currentIndex() const;
|
||||
ads::CDockWidgetTab* currentTab() const;
|
||||
ads::CDockWidgetTab* tab(int Index) const;
|
||||
virtual bool eventFilter(QObject *watched, QEvent *event);
|
||||
bool isTabOpen(int Index) const;
|
||||
virtual QSize minimumSizeHint() const;
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
public slots:
|
||||
void setCurrentIndex(int Index);
|
||||
void closeTab(int Index);
|
||||
|
||||
signals:
|
||||
void currentChanging(int Index);
|
||||
void currentChanged(int Index);
|
||||
void tabBarClicked(int index);
|
||||
void tabCloseRequested(int index);
|
||||
void tabClosed(int index);
|
||||
void tabOpened(int index);
|
||||
void tabMoved(int from, int to);
|
||||
void removingTab(int index);
|
||||
void tabInserted(int index);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
32
sip/DockAreaTitleBar.sip
Normal file
@@ -0,0 +1,32 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockAreaTitleBar : QFrame
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <DockAreaTitleBar.h>
|
||||
%End
|
||||
|
||||
public slots:
|
||||
void markTabsMenuOutdated();
|
||||
|
||||
|
||||
public:
|
||||
CDockAreaTitleBar(ads::CDockAreaWidget* parent /TransferThis/);
|
||||
virtual ~CDockAreaTitleBar();
|
||||
ads::CDockAreaTabBar* tabBar() const;
|
||||
QAbstractButton* button(ads::TitleBarButton which) const;
|
||||
virtual void setVisible(bool Visible);
|
||||
|
||||
|
||||
signals:
|
||||
void tabBarClicked(int index);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
65
sip/DockAreaWidget.sip
Normal file
@@ -0,0 +1,65 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockAreaWidget : QFrame
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
#include <DockAreaWidget.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
void insertDockWidget(int index, ads::CDockWidget* DockWidget /Transfer/, bool Activate = true);
|
||||
void addDockWidget(ads::CDockWidget* DockWidget /Transfer/);
|
||||
void removeDockWidget(ads::CDockWidget* DockWidget) /TransferBack/;
|
||||
void toggleDockWidgetView(ads::CDockWidget* DockWidget, bool Open);
|
||||
CDockWidget* nextOpenDockWidget(ads::CDockWidget* DockWidget) const;
|
||||
int index(ads::CDockWidget* DockWidget);
|
||||
void hideAreaWithNoVisibleContent();
|
||||
void updateTitleBarVisibility();
|
||||
void internalSetCurrentDockWidget(ads::CDockWidget* DockWidget /Transfer/);
|
||||
void markTitleBarMenuOutdated();
|
||||
|
||||
protected slots:
|
||||
void toggleView(bool Open);
|
||||
|
||||
public:
|
||||
CDockAreaWidget(ads::CDockManager* DockManager /TransferThis/, ads::CDockContainerWidget* parent /TransferThis/);
|
||||
virtual ~CDockAreaWidget();
|
||||
ads::CDockManager* dockManager() const;
|
||||
ads::CDockContainerWidget* dockContainer() const;
|
||||
QRect titleBarGeometry() const;
|
||||
QRect contentAreaGeometry() const;
|
||||
int dockWidgetsCount() const;
|
||||
QList<ads::CDockWidget*> dockWidgets() const;
|
||||
int openDockWidgetsCount() const;
|
||||
QList<ads::CDockWidget*> openedDockWidgets() const;
|
||||
ads::CDockWidget* dockWidget(int Index) const;
|
||||
int currentIndex() const;
|
||||
int indexOfFirstOpenDockWidget() const;
|
||||
ads::CDockWidget* currentDockWidget() const;
|
||||
void setCurrentDockWidget(ads::CDockWidget* DockWidget /Transfer/);
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
ads::CDockWidget::DockWidgetFeatures features() const;
|
||||
QAbstractButton* titleBarButton(ads::TitleBarButton which) const;
|
||||
virtual void setVisible(bool Visible);
|
||||
|
||||
public slots:
|
||||
void setCurrentIndex(int index);
|
||||
void closeArea();
|
||||
void closeOtherAreas();
|
||||
|
||||
signals:
|
||||
void tabBarClicked(int index);
|
||||
void currentChanging(int index);
|
||||
void currentChanged(int index);
|
||||
void viewToggled(bool Open);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
155
sip/DockContainerWidget.sip
Normal file
@@ -0,0 +1,155 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
/**
|
||||
* Container that manages a number of dock areas with single dock widgets
|
||||
* or tabyfied dock widgets in each area.
|
||||
* Each window that support docking has a DockContainerWidget. That means
|
||||
* the main application window and all floating windows are ore contain
|
||||
* an DockContainerWidget.
|
||||
*/
|
||||
class CDockContainerWidget : QFrame
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <DockContainerWidget.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual bool event(QEvent *e);
|
||||
QSplitter* rootSplitter() const;
|
||||
void createRootSplitter();
|
||||
void dropFloatingWidget(ads::CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
|
||||
void dropWidget(QWidget* widget, const QPoint& TargetPos);
|
||||
void addDockArea(ads::CDockAreaWidget* DockAreaWidget /Transfer/, ads::DockWidgetArea area = ads::CenterDockWidgetArea);
|
||||
void removeDockArea(ads::CDockAreaWidget* area /Transfer/);
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
bool restoreState(CDockingStateReader& Stream, bool Testing);
|
||||
ads::CDockAreaWidget* lastAddedDockAreaWidget(ads::DockWidgetArea area) const;
|
||||
bool hasTopLevelDockWidget() const;
|
||||
ads::CDockWidget* topLevelDockWidget() const;
|
||||
ads::CDockAreaWidget* topLevelDockArea() const;
|
||||
QList<ads::CDockWidget*> dockWidgets() const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
CDockContainerWidget(ads::CDockManager* DockManager /TransferThis/, QWidget* parent /TransferThis/ = 0);
|
||||
|
||||
/**
|
||||
* Virtual Destructor
|
||||
*/
|
||||
virtual ~CDockContainerWidget();
|
||||
|
||||
/**
|
||||
* Adds dockwidget into the given area.
|
||||
* If DockAreaWidget is not null, then the area parameter indicates the area
|
||||
* into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will
|
||||
* be dropped into the container.
|
||||
* \return Returns the dock area widget that contains the new DockWidget
|
||||
*/
|
||||
ads::CDockAreaWidget* addDockWidget(ads::DockWidgetArea area, ads::CDockWidget* Dockwidget /Transfer/,
|
||||
ads::CDockAreaWidget* DockAreaWidget /Transfer/ = 0);
|
||||
|
||||
/**
|
||||
* Removes dockwidget
|
||||
*/
|
||||
void removeDockWidget(ads::CDockWidget* Dockwidget) /TransferBack/;
|
||||
|
||||
/**
|
||||
* Returns the current zOrderIndex
|
||||
*/
|
||||
virtual unsigned int zOrderIndex() const;
|
||||
|
||||
/**
|
||||
* This function returns true if this container widgets z order index is
|
||||
* higher than the index of the container widget given in Other parameter
|
||||
*/
|
||||
bool isInFrontOf(ads::CDockContainerWidget* Other) const;
|
||||
|
||||
/**
|
||||
* Returns the dock area at teh given global position or 0 if there is no
|
||||
* dock area at this position
|
||||
*/
|
||||
ads::CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const;
|
||||
|
||||
/**
|
||||
* Returns the dock area at the given Index or 0 if the index is out of
|
||||
* range
|
||||
*/
|
||||
ads::CDockAreaWidget* dockArea(int Index) const;
|
||||
|
||||
/**
|
||||
* Returns the list of dock areas that are not closed
|
||||
* If all dock widgets in a dock area are closed, the dock area will be closed
|
||||
*/
|
||||
QList<ads::CDockAreaWidget*> openedDockAreas() const;
|
||||
|
||||
/**
|
||||
* Returns the number of dock areas in this container
|
||||
*/
|
||||
int dockAreaCount() const;
|
||||
|
||||
/**
|
||||
* Returns the number of visible dock areas
|
||||
*/
|
||||
int visibleDockAreaCount() const;
|
||||
|
||||
/**
|
||||
* This function returns true, if this container is in a floating widget
|
||||
*/
|
||||
bool isFloating() const;
|
||||
|
||||
/**
|
||||
* Dumps the layout for debugging purposes
|
||||
*/
|
||||
void dumpLayout();
|
||||
|
||||
/**
|
||||
* This functions returns the dock widget features of all dock widget in
|
||||
* this container.
|
||||
* A bitwise and is used to combine the flags of all dock widgets. That
|
||||
* means, if only dock widget does not support a certain flag, the whole
|
||||
* dock are does not support the flag.
|
||||
*/
|
||||
ads::CDockWidget::DockWidgetFeatures features() const;
|
||||
|
||||
/**
|
||||
* If this dock container is in a floating widget, this function returns
|
||||
* the floating widget.
|
||||
* Else, it returns a nullptr.
|
||||
*/
|
||||
ads::CFloatingDockContainer* floatingWidget() const;
|
||||
|
||||
/**
|
||||
* Call this function to close all dock areas except the KeepOpenArea
|
||||
*/
|
||||
void closeOtherAreas(ads::CDockAreaWidget* KeepOpenArea);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted if one or multiple dock areas has been added to
|
||||
* the internal list of dock areas.
|
||||
* If multiple dock areas are inserted, this signal is emitted only once
|
||||
*/
|
||||
void dockAreasAdded();
|
||||
|
||||
/**
|
||||
* This signal is emitted if one or multiple dock areas has been removed
|
||||
*/
|
||||
void dockAreasRemoved();
|
||||
|
||||
/**
|
||||
* This signal is emitted if a dock area is opened or closed via
|
||||
* toggleView() function
|
||||
*/
|
||||
void dockAreaViewToggled(ads::CDockAreaWidget* DockArea, bool Open);
|
||||
}; // class DockContainerWidget
|
||||
};
|
||||
// namespace ads
|
||||
|
||||
%End
|
||||
216
sip/DockManager.sip
Normal file
@@ -0,0 +1,216 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
%MappedType QMap<QString, ads::CDockWidget*>
|
||||
/TypeHint="Dict[QString, CDockWidget*]", TypeHintValue="{}"/
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qmap.h>
|
||||
%End
|
||||
|
||||
%ConvertFromTypeCode
|
||||
PyObject *d = PyDict_New();
|
||||
|
||||
if (!d)
|
||||
return 0;
|
||||
|
||||
QMap<QString, ads::CDockWidget*>::const_iterator it = sipCpp->constBegin();
|
||||
QMap<QString, ads::CDockWidget*>::const_iterator end = sipCpp->constEnd();
|
||||
|
||||
while (it != end)
|
||||
{
|
||||
QString *k = new QString(it.key());
|
||||
PyObject *kobj = sipConvertFromType(k, sipType_QString,
|
||||
sipTransferObj);
|
||||
|
||||
if (!kobj)
|
||||
{
|
||||
delete k;
|
||||
Py_DECREF(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *vobj = sipConvertFromType(it.value(), sipType_ads_CDockWidget,
|
||||
sipTransferObj);
|
||||
|
||||
if (!vobj)
|
||||
{
|
||||
Py_DECREF(kobj);
|
||||
Py_DECREF(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rc = PyDict_SetItem(d, kobj, vobj);
|
||||
|
||||
Py_DECREF(vobj);
|
||||
Py_DECREF(kobj);
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
Py_DECREF(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
return d;
|
||||
%End
|
||||
|
||||
%ConvertToTypeCode
|
||||
if (!sipIsErr)
|
||||
return PyDict_Check(sipPy);
|
||||
|
||||
QMap<QString, ads::CDockWidget*> *qm = new QMap<QString, ads::CDockWidget*>;
|
||||
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *kobj, *vobj;
|
||||
while (PyDict_Next(sipPy, &pos, &kobj, &vobj))
|
||||
{
|
||||
int kstate;
|
||||
QString *k = reinterpret_cast<QString *>(
|
||||
sipForceConvertToType(kobj, sipType_QString, sipTransferObj,
|
||||
SIP_NOT_NONE, &kstate, sipIsErr));
|
||||
|
||||
if (*sipIsErr)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"a dict key has type '%s' but '_TYPE1_' is expected",
|
||||
sipPyTypeName(Py_TYPE(kobj)));
|
||||
|
||||
delete qm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vstate;
|
||||
ads::CDockWidget *v = reinterpret_cast<ads::CDockWidget *>(
|
||||
sipForceConvertToType(vobj, sipType_ads_CDockWidget, sipTransferObj,
|
||||
SIP_NOT_NONE, &vstate, sipIsErr));
|
||||
|
||||
if (*sipIsErr)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"a dict value has type '%s' but '_TYPE2_' is expected",
|
||||
sipPyTypeName(Py_TYPE(vobj)));
|
||||
|
||||
sipReleaseType(k, sipType_QString, kstate);
|
||||
delete qm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
qm->insert(*k, v);
|
||||
|
||||
sipReleaseType(v, sipType_ads_CDockWidget, vstate);
|
||||
sipReleaseType(k, sipType_QString, kstate);
|
||||
}
|
||||
|
||||
*sipCppPtr = qm;
|
||||
|
||||
return sipGetState(sipTransferObj);
|
||||
%End
|
||||
};
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockManager : ads::CDockContainerWidget
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
#include <DockManager.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
void registerFloatingWidget(ads::CFloatingDockContainer* FloatingWidget /Transfer/);
|
||||
void removeFloatingWidget(ads::CFloatingDockContainer* FloatingWidget) /TransferBack/;
|
||||
void registerDockContainer(ads::CDockContainerWidget* DockContainer /Transfer/);
|
||||
void removeDockContainer(ads::CDockContainerWidget* DockContainer /TransferBack/);
|
||||
ads::CDockOverlay* containerOverlay() const;
|
||||
ads::CDockOverlay* dockAreaOverlay() const;
|
||||
|
||||
public:
|
||||
enum eViewMenuInsertionOrder
|
||||
{
|
||||
MenuSortedByInsertion,
|
||||
MenuAlphabeticallySorted
|
||||
};
|
||||
|
||||
enum eConfigFlag
|
||||
{
|
||||
ActiveTabHasCloseButton,
|
||||
DockAreaHasCloseButton,
|
||||
DockAreaCloseButtonClosesTab,
|
||||
OpaqueSplitterResize,
|
||||
XmlAutoFormattingEnabled,
|
||||
XmlCompressionEnabled,
|
||||
TabCloseButtonIsToolButton,
|
||||
AllTabsHaveCloseButton,
|
||||
RetainTabSizeWhenCloseButtonHidden,
|
||||
OpaqueUndocking,
|
||||
DragPreviewIsDynamic,
|
||||
DragPreviewShowsContentPixmap,
|
||||
DragPreviewHasWindowFrame,
|
||||
DefaultConfig,
|
||||
DefaultNonOpaqueConfig,
|
||||
NonOpaqueWithWindowFrame,
|
||||
};
|
||||
typedef QFlags<ads::CDockManager::eConfigFlag> ConfigFlags;
|
||||
|
||||
CDockManager(QWidget* parent /TransferThis/ = 0);
|
||||
virtual ~CDockManager();
|
||||
static ads::CDockManager::ConfigFlags configFlags();
|
||||
static void setConfigFlags(const ads::CDockManager::ConfigFlags Flags);
|
||||
static void setConfigFlag(ads::CDockManager::eConfigFlag Flag, bool On = true);
|
||||
static ads::CIconProvider& iconProvider();
|
||||
ads::CDockAreaWidget* addDockWidget(ads::DockWidgetArea area, ads::CDockWidget* Dockwidget /Transfer/,
|
||||
ads::CDockAreaWidget* DockAreaWidget /Transfer/ = 0);
|
||||
ads::CDockAreaWidget* addDockWidgetTab(ads::DockWidgetArea area,
|
||||
ads::CDockWidget* Dockwidget /Transfer/);
|
||||
ads::CDockAreaWidget* addDockWidgetTabToArea(ads::CDockWidget* Dockwidget /Transfer/,
|
||||
ads::CDockAreaWidget* DockAreaWidget /Transfer/);
|
||||
ads::CFloatingDockContainer* addDockWidgetFloating(ads::CDockWidget* DockWidget /Transfer/);
|
||||
ads::CDockWidget* findDockWidget(const QString& ObjectName) const;
|
||||
void removeDockWidget(ads::CDockWidget* Dockwidget) /TransferBack/;
|
||||
QMap<QString, ads::CDockWidget*> dockWidgetsMap() const;
|
||||
const QList<ads::CDockContainerWidget*> dockContainers() const;
|
||||
const QList<ads::CFloatingDockContainer*> floatingWidgets() const;
|
||||
virtual unsigned int zOrderIndex() const;
|
||||
QByteArray saveState(int version = 1) const;
|
||||
bool restoreState(const QByteArray &state, int version = 1);
|
||||
void addPerspective(const QString& UniquePrespectiveName);
|
||||
void removePerspective(const QString& Name);
|
||||
void removePerspectives(const QStringList& Names);
|
||||
QStringList perspectiveNames() const;
|
||||
void savePerspectives(QSettings& Settings) const;
|
||||
void loadPerspectives(QSettings& Settings);
|
||||
QAction* addToggleViewActionToMenu(QAction* ToggleViewAction /Transfer/,
|
||||
const QString& Group = QString(), const QIcon& GroupIcon = QIcon());
|
||||
QMenu* viewMenu() const;
|
||||
void setViewMenuInsertionOrder(ads::CDockManager::eViewMenuInsertionOrder Order);
|
||||
bool isRestoringState() const;
|
||||
static int startDragDistance();
|
||||
|
||||
public slots:
|
||||
void openPerspective(const QString& PerspectiveName);
|
||||
|
||||
signals:
|
||||
void perspectiveListChanged();
|
||||
void perspectivesRemoved();
|
||||
void restoringState();
|
||||
void stateRestored();
|
||||
void openingPerspective(const QString& PerspectiveName);
|
||||
void perspectiveOpened(const QString& PerspectiveName);
|
||||
void dockAreaCreated(ads::CDockAreaWidget* DockArea);
|
||||
void dockWidgetAboutToBeRemoved(ads::CDockWidget* DockWidget);
|
||||
void dockWidgetRemoved(ads::CDockWidget* DockWidget);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
77
sip/DockOverlay.sip
Normal file
@@ -0,0 +1,77 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockOverlay : public QFrame
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <DockOverlay.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
|
||||
enum eMode
|
||||
{
|
||||
ModeDockAreaOverlay,
|
||||
ModeContainerOverlay
|
||||
};
|
||||
|
||||
CDockOverlay(QWidget* parent /TransferThis/, eMode Mode = ads::CDockOverlay::ModeDockAreaOverlay);
|
||||
virtual ~CDockOverlay();
|
||||
void setAllowedAreas(ads::DockWidgetAreas areas);
|
||||
ads::DockWidgetAreas allowedAreas() const;
|
||||
ads::DockWidgetArea dropAreaUnderCursor() const;
|
||||
ads::DockWidgetArea showOverlay(QWidget* target);
|
||||
void hideOverlay();
|
||||
void enableDropPreview(bool Enable);
|
||||
QRect dropOverlayRect() const;
|
||||
virtual bool event(QEvent *e);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *e);
|
||||
virtual void showEvent(QShowEvent* e);
|
||||
virtual void hideEvent(QHideEvent* e);
|
||||
};
|
||||
|
||||
|
||||
class CDockOverlayCross : public QWidget
|
||||
{
|
||||
|
||||
public:
|
||||
enum eIconColor
|
||||
{
|
||||
FrameColor,
|
||||
WindowBackgroundColor,
|
||||
OverlayColor,
|
||||
ArrowColor,
|
||||
ShadowColor
|
||||
};
|
||||
|
||||
protected:
|
||||
QString iconColors() const;
|
||||
QColor iconColor() const;
|
||||
void setIconFrameColor(const QColor& Color);
|
||||
void setIconBackgroundColor(const QColor& Color);
|
||||
void setIconOverlayColor(const QColor& Color);
|
||||
void setIconArrowColor(const QColor& Color);
|
||||
void setIconShadowColor(const QColor& Color);
|
||||
|
||||
public:
|
||||
CDockOverlayCross(ads::CDockOverlay* overlay /TransferThis/);
|
||||
virtual ~CDockOverlayCross();
|
||||
void setIconColor(ads::CDockOverlayCross::eIconColor ColorIndex, const QColor& Color);
|
||||
QColor iconColor(ads::CDockOverlayCross::eIconColor ColorIndex) const;
|
||||
ads::DockWidgetArea cursorLocation() const;
|
||||
void setupOverlayCross(ads::CDockOverlay::eMode Mode);
|
||||
void updateOverlayIcons();
|
||||
void reset();
|
||||
void updatePosition();
|
||||
void setIconColors(const QString& Colors);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
23
sip/DockSplitter.sip
Normal file
@@ -0,0 +1,23 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockSplitter : QSplitter
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <DockSplitter.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
CDockSplitter(QWidget *parent /TransferThis/ = 0);
|
||||
CDockSplitter(Qt::Orientation orientation, QWidget *parent /TransferThis/ = 0);
|
||||
virtual ~CDockSplitter();
|
||||
bool hasVisibleContent() const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
106
sip/DockWidget.sip
Normal file
@@ -0,0 +1,106 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockWidget : QFrame
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <DockWidget.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
void setDockManager(ads::CDockManager* DockManager /Transfer/);
|
||||
void setDockArea(ads::CDockAreaWidget* DockArea /Transfer/);
|
||||
void setToggleViewActionChecked(bool Checked);
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
void flagAsUnassigned();
|
||||
static void emitTopLevelEventForWidget(ads::CDockWidget* TopLevelDockWidget, bool Floating);
|
||||
void emitTopLevelChanged(bool Floating);
|
||||
void setClosedState(bool Closed);
|
||||
void toggleViewInternal(bool Open);
|
||||
|
||||
public:
|
||||
enum DockWidgetFeature
|
||||
{
|
||||
DockWidgetClosable,
|
||||
DockWidgetMovable,
|
||||
DockWidgetFloatable,
|
||||
DockWidgetDeleteOnClose,
|
||||
AllDockWidgetFeatures,
|
||||
NoDockWidgetFeatures
|
||||
};
|
||||
typedef QFlags<ads::CDockWidget::DockWidgetFeature> DockWidgetFeatures;
|
||||
|
||||
enum eState
|
||||
{
|
||||
StateHidden,
|
||||
StateDocked,
|
||||
StateFloating
|
||||
};
|
||||
|
||||
enum eInsertMode
|
||||
{
|
||||
AutoScrollArea,
|
||||
ForceScrollArea,
|
||||
ForceNoScrollArea
|
||||
};
|
||||
|
||||
enum eToggleViewActionMode
|
||||
{
|
||||
ActionModeToggle,
|
||||
ActionModeShow
|
||||
};
|
||||
|
||||
|
||||
CDockWidget(const QString &title, QWidget* parent /TransferThis/ = 0);
|
||||
virtual ~CDockWidget();
|
||||
virtual QSize minimumSizeHint() const;
|
||||
void setWidget(QWidget* widget /Transfer/, ads::CDockWidget::eInsertMode InsertMode = AutoScrollArea);
|
||||
QWidget* takeWidget() /TransferBack/;
|
||||
QWidget* widget() const;
|
||||
ads::CDockWidgetTab* tabWidget() const;
|
||||
void setFeatures(ads::CDockWidget::DockWidgetFeatures features);
|
||||
void setFeature(ads::CDockWidget::DockWidgetFeature flag, bool on);
|
||||
ads::CDockWidget::DockWidgetFeatures features() const;
|
||||
ads::CDockManager* dockManager() const;
|
||||
ads::CDockContainerWidget* dockContainer() const;
|
||||
ads::CDockAreaWidget* dockAreaWidget() const;
|
||||
bool isFloating() const;
|
||||
bool isInFloatingContainer() const;
|
||||
bool isClosed() const;
|
||||
QAction* toggleViewAction() const;
|
||||
void setToggleViewActionMode(ads::CDockWidget::eToggleViewActionMode Mode);
|
||||
void setIcon(const QIcon& Icon);
|
||||
QIcon icon() const;
|
||||
QToolBar* toolBar() const;
|
||||
QToolBar* createDefaultToolBar();
|
||||
void setToolBar(QToolBar* ToolBar);
|
||||
void setToolBarStyle(Qt::ToolButtonStyle Style, ads::CDockWidget::eState State);
|
||||
Qt::ToolButtonStyle toolBarStyle(ads::CDockWidget::eState State) const;
|
||||
void setToolBarIconSize(const QSize& IconSize, ads::CDockWidget::eState State);
|
||||
QSize toolBarIconSize(eState State) const;
|
||||
void setTabToolTip(const QString &text);
|
||||
|
||||
public:
|
||||
virtual bool event(QEvent *e);
|
||||
|
||||
public slots:
|
||||
void toggleView(bool Open = true);
|
||||
void setFloating();
|
||||
void deleteDockWidget();
|
||||
|
||||
signals:
|
||||
void viewToggled(bool Open);
|
||||
void closed();
|
||||
void titleChanged(const QString& Title);
|
||||
void topLevelChanged(bool topLevel);
|
||||
void visibilityChanged(bool visible);
|
||||
void featuresChanged(ads::CDockWidget::DockWidgetFeatures features);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
50
sip/DockWidgetTab.sip
Normal file
@@ -0,0 +1,50 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockWidgetTab : QFrame
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <DockWidgetTab.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent* ev);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* ev);
|
||||
virtual void mouseMoveEvent(QMouseEvent* ev);
|
||||
virtual void contextMenuEvent(QContextMenuEvent* ev);
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent *event);
|
||||
|
||||
public:
|
||||
CDockWidgetTab(ads::CDockWidget* DockWidget /TransferThis/, QWidget* parent /TransferThis/ = 0);
|
||||
virtual ~CDockWidgetTab();
|
||||
bool isActiveTab() const;
|
||||
void setActiveTab(bool active);
|
||||
ads::CDockWidget* dockWidget() const;
|
||||
void setDockAreaWidget(ads::CDockAreaWidget* DockArea /Transfer/);
|
||||
ads::CDockAreaWidget* dockAreaWidget() const;
|
||||
void setIcon(const QIcon& Icon);
|
||||
const QIcon& icon() const;
|
||||
QString text() const;
|
||||
void setText(const QString& title);
|
||||
bool isClosable() const;
|
||||
virtual bool event(QEvent *e);
|
||||
|
||||
|
||||
public slots:
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
signals:
|
||||
void activeTabChanged();
|
||||
void clicked();
|
||||
void closeRequested();
|
||||
void closeOtherTabsRequested();
|
||||
void moved(const QPoint& GlobalPos);
|
||||
}; // class DockWidgetTab
|
||||
};
|
||||
// namespace ads
|
||||
|
||||
%End
|
||||
21
sip/DockingStateReader.sip
Normal file
@@ -0,0 +1,21 @@
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CDockingStateReader : QXmlStreamReader
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
#include <DockingStateReader.h>
|
||||
%End
|
||||
|
||||
|
||||
public:
|
||||
void setFileVersion(int FileVersion);
|
||||
int fileVersion() const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
40
sip/ElidingLabel.sip
Normal file
@@ -0,0 +1,40 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CElidingLabel : QLabel
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <ElidingLabel.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event);
|
||||
virtual void resizeEvent( QResizeEvent *event );
|
||||
virtual void mouseDoubleClickEvent( QMouseEvent *ev );
|
||||
|
||||
public:
|
||||
CElidingLabel(QWidget* parent /TransferThis/ = 0, Qt::WindowFlags f = 0);
|
||||
CElidingLabel(const QString& text, QWidget* parent /TransferThis/ = 0, Qt::WindowFlags f = 0);
|
||||
virtual ~CElidingLabel();
|
||||
Qt::TextElideMode elideMode() const;
|
||||
void setElideMode(Qt::TextElideMode mode);
|
||||
|
||||
|
||||
public:
|
||||
virtual QSize minimumSizeHint() const;
|
||||
virtual QSize sizeHint() const;
|
||||
void setText(const QString &text);
|
||||
QString text() const;
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
void doubleClicked();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
65
sip/FloatingDockContainer.sip
Normal file
@@ -0,0 +1,65 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class IFloatingWidget
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <FloatingDockContainer.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
|
||||
ads::eDragState DragState, QWidget* MouseEventHandler) = 0;
|
||||
|
||||
virtual void moveFloating() = 0;
|
||||
virtual void finishDragging() = 0;
|
||||
};
|
||||
|
||||
|
||||
class CFloatingDockContainer : QWidget, ads::IFloatingWidget
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
#include <FloatingDockContainer.h>
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
|
||||
ads::eDragState DragState, QWidget* MouseEventHandler);
|
||||
void startDragging(const QPoint& DragStartMousePos, const QSize& Size,
|
||||
QWidget* MouseEventHandler);
|
||||
virtual void finishDragging();
|
||||
void initFloatingGeometry(const QPoint& DragStartMousePos, const QSize& Size);
|
||||
void moveFloating();
|
||||
bool restoreState(ads::CDockingStateReader& Stream, bool Testing);
|
||||
void updateWindowTitle();
|
||||
|
||||
|
||||
protected:
|
||||
virtual void changeEvent(QEvent *event);
|
||||
virtual void moveEvent(QMoveEvent *event);
|
||||
virtual bool event(QEvent *e);
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
virtual void hideEvent(QHideEvent *event);
|
||||
virtual void showEvent(QShowEvent *event);
|
||||
virtual bool eventFilter(QObject *watched, QEvent *event);
|
||||
|
||||
public:
|
||||
CFloatingDockContainer(ads::CDockManager* DockManager /TransferThis/);
|
||||
CFloatingDockContainer(ads::CDockAreaWidget* DockArea /TransferThis/);
|
||||
CFloatingDockContainer(ads::CDockWidget* DockWidget /TransferThis/);
|
||||
virtual ~CFloatingDockContainer();
|
||||
ads::CDockContainerWidget* dockContainer() const;
|
||||
bool isClosable() const;
|
||||
bool hasTopLevelDockWidget() const;
|
||||
ads::CDockWidget* topLevelDockWidget() const;
|
||||
QList<ads::CDockWidget*> dockWidgets() const;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
38
sip/FloatingDragPreview.sip
Normal file
@@ -0,0 +1,38 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CFloatingDragPreview : QWidget, ads::IFloatingWidget
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
#include <FloatingDragPreview.h>
|
||||
%End
|
||||
|
||||
|
||||
public:
|
||||
CFloatingDragPreview(ads::CDockWidget* Content /TransferThis/ );
|
||||
CFloatingDragPreview(ads::CDockAreaWidget* Content /TransferThis/ );
|
||||
|
||||
virtual ~CFloatingDragPreview();
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
virtual void startFloating(const QPoint& DragStartMousePos, const QSize& Size,
|
||||
ads::eDragState DragState, QWidget* MouseEventHandler);
|
||||
|
||||
virtual void moveFloating();
|
||||
|
||||
virtual void finishDragging();
|
||||
|
||||
signals:
|
||||
void draggingCanceled();
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
28
sip/IconProvider.sip
Normal file
@@ -0,0 +1,28 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
class CIconProvider
|
||||
{
|
||||
|
||||
%TypeHeaderCode
|
||||
#include <IconProvider.h>
|
||||
%End
|
||||
|
||||
|
||||
public:
|
||||
CIconProvider();
|
||||
|
||||
virtual ~CIconProvider();
|
||||
|
||||
QIcon customIcon(eIcon IconId);
|
||||
|
||||
void registerCustomIcon(eIcon IconId, const QIcon& icon /TransferThis/ );
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
23
sip/ads.sip
Normal file
@@ -0,0 +1,23 @@
|
||||
%Module(name=PyQtAds.QtAds.ads, call_super_init=True, keyword_arguments="Optional", use_limited_api=True)
|
||||
%Import QtCore/QtCoremod.sip
|
||||
%DefaultSupertype sip.simplewrapper
|
||||
%Platforms {Linux macOS Windows}
|
||||
|
||||
%Include ads_globals.sip
|
||||
%Include DockWidget.sip
|
||||
%Include DockAreaTabBar.sip
|
||||
%Include DockAreaTitleBar.sip
|
||||
%Include DockAreaWidget.sip
|
||||
%Include DockContainerWidget.sip
|
||||
%Include DockingStateReader.sip
|
||||
%Include DockManager.sip
|
||||
%Include DockOverlay.sip
|
||||
%Include DockSplitter.sip
|
||||
%Include DockWidgetTab.sip
|
||||
%Include ElidingLabel.sip
|
||||
%Include FloatingDockContainer.sip
|
||||
%Include FloatingDragPreview.sip
|
||||
%Include IconProvider.sip
|
||||
%If (Linux)
|
||||
%Include linux/FloatingWidgetTitleBar.sip
|
||||
%End
|
||||
54
sip/ads_globals.sip
Normal file
@@ -0,0 +1,54 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <ads_globals.h>
|
||||
%End
|
||||
|
||||
enum DockWidgetArea
|
||||
{
|
||||
NoDockWidgetArea,
|
||||
LeftDockWidgetArea,
|
||||
RightDockWidgetArea,
|
||||
TopDockWidgetArea,
|
||||
BottomDockWidgetArea,
|
||||
CenterDockWidgetArea,
|
||||
|
||||
InvalidDockWidgetArea,
|
||||
OuterDockAreas,
|
||||
AllDockAreas
|
||||
};
|
||||
typedef QFlags<ads::DockWidgetArea> DockWidgetAreas;
|
||||
|
||||
|
||||
enum TitleBarButton
|
||||
{
|
||||
TitleBarButtonTabsMenu,
|
||||
TitleBarButtonUndock,
|
||||
TitleBarButtonClose
|
||||
};
|
||||
|
||||
enum eDragState
|
||||
{
|
||||
DraggingInactive,
|
||||
DraggingMousePressed,
|
||||
DraggingTab,
|
||||
DraggingFloatingWidget
|
||||
};
|
||||
|
||||
enum eIcon
|
||||
{
|
||||
TabCloseIcon,
|
||||
DockAreaMenuIcon,
|
||||
DockAreaUndockIcon,
|
||||
DockAreaCloseIcon,
|
||||
|
||||
IconCount,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
31
sip/linux/FloatingWidgetTitleBar.sip
Normal file
@@ -0,0 +1,31 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%If (Qt_5_0_0 -)
|
||||
|
||||
namespace ads
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <FloatingWidgetTitleBar.h>
|
||||
%End
|
||||
|
||||
class CFloatingWidgetTitleBar : QWidget
|
||||
{
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *ev);
|
||||
virtual void mouseReleaseEvent(QMouseEvent *ev);
|
||||
virtual void mouseMoveEvent(QMouseEvent *ev);
|
||||
|
||||
public:
|
||||
explicit CFloatingWidgetTitleBar(CFloatingDockContainer *parent /TransferThis/ = 0);
|
||||
virtual ~CFloatingWidgetTitleBar();
|
||||
void enableCloseButton(bool Enable);
|
||||
void setTitle(const QString &Text);
|
||||
|
||||
signals:
|
||||
void closeRequested();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
%End
|
||||
@@ -1,3 +1,22 @@
|
||||
/*******************************************************************************
|
||||
** Qt Advanced Docking System
|
||||
** Copyright (C) 2017 Uwe Kindler
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU Lesser General Public
|
||||
** License as published by the Free Software Foundation; either
|
||||
** version 2.1 of the License, or (at your option) any later version.
|
||||
**
|
||||
** This library is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public
|
||||
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DockAreaTabBar.cpp
|
||||
/// \author Uwe Kindler
|
||||
@@ -8,16 +27,24 @@
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <FloatingDragPreview.h>
|
||||
#include "DockAreaTabBar.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QScrollBar>
|
||||
#include <QDebug>
|
||||
#include <QBoxLayout>
|
||||
#include <QApplication>
|
||||
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockAreaWidget.h"
|
||||
#include "DockOverlay.h"
|
||||
#include "DockManager.h"
|
||||
#include "DockWidget.h"
|
||||
#include "DockWidgetTab.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace ads
|
||||
{
|
||||
@@ -29,12 +56,30 @@ struct DockAreaTabBarPrivate
|
||||
CDockAreaTabBar* _this;
|
||||
QPoint DragStartMousePos;
|
||||
CDockAreaWidget* DockArea;
|
||||
CFloatingDockContainer* FloatingWidget = nullptr;
|
||||
IFloatingWidget* FloatingWidget = nullptr;
|
||||
QWidget* TabsContainerWidget;
|
||||
QBoxLayout* TabsLayout;
|
||||
int CurrentIndex = -1;
|
||||
eDragState DragState = DraggingInactive;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
*/
|
||||
DockAreaTabBarPrivate(CDockAreaTabBar* _public);
|
||||
|
||||
/**
|
||||
* Update tabs after current index changed or when tabs are removed.
|
||||
* The function reassigns the stylesheet to update the tabs
|
||||
*/
|
||||
void updateTabs();
|
||||
|
||||
/**
|
||||
* Test function for current drag state
|
||||
*/
|
||||
bool isDraggingState(eDragState dragState) const
|
||||
{
|
||||
return this->DragState == dragState;
|
||||
}
|
||||
};
|
||||
// struct DockAreaTabBarPrivate
|
||||
|
||||
@@ -45,17 +90,54 @@ DockAreaTabBarPrivate::DockAreaTabBarPrivate(CDockAreaTabBar* _public) :
|
||||
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaTabBarPrivate::updateTabs()
|
||||
{
|
||||
// Set active TAB and update all other tabs to be inactive
|
||||
for (int i = 0; i < _this->count(); ++i)
|
||||
{
|
||||
auto TabWidget = _this->tab(i);
|
||||
if (!TabWidget)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == CurrentIndex)
|
||||
{
|
||||
TabWidget->show();
|
||||
TabWidget->setActiveTab(true);
|
||||
_this->ensureWidgetVisible(TabWidget);
|
||||
}
|
||||
else
|
||||
{
|
||||
TabWidget->setActiveTab(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) :
|
||||
QScrollArea(parent),
|
||||
d(new DockAreaTabBarPrivate(this))
|
||||
{
|
||||
d->DockArea = parent;
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
setWidgetResizable(true);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
d->TabsContainerWidget = new QWidget();
|
||||
d->TabsContainerWidget->setObjectName("tabsContainerWidget");
|
||||
setWidget(d->TabsContainerWidget);
|
||||
|
||||
d->TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
d->TabsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
d->TabsLayout->setSpacing(0);
|
||||
d->TabsLayout->addStretch(1);
|
||||
d->TabsContainerWidget->setLayout(d->TabsLayout);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
@@ -88,9 +170,10 @@ void CDockAreaTabBar::mousePressEvent(QMouseEvent* ev)
|
||||
{
|
||||
ev->accept();
|
||||
d->DragStartMousePos = ev->pos();
|
||||
d->DragState = DraggingMousePressed;
|
||||
return;
|
||||
}
|
||||
QScrollArea::mousePressEvent(ev);
|
||||
Super::mousePressEvent(ev);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,30 +182,37 @@ void CDockAreaTabBar::mouseReleaseEvent(QMouseEvent* ev)
|
||||
{
|
||||
if (ev->button() == Qt::LeftButton)
|
||||
{
|
||||
qDebug() << "CTabsScrollArea::mouseReleaseEvent";
|
||||
ADS_PRINT("CDockAreaTabBar::mouseReleaseEvent");
|
||||
ev->accept();
|
||||
d->FloatingWidget = nullptr;
|
||||
auto CurrentDragState = d->DragState;
|
||||
d->DragStartMousePos = QPoint();
|
||||
d->DragState = DraggingInactive;
|
||||
if (DraggingFloatingWidget == CurrentDragState)
|
||||
{
|
||||
d->FloatingWidget->finishDragging();
|
||||
}
|
||||
return;
|
||||
}
|
||||
QScrollArea::mouseReleaseEvent(ev);
|
||||
Super::mouseReleaseEvent(ev);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTabBar::mouseMoveEvent(QMouseEvent* ev)
|
||||
{
|
||||
QScrollArea::mouseMoveEvent(ev);
|
||||
if (ev->buttons() != Qt::LeftButton)
|
||||
Super::mouseMoveEvent(ev);
|
||||
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
|
||||
{
|
||||
d->DragState = DraggingInactive;
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->FloatingWidget)
|
||||
{
|
||||
d->FloatingWidget->moveFloating();
|
||||
return;
|
||||
}
|
||||
// move floating window
|
||||
if (d->isDraggingState(DraggingFloatingWidget))
|
||||
{
|
||||
d->FloatingWidget->moveFloating();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is the last dock area in a dock container it does not make
|
||||
// sense to move it to a new floating widget and leave this one
|
||||
@@ -133,9 +223,17 @@ void CDockAreaTabBar::mouseMoveEvent(QMouseEvent* ev)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this->geometry().contains(ev->pos()))
|
||||
// If one single dock widget in this area is not floatable then the whole
|
||||
// area is not floatable
|
||||
if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
{
|
||||
qDebug() << "CTabsScrollArea::startFloating";
|
||||
return;
|
||||
}
|
||||
|
||||
int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength();
|
||||
if (DragDistance >= CDockManager::startDragDistance())
|
||||
{
|
||||
ADS_PRINT("CTabsScrollArea::startFloating");
|
||||
startFloating(d->DragStartMousePos);
|
||||
auto Overlay = d->DockArea->dockManager()->containerOverlay();
|
||||
Overlay->setAllowedAreas(OuterDockAreas);
|
||||
@@ -155,18 +253,394 @@ void CDockAreaTabBar::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
return;
|
||||
}
|
||||
startFloating(event->pos());
|
||||
|
||||
if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
{
|
||||
return;
|
||||
}
|
||||
makeAreaFloating(event->pos(), DraggingInactive);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTabBar::startFloating(const QPoint& Pos)
|
||||
IFloatingWidget* CDockAreaTabBar::makeAreaFloating(const QPoint& Offset, eDragState DragState)
|
||||
{
|
||||
QSize Size = d->DockArea->size();
|
||||
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(d->DockArea);
|
||||
FloatingWidget->startFloating(Pos, Size);
|
||||
d->FloatingWidget = FloatingWidget;
|
||||
d->DragState = DragState;
|
||||
bool OpaqueUndocking = CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking) ||
|
||||
(DraggingFloatingWidget != DragState);
|
||||
CFloatingDockContainer* FloatingDockContainer = nullptr;
|
||||
IFloatingWidget* FloatingWidget;
|
||||
if (OpaqueUndocking)
|
||||
{
|
||||
FloatingWidget = FloatingDockContainer = new CFloatingDockContainer(d->DockArea);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto w = new CFloatingDragPreview(d->DockArea);
|
||||
connect(w, &CFloatingDragPreview::draggingCanceled, [=]()
|
||||
{
|
||||
d->DragState = DraggingInactive;
|
||||
});
|
||||
FloatingWidget = w;
|
||||
}
|
||||
|
||||
FloatingWidget->startFloating(Offset, Size, DragState, nullptr);
|
||||
if (FloatingDockContainer)
|
||||
{
|
||||
auto TopLevelDockWidget = FloatingDockContainer->topLevelDockWidget();
|
||||
if (TopLevelDockWidget)
|
||||
{
|
||||
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
return FloatingWidget;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTabBar::startFloating(const QPoint& Offset)
|
||||
{
|
||||
d->FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTabBar::setCurrentIndex(int index)
|
||||
{
|
||||
if (index == d->CurrentIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < -1 || index > (count() - 1))
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
||||
return;
|
||||
}
|
||||
|
||||
emit currentChanging(index);
|
||||
d->CurrentIndex = index;
|
||||
d->updateTabs();
|
||||
emit currentChanged(index);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaTabBar::count() const
|
||||
{
|
||||
// The tab bar contains a stretch item as last item
|
||||
return d->TabsLayout->count() - 1;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockAreaTabBar::insertTab(int Index, CDockWidgetTab* Tab)
|
||||
{
|
||||
d->TabsLayout->insertWidget(Index, Tab);
|
||||
connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked()));
|
||||
connect(Tab, SIGNAL(closeRequested()), this, SLOT(onTabCloseRequested()));
|
||||
connect(Tab, SIGNAL(closeOtherTabsRequested()), this, SLOT(onCloseOtherTabsRequested()));
|
||||
connect(Tab, SIGNAL(moved(const QPoint&)), this, SLOT(onTabWidgetMoved(const QPoint&)));
|
||||
Tab->installEventFilter(this);
|
||||
emit tabInserted(Index);
|
||||
if (Index <= d->CurrentIndex)
|
||||
{
|
||||
setCurrentIndex(d->CurrentIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab)
|
||||
{
|
||||
if (!count())
|
||||
{
|
||||
return;
|
||||
}
|
||||
ADS_PRINT("CDockAreaTabBar::removeTab ");
|
||||
int NewCurrentIndex = currentIndex();
|
||||
int RemoveIndex = d->TabsLayout->indexOf(Tab);
|
||||
if (count() == 1)
|
||||
{
|
||||
NewCurrentIndex = -1;
|
||||
}
|
||||
if (NewCurrentIndex > RemoveIndex)
|
||||
{
|
||||
NewCurrentIndex--;
|
||||
}
|
||||
else if (NewCurrentIndex == RemoveIndex)
|
||||
{
|
||||
NewCurrentIndex = -1;
|
||||
// First we walk to the right to search for the next visible tab
|
||||
for (int i = (RemoveIndex + 1); i < count(); ++i)
|
||||
{
|
||||
if (tab(i)->isVisibleTo(this))
|
||||
{
|
||||
NewCurrentIndex = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no visible tab right to this tab then we walk to
|
||||
// the left to find a visible tab
|
||||
if (NewCurrentIndex < 0)
|
||||
{
|
||||
for (int i = (RemoveIndex - 1); i >= 0; --i)
|
||||
{
|
||||
if (tab(i)->isVisibleTo(this))
|
||||
{
|
||||
NewCurrentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit removingTab(RemoveIndex);
|
||||
d->TabsLayout->removeWidget(Tab);
|
||||
Tab->disconnect(this);
|
||||
Tab->removeEventFilter(this);
|
||||
ADS_PRINT("NewCurrentIndex " << NewCurrentIndex);
|
||||
if (NewCurrentIndex != d->CurrentIndex)
|
||||
{
|
||||
setCurrentIndex(NewCurrentIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
d->updateTabs();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
int CDockAreaTabBar::currentIndex() const
|
||||
{
|
||||
return d->CurrentIndex;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
CDockWidgetTab* CDockAreaTabBar::currentTab() const
|
||||
{
|
||||
if (d->CurrentIndex < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(d->CurrentIndex)->widget());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockAreaTabBar::onTabClicked()
|
||||
{
|
||||
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
||||
if (!Tab)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int index = d->TabsLayout->indexOf(Tab);
|
||||
if (index < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
setCurrentIndex(index);
|
||||
emit tabBarClicked(index);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockAreaTabBar::onTabCloseRequested()
|
||||
{
|
||||
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
||||
int Index = d->TabsLayout->indexOf(Tab);
|
||||
closeTab(Index);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockAreaTabBar::onCloseOtherTabsRequested()
|
||||
{
|
||||
auto Sender = qobject_cast<CDockWidgetTab*>(sender());
|
||||
for (int i = 0; i < count(); ++i)
|
||||
{
|
||||
auto Tab = tab(i);
|
||||
if (Tab->isClosable() && !Tab->isHidden() && Tab != Sender)
|
||||
{
|
||||
// If the dock widget is deleted with the closeTab() call, its tab
|
||||
// it will no longer be in the layout, and thus the index needs to
|
||||
// be updated to not skip any tabs
|
||||
int Offset = Tab->dockWidget()->features().testFlag(
|
||||
CDockWidget::DockWidgetDeleteOnClose) ? 1 : 0;
|
||||
closeTab(i);
|
||||
|
||||
// If the the dock widget blocks closing, i.e. if the flag
|
||||
// CustomCloseHandling is set, and the dock widget is still open,
|
||||
// then we do not need to correct the index
|
||||
if (Tab->dockWidget()->isClosed())
|
||||
{
|
||||
i -= Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
CDockWidgetTab* CDockAreaTabBar::tab(int Index) const
|
||||
{
|
||||
if (Index >= count() || Index < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(Index)->widget());
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos)
|
||||
{
|
||||
CDockWidgetTab* MovingTab = qobject_cast<CDockWidgetTab*>(sender());
|
||||
if (!MovingTab)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int fromIndex = d->TabsLayout->indexOf(MovingTab);
|
||||
auto MousePos = mapFromGlobal(GlobalPos);
|
||||
int toIndex = -1;
|
||||
// Find tab under mouse
|
||||
for (int i = 0; i < count(); ++i)
|
||||
{
|
||||
CDockWidgetTab* DropTab = tab(i);
|
||||
if (DropTab == MovingTab || !DropTab->isVisibleTo(this)
|
||||
|| !DropTab->geometry().contains(MousePos))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
toIndex = d->TabsLayout->indexOf(DropTab);
|
||||
if (toIndex == fromIndex)
|
||||
{
|
||||
toIndex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (toIndex < 0)
|
||||
{
|
||||
toIndex = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Now check if the mouse is behind the last tab
|
||||
if (toIndex < 0)
|
||||
{
|
||||
if (MousePos.x() > tab(count() - 1)->geometry().right())
|
||||
{
|
||||
ADS_PRINT("after all tabs");
|
||||
toIndex = count() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
toIndex = fromIndex;
|
||||
}
|
||||
}
|
||||
|
||||
d->TabsLayout->removeWidget(MovingTab);
|
||||
d->TabsLayout->insertWidget(toIndex, MovingTab);
|
||||
if (toIndex >= 0)
|
||||
{
|
||||
ADS_PRINT("tabMoved from " << fromIndex << " to " << toIndex);
|
||||
emit tabMoved(fromIndex, toIndex);
|
||||
setCurrentIndex(toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockAreaTabBar::closeTab(int Index)
|
||||
{
|
||||
if (Index < 0 || Index >= count())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto Tab = tab(Index);
|
||||
if (Tab->isHidden())
|
||||
{
|
||||
return;
|
||||
}
|
||||
//Tab->hide();
|
||||
emit tabCloseRequested(Index);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
bool Result = Super::eventFilter(watched, event);
|
||||
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(watched);
|
||||
if (!Tab)
|
||||
{
|
||||
return Result;
|
||||
}
|
||||
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::Hide:
|
||||
emit tabClosed(d->TabsLayout->indexOf(Tab)); break;
|
||||
case QEvent::Show:
|
||||
emit tabOpened(d->TabsLayout->indexOf(Tab)); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
bool CDockAreaTabBar::isTabOpen(int Index) const
|
||||
{
|
||||
if (Index < 0 || Index >= count())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !tab(Index)->isHidden();
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
QSize CDockAreaTabBar::minimumSizeHint() const
|
||||
{
|
||||
QSize Size = sizeHint();
|
||||
Size.setWidth(Super::minimumSizeHint().width());// this defines the minimum width of a dock area
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
QSize CDockAreaTabBar::sizeHint() const
|
||||
{
|
||||
QSize Size = Super::sizeHint();
|
||||
Size.setHeight(d->TabsContainerWidget->sizeHint().height());
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
eDragState CDockAreaTabBar::dragState() const
|
||||
{
|
||||
return d->DragState;
|
||||
}
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
#ifndef DockAreaTabBarH
|
||||
#define DockAreaTabBarH
|
||||
/*******************************************************************************
|
||||
** Qt Advanced Docking System
|
||||
** Copyright (C) 2017 Uwe Kindler
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU Lesser General Public
|
||||
** License as published by the Free Software Foundation; either
|
||||
** version 2.1 of the License, or (at your option) any later version.
|
||||
**
|
||||
** This library is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public
|
||||
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DockAreaTabBar.h
|
||||
/// \author Uwe Kindler
|
||||
@@ -11,26 +30,43 @@
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <QScrollArea>
|
||||
#include "ads_globals.h"
|
||||
|
||||
namespace ads
|
||||
{
|
||||
class CDockAreaWidget;
|
||||
class CDockWidgetTab;
|
||||
struct DockAreaTabBarPrivate;
|
||||
class CDockAreaTitleBar;
|
||||
class CFloatingDockContainer;
|
||||
class IFloatingWidget;
|
||||
|
||||
/**
|
||||
* Custom tabbar implementation for tab area that is shown on top of a
|
||||
* dock area widget.
|
||||
* The tabbar displays the tab widgets of the contained dock widgets.
|
||||
* We cannot use QTabBar here because it does a lot of fancy animations
|
||||
* that will crash the application if a tab is removed while the animation
|
||||
* has not finished. And we need to remove a tab, if the user drags a
|
||||
* a dock widget out of a group of tabbed widgets
|
||||
*/
|
||||
class CDockAreaTabBar : public QScrollArea
|
||||
class ADS_EXPORT CDockAreaTabBar : public QScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
DockAreaTabBarPrivate* d; ///< private data (pimpl)
|
||||
friend class DockAreaTabBarPrivate;
|
||||
friend struct DockAreaTabBarPrivate;
|
||||
friend class CDockAreaTitleBar;
|
||||
|
||||
private slots:
|
||||
void onTabClicked();
|
||||
void onTabCloseRequested();
|
||||
void onCloseOtherTabsRequested();
|
||||
void onTabWidgetMoved(const QPoint& GlobalPos);
|
||||
|
||||
protected:
|
||||
virtual void wheelEvent(QWheelEvent* Event) override;
|
||||
|
||||
/**
|
||||
* Stores mouse position to detect dragging
|
||||
*/
|
||||
@@ -55,9 +91,22 @@ protected:
|
||||
/**
|
||||
* Starts floating
|
||||
*/
|
||||
void startFloating(const QPoint& Pos);
|
||||
void startFloating(const QPoint& Offset);
|
||||
|
||||
/**
|
||||
* Makes the dock area floating
|
||||
*/
|
||||
IFloatingWidget* makeAreaFloating(const QPoint& Offset, eDragState DragState);
|
||||
|
||||
/**
|
||||
* Returns the current drag state
|
||||
*/
|
||||
eDragState dragState() const;
|
||||
|
||||
|
||||
public:
|
||||
using Super = QScrollArea;
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
@@ -67,6 +116,129 @@ public:
|
||||
* Virtual Destructor
|
||||
*/
|
||||
virtual ~CDockAreaTabBar();
|
||||
|
||||
/**
|
||||
* Inserts the given dock widget tab at the given position.
|
||||
* Inserting a new tab at an index less than or equal to the current index
|
||||
* will increment the current index, but keep the current tab.
|
||||
*/
|
||||
void insertTab(int Index, CDockWidgetTab* Tab);
|
||||
|
||||
/**
|
||||
* Removes the given DockWidgetTab from the tabbar
|
||||
*/
|
||||
void removeTab(CDockWidgetTab* Tab);
|
||||
|
||||
/**
|
||||
* Returns the number of tabs in this tabbar
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* Returns the current index or -1 if no tab is selected
|
||||
*/
|
||||
int currentIndex() const;
|
||||
|
||||
/**
|
||||
* Returns the current tab or a nullptr if no tab is selected.
|
||||
*/
|
||||
CDockWidgetTab* currentTab() const;
|
||||
|
||||
/**
|
||||
* Returns the tab with the given index
|
||||
*/
|
||||
CDockWidgetTab* tab(int Index) const;
|
||||
|
||||
/**
|
||||
* Filters the tab widget events
|
||||
*/
|
||||
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
/**
|
||||
* This function returns true if the tab is open, that means if it is
|
||||
* visible to the user. If the function returns false, the tab is
|
||||
* closed
|
||||
*/
|
||||
bool isTabOpen(int Index) const;
|
||||
|
||||
/**
|
||||
* Overrides the minimumSizeHint() function of QScrollArea
|
||||
* The minimumSizeHint() is bigger than the sizeHint () for the scroll
|
||||
* area because even if the scrollbars are invisible, the required speace
|
||||
* is reserved in the minimumSizeHint(). This override simply returns
|
||||
* sizeHint();
|
||||
*/
|
||||
virtual QSize minimumSizeHint() const override;
|
||||
|
||||
/**
|
||||
* The function provides a sizeHint that matches the height of the
|
||||
* internal viewport.
|
||||
*/
|
||||
virtual QSize sizeHint() const override;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* This property sets the index of the tab bar's visible tab
|
||||
*/
|
||||
void setCurrentIndex(int Index);
|
||||
|
||||
/**
|
||||
* This function will close the tab given in Index param.
|
||||
* Closing a tab means, the tab will be hidden, it will not be removed
|
||||
*/
|
||||
void closeTab(int Index);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted when the tab bar's current tab is about to be changed. The new
|
||||
* current has the given index, or -1 if there isn't a new one.
|
||||
*/
|
||||
void currentChanging(int Index);
|
||||
|
||||
/**
|
||||
* This signal is emitted when the tab bar's current tab changes. The new
|
||||
* current has the given index, or -1 if there isn't a new one
|
||||
*/
|
||||
void currentChanged(int Index);
|
||||
|
||||
/**
|
||||
* This signal is emitted when user clicks on a tab
|
||||
*/
|
||||
void tabBarClicked(int index);
|
||||
|
||||
/**
|
||||
* This signal is emitted when the close button on a tab is clicked.
|
||||
* The index is the index that should be closed.
|
||||
*/
|
||||
void tabCloseRequested(int index);
|
||||
|
||||
/**
|
||||
* This signal is emitted if a tab has been closed
|
||||
*/
|
||||
void tabClosed(int index);
|
||||
|
||||
/**
|
||||
* This signal is emitted if a tab has been opened.
|
||||
* A tab is opened if it has been made visible
|
||||
*/
|
||||
void tabOpened(int index);
|
||||
|
||||
/**
|
||||
* This signal is emitted when the tab has moved the tab at index position
|
||||
* from to index position to.
|
||||
*/
|
||||
void tabMoved(int from, int to);
|
||||
|
||||
/**
|
||||
* This signal is emitted, just before the tab with the given index is
|
||||
* removed
|
||||
*/
|
||||
void removingTab(int index);
|
||||
|
||||
/**
|
||||
* This signal is emitted if a tab has been inserted
|
||||
*/
|
||||
void tabInserted(int index);
|
||||
}; // class CDockAreaTabBar
|
||||
} // namespace ads
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
386
src/DockAreaTitleBar.cpp
Normal file
@@ -0,0 +1,386 @@
|
||||
/*******************************************************************************
|
||||
** Qt Advanced Docking System
|
||||
** Copyright (C) 2017 Uwe Kindler
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU Lesser General Public
|
||||
** License as published by the Free Software Foundation; either
|
||||
** version 2.1 of the License, or (at your option) any later version.
|
||||
**
|
||||
** This library is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public
|
||||
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DockAreaTitleBar.cpp
|
||||
/// \author Uwe Kindler
|
||||
/// \date 12.10.2018
|
||||
/// \brief Implementation of CDockAreaTitleBar class
|
||||
//============================================================================
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include "DockAreaTitleBar.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QToolButton>
|
||||
#include <QBoxLayout>
|
||||
#include <QStyle>
|
||||
#include <QMenu>
|
||||
#include <QScrollArea>
|
||||
#include <QMouseEvent>
|
||||
#include <QDebug>
|
||||
|
||||
#include "ads_globals.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockAreaWidget.h"
|
||||
#include "DockOverlay.h"
|
||||
#include "DockManager.h"
|
||||
#include "DockWidget.h"
|
||||
#include "DockWidgetTab.h"
|
||||
#include "DockAreaTabBar.h"
|
||||
#include "IconProvider.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace ads
|
||||
{
|
||||
using tTileBarButton = QToolButton;
|
||||
/**
|
||||
* Private data class of CDockAreaTitleBar class (pimpl)
|
||||
*/
|
||||
struct DockAreaTitleBarPrivate
|
||||
{
|
||||
CDockAreaTitleBar* _this;
|
||||
tTileBarButton* TabsMenuButton;
|
||||
tTileBarButton* UndockButton;
|
||||
tTileBarButton* CloseButton;
|
||||
QBoxLayout* TopLayout;
|
||||
CDockAreaWidget* DockArea;
|
||||
CDockAreaTabBar* TabBar;
|
||||
bool MenuOutdated = true;
|
||||
QMenu* TabsMenu;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
*/
|
||||
DockAreaTitleBarPrivate(CDockAreaTitleBar* _public);
|
||||
|
||||
/**
|
||||
* Creates the title bar close and menu buttons
|
||||
*/
|
||||
void createButtons();
|
||||
|
||||
/**
|
||||
* Creates the internal TabBar
|
||||
*/
|
||||
void createTabBar();
|
||||
|
||||
/**
|
||||
* Convenience function for DockManager access
|
||||
*/
|
||||
CDockManager* dockManager() const
|
||||
{
|
||||
return DockArea->dockManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given config flag is set
|
||||
*/
|
||||
bool testConfigFlag(CDockManager::eConfigFlag Flag) const
|
||||
{
|
||||
return CDockManager::configFlags().testFlag(Flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to set title bar button icons depending on operating
|
||||
* system and to avoid duplicated code. On windows the standard icons
|
||||
* are blurry since Qt 5.11 so we need to do some additional steps.
|
||||
* If the global IconPovider of the dockmanager provides a custom
|
||||
* Icon for the given CustomIconId, the this icon will be used.
|
||||
*/
|
||||
void setTitleBarButtonIcon(tTileBarButton* Button, QStyle::StandardPixmap StandarPixmap,
|
||||
ads::eIcon CustomIconId)
|
||||
{
|
||||
// First we try to use custom icons if available
|
||||
QIcon Icon = CDockManager::iconProvider().customIcon(CustomIconId);
|
||||
if (!Icon.isNull())
|
||||
{
|
||||
Button->setIcon(Icon);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
Button->setIcon(_this->style()->standardIcon(StandarPixmap));
|
||||
#else
|
||||
QPixmap normalPixmap = _this->style()->standardPixmap(StandarPixmap, 0, Button);
|
||||
Icon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25), QIcon::Disabled);
|
||||
Icon.addPixmap(normalPixmap, QIcon::Normal);
|
||||
Button->setIcon(Icon);
|
||||
#endif
|
||||
}
|
||||
};// struct DockAreaTitleBarPrivate
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) :
|
||||
_this(_public)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaTitleBarPrivate::createButtons()
|
||||
{
|
||||
QSizePolicy ButtonSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
// Tabs menu button
|
||||
TabsMenuButton = new tTileBarButton();
|
||||
TabsMenuButton->setObjectName("tabsMenuButton");
|
||||
TabsMenuButton->setAutoRaise(true);
|
||||
TabsMenuButton->setPopupMode(QToolButton::InstantPopup);
|
||||
setTitleBarButtonIcon(TabsMenuButton, QStyle::SP_TitleBarUnshadeButton, ads::DockAreaMenuIcon);
|
||||
QMenu* TabsMenu = new QMenu(TabsMenuButton);
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
TabsMenu->setToolTipsVisible(true);
|
||||
#endif
|
||||
_this->connect(TabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow()));
|
||||
TabsMenuButton->setMenu(TabsMenu);
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
TabsMenuButton->setToolTip(QObject::tr("List all tabs"));
|
||||
#endif
|
||||
TabsMenuButton->setSizePolicy(ButtonSizePolicy);
|
||||
TopLayout->addWidget(TabsMenuButton, 0);
|
||||
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
|
||||
SLOT(onTabsMenuActionTriggered(QAction*)));
|
||||
|
||||
|
||||
// Undock button
|
||||
UndockButton = new tTileBarButton();
|
||||
UndockButton->setObjectName("undockButton");
|
||||
UndockButton->setAutoRaise(true);
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
UndockButton->setToolTip(QObject::tr("Detach Group"));
|
||||
#endif
|
||||
setTitleBarButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon);
|
||||
UndockButton->setSizePolicy(ButtonSizePolicy);
|
||||
TopLayout->addWidget(UndockButton, 0);
|
||||
_this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked()));
|
||||
|
||||
|
||||
// Close button
|
||||
CloseButton = new tTileBarButton();
|
||||
CloseButton->setObjectName("closeButton");
|
||||
CloseButton->setAutoRaise(true);
|
||||
setTitleBarButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon);
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
if (testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||
{
|
||||
CloseButton->setToolTip(QObject::tr("Close Active Tab"));
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseButton->setToolTip(QObject::tr("Close Group"));
|
||||
}
|
||||
#endif
|
||||
CloseButton->setSizePolicy(ButtonSizePolicy);
|
||||
CloseButton->setIconSize(QSize(16, 16));
|
||||
if (testConfigFlag(CDockManager::DockAreaHasCloseButton))
|
||||
{
|
||||
TopLayout->addWidget(CloseButton, 0);
|
||||
}
|
||||
_this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked()));
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaTitleBarPrivate::createTabBar()
|
||||
{
|
||||
TabBar = new CDockAreaTabBar(DockArea);
|
||||
TopLayout->addWidget(TabBar);
|
||||
_this->connect(TabBar, SIGNAL(tabClosed(int)), SLOT(markTabsMenuOutdated()));
|
||||
_this->connect(TabBar, SIGNAL(tabOpened(int)), SLOT(markTabsMenuOutdated()));
|
||||
_this->connect(TabBar, SIGNAL(tabInserted(int)), SLOT(markTabsMenuOutdated()));
|
||||
_this->connect(TabBar, SIGNAL(removingTab(int)), SLOT(markTabsMenuOutdated()));
|
||||
_this->connect(TabBar, SIGNAL(tabMoved(int, int)), SLOT(markTabsMenuOutdated()));
|
||||
_this->connect(TabBar, SIGNAL(currentChanged(int)), SLOT(onCurrentTabChanged(int)));
|
||||
_this->connect(TabBar, SIGNAL(tabBarClicked(int)), SIGNAL(tabBarClicked(int)));
|
||||
|
||||
TabBar->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
_this->connect(TabBar, SIGNAL(customContextMenuRequested(const QPoint&)),
|
||||
SLOT(showContextMenu(const QPoint&)));
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) :
|
||||
QFrame(parent),
|
||||
d(new DockAreaTitleBarPrivate(this))
|
||||
{
|
||||
d->DockArea = parent;
|
||||
|
||||
setObjectName("dockAreaTitleBar");
|
||||
d->TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
d->TopLayout->setContentsMargins(0, 0, 0, 0);
|
||||
d->TopLayout->setSpacing(0);
|
||||
setLayout(d->TopLayout);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
d->createTabBar();
|
||||
d->createButtons();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockAreaTitleBar::~CDockAreaTitleBar()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockAreaTabBar* CDockAreaTitleBar::tabBar() const
|
||||
{
|
||||
return d->TabBar;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::markTabsMenuOutdated()
|
||||
{
|
||||
d->MenuOutdated = true;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::onTabsMenuAboutToShow()
|
||||
{
|
||||
if (!d->MenuOutdated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu* menu = d->TabsMenuButton->menu();
|
||||
menu->clear();
|
||||
for (int i = 0; i < d->TabBar->count(); ++i)
|
||||
{
|
||||
if (!d->TabBar->isTabOpen(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto Tab = d->TabBar->tab(i);
|
||||
QAction* Action = menu->addAction(Tab->icon(), Tab->text());
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
Action->setToolTip(Tab->toolTip());
|
||||
#endif
|
||||
Action->setData(i);
|
||||
}
|
||||
|
||||
d->MenuOutdated = false;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::onCloseButtonClicked()
|
||||
{
|
||||
ADS_PRINT("CDockAreaTitleBar::onCloseButtonClicked");
|
||||
if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||
{
|
||||
d->TabBar->closeTab(d->TabBar->currentIndex());
|
||||
}
|
||||
else
|
||||
{
|
||||
d->DockArea->closeArea();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::onUndockButtonClicked()
|
||||
{
|
||||
if (d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||
{
|
||||
d->TabBar->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::onTabsMenuActionTriggered(QAction* Action)
|
||||
{
|
||||
int Index = Action->data().toInt();
|
||||
d->TabBar->setCurrentIndex(Index);
|
||||
emit tabBarClicked(Index);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::onCurrentTabChanged(int Index)
|
||||
{
|
||||
if (Index < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||
{
|
||||
CDockWidget* DockWidget = d->TabBar->tab(Index)->dockWidget();
|
||||
d->CloseButton->setEnabled(DockWidget->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const
|
||||
{
|
||||
switch (which)
|
||||
{
|
||||
case TitleBarButtonTabsMenu: return d->TabsMenuButton;
|
||||
case TitleBarButtonUndock: return d->UndockButton;
|
||||
case TitleBarButtonClose: return d->CloseButton;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::setVisible(bool Visible)
|
||||
{
|
||||
Super::setVisible(Visible);
|
||||
markTabsMenuOutdated();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaTitleBar::showContextMenu(const QPoint& pos)
|
||||
{
|
||||
if (d->TabBar->dragState() == DraggingFloatingWidget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QMenu Menu(this);
|
||||
auto Action = Menu.addAction(tr("Detach Area"), this, SLOT(onUndockButtonClicked()));
|
||||
Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable));
|
||||
Menu.addSeparator();
|
||||
Action = Menu.addAction(tr("Close Area"), this, SLOT(onCloseButtonClicked()));
|
||||
Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||
Menu.addAction(tr("Close Other Areas"), d->DockArea, SLOT(closeOtherAreas()));
|
||||
Menu.exec(mapToGlobal(pos));
|
||||
}
|
||||
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// EOF DockAreaTitleBar.cpp
|
||||
112
src/DockAreaTitleBar.h
Normal file
@@ -0,0 +1,112 @@
|
||||
#ifndef DockAreaTitleBarH
|
||||
#define DockAreaTitleBarH
|
||||
/*******************************************************************************
|
||||
** Qt Advanced Docking System
|
||||
** Copyright (C) 2017 Uwe Kindler
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU Lesser General Public
|
||||
** License as published by the Free Software Foundation; either
|
||||
** version 2.1 of the License, or (at your option) any later version.
|
||||
**
|
||||
** This library is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public
|
||||
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DockAreaTitleBar.h
|
||||
/// \author Uwe Kindler
|
||||
/// \date 12.10.2018
|
||||
/// \brief Declaration of CDockAreaTitleBar class
|
||||
//============================================================================
|
||||
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <QFrame>
|
||||
|
||||
#include "ads_globals.h"
|
||||
|
||||
class QAbstractButton;
|
||||
|
||||
namespace ads
|
||||
{
|
||||
class CDockAreaTabBar;
|
||||
class CDockAreaWidget;
|
||||
struct DockAreaTitleBarPrivate;
|
||||
|
||||
/**
|
||||
* Title bar of a dock area.
|
||||
* The title bar contains a tabbar with all tabs for a dock widget group and
|
||||
* with a tabs menu button, a undock button and a close button.
|
||||
*/
|
||||
class ADS_EXPORT CDockAreaTitleBar : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
DockAreaTitleBarPrivate* d; ///< private data (pimpl)
|
||||
friend struct DockAreaTitleBarPrivate;
|
||||
|
||||
private slots:
|
||||
void onTabsMenuAboutToShow();
|
||||
void onCloseButtonClicked();
|
||||
void onUndockButtonClicked();
|
||||
void onTabsMenuActionTriggered(QAction* Action);
|
||||
void onCurrentTabChanged(int Index);
|
||||
void showContextMenu(const QPoint& pos);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Call this slot to tell the title bar that it should update the tabs menu
|
||||
* the next time it is shown.
|
||||
*/
|
||||
void markTabsMenuOutdated();
|
||||
|
||||
|
||||
public:
|
||||
using Super = QFrame;
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
CDockAreaTitleBar(CDockAreaWidget* parent);
|
||||
|
||||
/**
|
||||
* Virtual Destructor
|
||||
*/
|
||||
virtual ~CDockAreaTitleBar();
|
||||
|
||||
/**
|
||||
* Returns the pointer to the tabBar()
|
||||
*/
|
||||
CDockAreaTabBar* tabBar() const;
|
||||
|
||||
/**
|
||||
* Returns the button corresponding to the given title bar button identifier
|
||||
*/
|
||||
QAbstractButton* button(TitleBarButton which) const;
|
||||
|
||||
/**
|
||||
* Marks the tabs menu outdated before it calls its base class
|
||||
* implementation
|
||||
*/
|
||||
virtual void setVisible(bool Visible) override;
|
||||
|
||||
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted if a tab in the tab bar is clicked by the user
|
||||
* or if the user clicks on a tab item in the title bar tab menu.
|
||||
*/
|
||||
void tabBarClicked(int index);
|
||||
}; // class name
|
||||
}
|
||||
// namespace ads
|
||||
//-----------------------------------------------------------------------------
|
||||
#endif // DockAreaTitleBarH
|
||||
@@ -1,17 +1,17 @@
|
||||
/*******************************************************************************
|
||||
** Qt Advanced Docking System
|
||||
** Copyright (C) 2017 Uwe Kindler
|
||||
**
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU Lesser General Public
|
||||
** License as published by the Free Software Foundation; either
|
||||
** version 2.1 of the License, or (at your option) any later version.
|
||||
**
|
||||
**
|
||||
** This library is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Lesser General Public License for more details.
|
||||
**
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public
|
||||
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
@@ -28,7 +28,7 @@
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <DockWidgetTab.h>
|
||||
#include "DockWidgetTab.h"
|
||||
#include "DockAreaWidget.h"
|
||||
|
||||
#include <QStackedLayout>
|
||||
@@ -41,6 +41,8 @@
|
||||
#include <QMenu>
|
||||
#include <QSplitter>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QVector>
|
||||
#include <QList>
|
||||
|
||||
|
||||
#include "DockContainerWidget.h"
|
||||
@@ -49,13 +51,187 @@
|
||||
#include "DockManager.h"
|
||||
#include "DockOverlay.h"
|
||||
#include "DockAreaTabBar.h"
|
||||
#include "DockSplitter.h"
|
||||
#include "DockAreaTitleBar.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace ads
|
||||
{
|
||||
static const char* const INDEX_PROPERTY = "index";
|
||||
static const char* const ACTION_PROPERTY = "action";
|
||||
static const int APPEND = -1;
|
||||
|
||||
/**
|
||||
* Internal dock area layout mimics stack layout but only inserts the current
|
||||
* widget into the internal QLayout object.
|
||||
* \warning Only the current widget has a parent. All other widgets
|
||||
* do not have a parent. That means, a widget that is in this layout may
|
||||
* return nullptr for its parent() function if it is not the current widget.
|
||||
*/
|
||||
class CDockAreaLayout
|
||||
{
|
||||
private:
|
||||
QBoxLayout* m_ParentLayout;
|
||||
QList<QWidget*> m_Widgets;
|
||||
int m_CurrentIndex = -1;
|
||||
QWidget* m_CurrentWidget = nullptr;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an instance with the given parent layout
|
||||
*/
|
||||
CDockAreaLayout(QBoxLayout* ParentLayout)
|
||||
: m_ParentLayout(ParentLayout)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of widgets in this layout
|
||||
*/
|
||||
int count() const
|
||||
{
|
||||
return m_Widgets.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the widget at the given index position into the internal widget
|
||||
* list
|
||||
*/
|
||||
void insertWidget(int index, QWidget* Widget)
|
||||
{
|
||||
Widget->setParent(nullptr);
|
||||
if (index < 0)
|
||||
{
|
||||
index = m_Widgets.count();
|
||||
}
|
||||
m_Widgets.insert(index, Widget);
|
||||
if (m_CurrentIndex < 0)
|
||||
{
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index <= m_CurrentIndex )
|
||||
{
|
||||
++m_CurrentIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given widget from the layout
|
||||
*/
|
||||
void removeWidget(QWidget* Widget)
|
||||
{
|
||||
if (currentWidget() == Widget)
|
||||
{
|
||||
auto LayoutItem = m_ParentLayout->takeAt(1);
|
||||
if (LayoutItem)
|
||||
{
|
||||
LayoutItem->widget()->setParent(nullptr);
|
||||
}
|
||||
m_CurrentWidget = nullptr;
|
||||
m_CurrentIndex = -1;
|
||||
}
|
||||
m_Widgets.removeOne(Widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current selected widget
|
||||
*/
|
||||
QWidget* currentWidget() const
|
||||
{
|
||||
return m_CurrentWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the widget with the give index.
|
||||
*/
|
||||
void setCurrentIndex(int index)
|
||||
{
|
||||
QWidget *prev = currentWidget();
|
||||
QWidget *next = widget(index);
|
||||
if (!next || (next == prev && !m_CurrentWidget))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool reenableUpdates = false;
|
||||
QWidget *parent = m_ParentLayout->parentWidget();
|
||||
|
||||
if (parent && parent->updatesEnabled())
|
||||
{
|
||||
reenableUpdates = true;
|
||||
parent->setUpdatesEnabled(false);
|
||||
}
|
||||
|
||||
auto LayoutItem = m_ParentLayout->takeAt(1);
|
||||
if (LayoutItem)
|
||||
{
|
||||
LayoutItem->widget()->setParent(nullptr);
|
||||
}
|
||||
|
||||
m_ParentLayout->addWidget(next);
|
||||
if (prev)
|
||||
{
|
||||
prev->hide();
|
||||
}
|
||||
m_CurrentIndex = index;
|
||||
m_CurrentWidget = next;
|
||||
|
||||
|
||||
if (reenableUpdates)
|
||||
{
|
||||
parent->setUpdatesEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the current active widget
|
||||
*/
|
||||
int currentIndex() const
|
||||
{
|
||||
return m_CurrentIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are no widgets in the layout
|
||||
*/
|
||||
bool isEmpty() const
|
||||
{
|
||||
return m_Widgets.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the given widget
|
||||
*/
|
||||
int indexOf(QWidget* w) const
|
||||
{
|
||||
return m_Widgets.indexOf(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the widget for the given index
|
||||
*/
|
||||
QWidget* widget(int index) const
|
||||
{
|
||||
return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the geometry of the current active widget
|
||||
*/
|
||||
QRect geometry() const
|
||||
{
|
||||
return m_Widgets.empty() ? QRect() : currentWidget()->geometry();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
using DockAreaLayout = CDockAreaLayout;
|
||||
|
||||
|
||||
/**
|
||||
@@ -63,18 +239,12 @@ static const int APPEND = -1;
|
||||
*/
|
||||
struct DockAreaWidgetPrivate
|
||||
{
|
||||
CDockAreaWidget* _this;
|
||||
QBoxLayout* Layout;
|
||||
QFrame* TitleBar;
|
||||
QBoxLayout* TopLayout;
|
||||
QStackedLayout* ContentsLayout;
|
||||
CDockAreaTabBar* TabBar;
|
||||
QWidget* TabsContainerWidget;
|
||||
QBoxLayout* TabsLayout;
|
||||
QPushButton* TabsMenuButton;
|
||||
QPushButton* CloseButton;
|
||||
int TabsLayoutInitCount;
|
||||
CDockManager* DockManager = nullptr;
|
||||
CDockAreaWidget* _this = nullptr;
|
||||
QBoxLayout* Layout = nullptr;
|
||||
DockAreaLayout* ContentsLayout = nullptr;
|
||||
CDockAreaTitleBar* TitleBar = nullptr;
|
||||
CDockManager* DockManager = nullptr;
|
||||
bool UpdateTitleBarButtons = false;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@@ -84,7 +254,7 @@ struct DockAreaWidgetPrivate
|
||||
/**
|
||||
* Creates the layout for top area with tabs and close button
|
||||
*/
|
||||
void createTabBar();
|
||||
void createTitleBar();
|
||||
|
||||
/**
|
||||
* Returns the dock widget with the given index
|
||||
@@ -97,18 +267,11 @@ struct DockAreaWidgetPrivate
|
||||
/**
|
||||
* Convenience function to ease title widget access by index
|
||||
*/
|
||||
CDockWidgetTab* titleWidgetAt(int index)
|
||||
CDockWidgetTab* tabWidgetAt(int index)
|
||||
{
|
||||
return dockWidgetAt(index)->titleBar();
|
||||
return dockWidgetAt(index)->tabWidget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tabs menu entry for the given dock widget
|
||||
* If menu is 0, a menu entry is added to the menu of the TabsMenuButton
|
||||
* member. If menu is a valid menu pointer, the entry will be added to
|
||||
* the given menu
|
||||
*/
|
||||
void addTabsMenuEntry(CDockWidget* DockWidget, int Index = -1, QMenu* menu = 0);
|
||||
|
||||
/**
|
||||
* Returns the tab action of the given dock widget
|
||||
@@ -127,16 +290,17 @@ struct DockAreaWidgetPrivate
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tabs menu if dock widget order changed or if dock widget has
|
||||
* been removed
|
||||
* Convenience function for tabbar access
|
||||
*/
|
||||
void updateTabsMenu();
|
||||
CDockAreaTabBar* tabBar() const
|
||||
{
|
||||
return TitleBar->tabBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tab bar visibility depending on the number of dock widgets
|
||||
* in this area
|
||||
* Udpates the enable state of the close and detach button
|
||||
*/
|
||||
void updateTabBar();
|
||||
void updateTitleBarButtonStates();
|
||||
};
|
||||
// struct DockAreaWidgetPrivate
|
||||
|
||||
@@ -150,102 +314,30 @@ DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) :
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaWidgetPrivate::createTabBar()
|
||||
void DockAreaWidgetPrivate::createTitleBar()
|
||||
{
|
||||
TitleBar = new QFrame(_this);
|
||||
TitleBar->setObjectName("dockAreaTitleBar");
|
||||
TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
TopLayout->setContentsMargins(0, 0, 0, 0);
|
||||
TopLayout->setSpacing(0);
|
||||
TitleBar->setLayout(TopLayout);
|
||||
TitleBar = new CDockAreaTitleBar(_this);
|
||||
Layout->addWidget(TitleBar);
|
||||
|
||||
TabBar = new CDockAreaTabBar(_this);
|
||||
TopLayout->addWidget(TabBar, 1);
|
||||
|
||||
TabsContainerWidget = new QWidget();
|
||||
TabsContainerWidget->setObjectName("tabsContainerWidget");
|
||||
TabBar->setWidget(TabsContainerWidget);
|
||||
|
||||
TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
TabsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
TabsLayout->setSpacing(0);
|
||||
TabsLayout->addStretch(1);
|
||||
TabsContainerWidget->setLayout(TabsLayout);
|
||||
|
||||
TabsMenuButton = new QPushButton();
|
||||
TabsMenuButton->setObjectName("tabsMenuButton");
|
||||
TabsMenuButton->setFlat(true);
|
||||
TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton));
|
||||
TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width());
|
||||
TabsMenuButton->setMenu(new QMenu(TabsMenuButton));
|
||||
TopLayout->addWidget(TabsMenuButton, 0);
|
||||
TabsMenuButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
|
||||
SLOT(onTabsMenuActionTriggered(QAction*)));
|
||||
|
||||
CloseButton = new QPushButton();
|
||||
CloseButton->setObjectName("closeButton");
|
||||
CloseButton->setFlat(true);
|
||||
CloseButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
|
||||
CloseButton->setToolTip(_this->tr("Close"));
|
||||
CloseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
TopLayout->addWidget(CloseButton, 0);
|
||||
_this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked()));
|
||||
|
||||
TabsLayoutInitCount = TabsLayout->count();
|
||||
QObject::connect(tabBar(), &CDockAreaTabBar::tabCloseRequested, _this, &CDockAreaWidget::onTabCloseRequested);
|
||||
QObject::connect(TitleBar, &CDockAreaTitleBar::tabBarClicked, _this, &CDockAreaWidget::setCurrentIndex);
|
||||
QObject::connect(tabBar(), &CDockAreaTabBar::tabMoved, _this, &CDockAreaWidget::reorderDockWidget);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaWidgetPrivate::updateTabBar()
|
||||
void DockAreaWidgetPrivate::updateTitleBarButtonStates()
|
||||
{
|
||||
CDockContainerWidget* Container = _this->dockContainer();
|
||||
if (!Container)
|
||||
if (_this->isHidden())
|
||||
{
|
||||
UpdateTitleBarButtons = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Container->isFloating() && (Container->dockAreaCount() == 1) && (_this->count() == 1))
|
||||
{
|
||||
TitleBar->setVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleBar->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget,
|
||||
int Index, QMenu* menu)
|
||||
{
|
||||
menu = menu ? menu : TabsMenuButton->menu();
|
||||
QAction* Action;
|
||||
if (Index >= 0 && Index < menu->actions().count())
|
||||
{
|
||||
Action = new QAction(DockWidget->icon(), DockWidget->windowTitle());
|
||||
menu->insertAction(menu->actions().at(Index), Action);
|
||||
}
|
||||
else
|
||||
{
|
||||
Action = menu->addAction(DockWidget->icon(), DockWidget->windowTitle());
|
||||
}
|
||||
QVariant vAction = QVariant::fromValue(Action);
|
||||
DockWidget->setProperty(ACTION_PROPERTY, vAction);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaWidgetPrivate::updateTabsMenu()
|
||||
{
|
||||
QMenu* menu = TabsMenuButton->menu();
|
||||
menu->clear();
|
||||
for (int i = 0; i < ContentsLayout->count(); ++i)
|
||||
{
|
||||
addTabsMenuEntry(dockWidgetAt(i), APPEND, menu);
|
||||
}
|
||||
TitleBar->button(TitleBarButtonClose)->setEnabled(
|
||||
_this->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||
TitleBar->button(TitleBarButtonUndock)->setEnabled(
|
||||
_this->features().testFlag(CDockWidget::DockWidgetFloatable));
|
||||
UpdateTitleBarButtons = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,18 +352,19 @@ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget
|
||||
d->Layout->setSpacing(0);
|
||||
setLayout(d->Layout);
|
||||
|
||||
d->createTabBar();
|
||||
|
||||
d->ContentsLayout = new QStackedLayout();
|
||||
d->ContentsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
d->ContentsLayout->setSpacing(0);
|
||||
d->Layout->addLayout(d->ContentsLayout, 1);
|
||||
d->createTitleBar();
|
||||
d->ContentsLayout = new DockAreaLayout(d->Layout);
|
||||
if (d->DockManager)
|
||||
{
|
||||
emit d->DockManager->dockAreaCreated(this);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
CDockAreaWidget::~CDockAreaWidget()
|
||||
{
|
||||
qDebug() << "~CDockAreaWidget()";
|
||||
ADS_PRINT("~CDockAreaWidget()");
|
||||
delete d->ContentsLayout;
|
||||
delete d;
|
||||
}
|
||||
|
||||
@@ -286,18 +379,7 @@ CDockManager* CDockAreaWidget::dockManager() const
|
||||
//============================================================================
|
||||
CDockContainerWidget* CDockAreaWidget::dockContainer() const
|
||||
{
|
||||
QWidget* Parent = parentWidget();
|
||||
while (Parent)
|
||||
{
|
||||
CDockContainerWidget* Container = dynamic_cast<CDockContainerWidget*>(Parent);
|
||||
if (Container)
|
||||
{
|
||||
return Container;
|
||||
}
|
||||
Parent = Parent->parentWidget();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return internal::findParent<CDockContainerWidget*>(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -313,83 +395,149 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
|
||||
bool Activate)
|
||||
{
|
||||
d->ContentsLayout->insertWidget(index, DockWidget);
|
||||
DockWidget->titleBar()->setDockAreaWidget(this);
|
||||
auto TitleBar = DockWidget->titleBar();
|
||||
d->TabsLayout->insertWidget(index, TitleBar);
|
||||
TitleBar->show();
|
||||
connect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked()));
|
||||
DockWidget->tabWidget()->setDockAreaWidget(this);
|
||||
auto TabWidget = DockWidget->tabWidget();
|
||||
// Inserting the tab will change the current index which in turn will
|
||||
// make the tab widget visible in the slot
|
||||
d->tabBar()->blockSignals(true);
|
||||
d->tabBar()->insertTab(index, TabWidget);
|
||||
d->tabBar()->blockSignals(false);
|
||||
TabWidget->setVisible(!DockWidget->isClosed());
|
||||
DockWidget->setProperty(INDEX_PROPERTY, index);
|
||||
if (Activate)
|
||||
{
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
d->addTabsMenuEntry(DockWidget, index);
|
||||
DockWidget->setDockArea(this);
|
||||
d->updateTitleBarButtonStates();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
|
||||
{
|
||||
qDebug() << "CDockAreaWidget::removeDockWidget";
|
||||
d->ContentsLayout->removeWidget(DockWidget);
|
||||
auto TitleBar = DockWidget->titleBar();
|
||||
TitleBar->hide();
|
||||
d->TabsLayout->removeWidget(TitleBar);
|
||||
disconnect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked()));
|
||||
setCurrentIndex(d->ContentsLayout->currentIndex());
|
||||
d->updateTabsMenu();
|
||||
ADS_PRINT("CDockAreaWidget::removeDockWidget");
|
||||
auto NextOpenDockWidget = nextOpenDockWidget(DockWidget);
|
||||
|
||||
d->ContentsLayout->removeWidget(DockWidget);
|
||||
auto TabWidget = DockWidget->tabWidget();
|
||||
TabWidget->hide();
|
||||
d->tabBar()->removeTab(TabWidget);
|
||||
CDockContainerWidget* DockContainer = dockContainer();
|
||||
if (d->ContentsLayout->isEmpty())
|
||||
if (NextOpenDockWidget)
|
||||
{
|
||||
qDebug() << "Dock Area empty";
|
||||
dockContainer()->removeDockArea(this);
|
||||
this->deleteLater();;
|
||||
setCurrentDockWidget(NextOpenDockWidget);
|
||||
}
|
||||
else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() > 1)
|
||||
{
|
||||
ADS_PRINT("Dock Area empty");
|
||||
DockContainer->removeDockArea(this);
|
||||
this->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
// if contents layout is not empty but there are no more open dock
|
||||
// widgets, then we need to hide the dock area because it does not
|
||||
// contain any visible content
|
||||
hideAreaWithNoVisibleContent();
|
||||
}
|
||||
|
||||
d->updateTabBar();
|
||||
DockWidget->setDockArea(nullptr);
|
||||
d->updateTitleBarButtonStates();
|
||||
updateTitleBarVisibility();
|
||||
auto TopLevelDockWidget = DockContainer->topLevelDockWidget();
|
||||
if (TopLevelDockWidget)
|
||||
{
|
||||
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||
}
|
||||
|
||||
#if (ADS_DEBUG_LEVEL > 0)
|
||||
DockContainer->dumpLayout();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::onDockWidgetTitleClicked()
|
||||
void CDockAreaWidget::hideAreaWithNoVisibleContent()
|
||||
{
|
||||
CDockWidgetTab* TitleWidget = qobject_cast<CDockWidgetTab*>(sender());
|
||||
if (!TitleWidget)
|
||||
this->toggleView(false);
|
||||
|
||||
// Hide empty parent splitters
|
||||
auto Splitter = internal::findParent<CDockSplitter*>(this);
|
||||
internal::hideEmptyParentSplitters(Splitter);
|
||||
|
||||
//Hide empty floating widget
|
||||
CDockContainerWidget* Container = this->dockContainer();
|
||||
if (!Container->isFloating())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int index = d->TabsLayout->indexOf(TitleWidget);
|
||||
setCurrentIndex(index);
|
||||
updateTitleBarVisibility();
|
||||
auto TopLevelWidget = Container->topLevelDockWidget();
|
||||
auto FloatingWidget = Container->floatingWidget();
|
||||
if (TopLevelWidget)
|
||||
{
|
||||
FloatingWidget->updateWindowTitle();
|
||||
CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
|
||||
}
|
||||
else if (Container->openedDockAreas().isEmpty())
|
||||
{
|
||||
FloatingWidget->hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::onCloseButtonClicked()
|
||||
void CDockAreaWidget::onTabCloseRequested(int Index)
|
||||
{
|
||||
currentDockWidget()->toggleView(false);
|
||||
ADS_PRINT("CDockAreaWidget::onTabCloseRequested " << Index);
|
||||
auto* DockWidget = dockWidget(Index);
|
||||
if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||
{
|
||||
//DockWidget->deleteDockWidget();
|
||||
DockWidget->closeDockWidgetInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
DockWidget->toggleView(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidget* CDockAreaWidget::currentDockWidget() const
|
||||
{
|
||||
return dockWidget(currentIndex());
|
||||
int CurrentIndex = currentIndex();
|
||||
if (CurrentIndex < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return dockWidget(CurrentIndex);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
|
||||
{
|
||||
int Index = tabIndex(DockWidget);
|
||||
if (dockManager()->isRestoringState())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
internalSetCurrentDockWidget(DockWidget);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::internalSetCurrentDockWidget(CDockWidget* DockWidget)
|
||||
{
|
||||
int Index = index(DockWidget);
|
||||
if (Index < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentIndex(Index);
|
||||
}
|
||||
|
||||
@@ -397,43 +545,22 @@ void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
|
||||
//============================================================================
|
||||
void CDockAreaWidget::setCurrentIndex(int index)
|
||||
{
|
||||
if (index < 0 || index > (d->TabsLayout->count() - 1))
|
||||
auto TabBar = d->tabBar();
|
||||
if (index < 0 || index > (TabBar->count() - 1))
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
||||
return;
|
||||
}
|
||||
|
||||
emit currentChanging(index);
|
||||
|
||||
// Set active TAB and update all other tabs to be inactive
|
||||
for (int i = 0; i < d->TabsLayout->count(); ++i)
|
||||
auto cw = d->ContentsLayout->currentWidget();
|
||||
auto nw = d->ContentsLayout->widget(index);
|
||||
if (cw == nw && !nw->isHidden())
|
||||
{
|
||||
QLayoutItem* item = d->TabsLayout->itemAt(i);
|
||||
if (!item->widget())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto TitleWidget = dynamic_cast<CDockWidgetTab*>(item->widget());
|
||||
if (!TitleWidget)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == index)
|
||||
{
|
||||
TitleWidget->show();
|
||||
TitleWidget->setActiveTab(true);
|
||||
d->TabBar->ensureWidgetVisible(TitleWidget);
|
||||
auto Features = TitleWidget->dockWidget()->features();
|
||||
d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable));
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleWidget->setActiveTab(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
emit currentChanging(index);
|
||||
TabBar->setCurrentIndex(index);
|
||||
d->ContentsLayout->setCurrentIndex(index);
|
||||
d->ContentsLayout->currentWidget()->show();
|
||||
emit currentChanged(index);
|
||||
@@ -448,9 +575,9 @@ int CDockAreaWidget::currentIndex() const
|
||||
|
||||
|
||||
//============================================================================
|
||||
QRect CDockAreaWidget::titleAreaGeometry() const
|
||||
QRect CDockAreaWidget::titleBarGeometry() const
|
||||
{
|
||||
return d->TopLayout->geometry();
|
||||
return d->TitleBar->geometry();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
@@ -461,7 +588,7 @@ QRect CDockAreaWidget::contentAreaGeometry() const
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaWidget::tabIndex(CDockWidget* DockWidget)
|
||||
int CDockAreaWidget::index(CDockWidget* DockWidget)
|
||||
{
|
||||
return d->ContentsLayout->indexOf(DockWidget);
|
||||
}
|
||||
@@ -479,6 +606,21 @@ QList<CDockWidget*> CDockAreaWidget::dockWidgets() const
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaWidget::openDockWidgetsCount() const
|
||||
{
|
||||
int Count = 0;
|
||||
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||
{
|
||||
if (!dockWidget(i)->isClosed())
|
||||
{
|
||||
++Count;
|
||||
}
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
|
||||
{
|
||||
@@ -496,22 +638,22 @@ QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
|
||||
int CDockAreaWidget::indexOfFirstOpenDockWidget() const
|
||||
{
|
||||
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||
{
|
||||
auto TitleWidget = d->titleWidgetAt(i);
|
||||
if (TitleWidget->geometry().contains(p) && (!exclude || TitleWidget != exclude))
|
||||
if (!dockWidget(i)->isClosed())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaWidget::count() const
|
||||
int CDockAreaWidget::dockWidgetsCount() const
|
||||
{
|
||||
return d->ContentsLayout->count();
|
||||
}
|
||||
@@ -520,70 +662,74 @@ int CDockAreaWidget::count() const
|
||||
//============================================================================
|
||||
CDockWidget* CDockAreaWidget::dockWidget(int Index) const
|
||||
{
|
||||
return dynamic_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
|
||||
return qobject_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
|
||||
{
|
||||
ADS_PRINT("CDockAreaWidget::reorderDockWidget");
|
||||
if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0
|
||||
|| toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex)
|
||||
{
|
||||
qDebug() << "Invalid index for tab movement" << fromIndex << toIndex;
|
||||
d->TabsLayout->update();
|
||||
ADS_PRINT("Invalid index for tab movement" << fromIndex << toIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
CDockWidget* DockWidget = dockWidget(fromIndex);
|
||||
|
||||
// reorder tabs menu action to match new order of contents
|
||||
auto Menu = d->TabsMenuButton->menu();
|
||||
auto TabsAction = d->dockWidgetTabAction(DockWidget);
|
||||
Menu->removeAction(TabsAction);
|
||||
if (toIndex >= Menu->actions().count())
|
||||
{
|
||||
Menu->addAction(TabsAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu->insertAction(Menu->actions().at(toIndex), TabsAction);
|
||||
}
|
||||
|
||||
|
||||
// now reorder contents and title bars
|
||||
QLayoutItem* liFrom = nullptr;
|
||||
liFrom = d->TabsLayout->takeAt(fromIndex);
|
||||
d->TabsLayout->insertItem(toIndex, liFrom);
|
||||
liFrom = d->ContentsLayout->takeAt(fromIndex);
|
||||
d->ContentsLayout->insertWidget(toIndex, liFrom->widget());
|
||||
delete liFrom;
|
||||
auto Widget = d->ContentsLayout->widget(fromIndex);
|
||||
d->ContentsLayout->removeWidget(Widget);
|
||||
d->ContentsLayout->insertWidget(toIndex, Widget);
|
||||
setCurrentIndex(toIndex);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action)
|
||||
void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open)
|
||||
{
|
||||
int Index = d->TabsMenuButton->menu()->actions().indexOf(Action);
|
||||
setCurrentIndex(Index);
|
||||
Q_UNUSED(DockWidget);
|
||||
Q_UNUSED(Open);
|
||||
updateTitleBarVisibility();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::updateDockArea()
|
||||
void CDockAreaWidget::updateTitleBarVisibility()
|
||||
{
|
||||
d->updateTabBar();
|
||||
CDockContainerWidget* Container = dockContainer();
|
||||
if (!Container)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->TitleBar)
|
||||
{
|
||||
d->TitleBar->setVisible(!Container->isFloating() || !Container->hasTopLevelDockWidget());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::markTitleBarMenuOutdated()
|
||||
{
|
||||
if (d->TitleBar)
|
||||
{
|
||||
d->TitleBar->markTabsMenuOutdated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
|
||||
{
|
||||
s.writeStartElement("DockAreaWidget");
|
||||
s.writeStartElement("Area");
|
||||
s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count()));
|
||||
s.writeAttribute("CurrentIndex", QString::number(d->ContentsLayout->currentIndex()));
|
||||
qDebug() << "CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
|
||||
<< " CurrentIndex: " << d->ContentsLayout->currentIndex();
|
||||
auto CurrentDockWidget = currentDockWidget();
|
||||
QString Name = CurrentDockWidget ? CurrentDockWidget->objectName() : "";
|
||||
s.writeAttribute("Current", Name);
|
||||
ADS_PRINT("CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
|
||||
<< " Current: " << Name);
|
||||
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||
{
|
||||
dockWidget(i)->saveState(s);
|
||||
@@ -591,6 +737,109 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
|
||||
s.writeEndElement();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const
|
||||
{
|
||||
auto OpenDockWidgets = openedDockWidgets();
|
||||
if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget))
|
||||
{
|
||||
CDockWidget* NextDockWidget;
|
||||
if (OpenDockWidgets.last() == DockWidget)
|
||||
{
|
||||
NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
int NextIndex = OpenDockWidgets.indexOf(DockWidget) + 1;
|
||||
NextDockWidget = OpenDockWidgets[NextIndex];
|
||||
}
|
||||
|
||||
return NextDockWidget;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidget::DockWidgetFeatures CDockAreaWidget::features(eBitwiseOperator Mode) const
|
||||
{
|
||||
if (BitwiseAnd == Mode)
|
||||
{
|
||||
CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures);
|
||||
for (const auto DockWidget : dockWidgets())
|
||||
{
|
||||
Features &= DockWidget->features();
|
||||
}
|
||||
return Features;
|
||||
}
|
||||
else
|
||||
{
|
||||
CDockWidget::DockWidgetFeatures Features(CDockWidget::NoDockWidgetFeatures);
|
||||
for (const auto DockWidget : dockWidgets())
|
||||
{
|
||||
Features |= DockWidget->features();
|
||||
}
|
||||
return Features;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::toggleView(bool Open)
|
||||
{
|
||||
setVisible(Open);
|
||||
|
||||
emit viewToggled(Open);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::setVisible(bool Visible)
|
||||
{
|
||||
Super::setVisible(Visible);
|
||||
if (d->UpdateTitleBarButtons)
|
||||
{
|
||||
d->updateTitleBarButtonStates();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QAbstractButton* CDockAreaWidget::titleBarButton(TitleBarButton which) const
|
||||
{
|
||||
return d->TitleBar->button(which);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::closeArea()
|
||||
{
|
||||
// If there is only one single dock widget and this widget has the
|
||||
// DeleteOnClose feature, then we delete the dock widget now
|
||||
auto OpenDockWidgets = openedDockWidgets();
|
||||
if (OpenDockWidgets.count() == 1 && OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||
{
|
||||
OpenDockWidgets[0]->closeDockWidgetInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto DockWidget : openedDockWidgets())
|
||||
{
|
||||
DockWidget->toggleView(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::closeOtherAreas()
|
||||
{
|
||||
dockContainer()->closeOtherAreas(this);
|
||||
}
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -33,16 +33,17 @@
|
||||
#include <QFrame>
|
||||
|
||||
#include "ads_globals.h"
|
||||
#include "DockWidget.h"
|
||||
|
||||
class QXmlStreamWriter;
|
||||
class QAbstractButton;
|
||||
|
||||
namespace ads
|
||||
{
|
||||
struct DockAreaWidgetPrivate;
|
||||
class CDockManager;
|
||||
class CDockContainerWidget;
|
||||
struct DockContainerWidgetPrivate;
|
||||
class CDockWidget;
|
||||
class DockContainerWidgetPrivate;
|
||||
|
||||
|
||||
/**
|
||||
@@ -59,11 +60,19 @@ private:
|
||||
friend class CDockContainerWidget;
|
||||
friend class DockContainerWidgetPrivate;
|
||||
friend class CDockWidgetTab;
|
||||
friend struct DockWidgetPrivate;
|
||||
friend class CDockWidget;
|
||||
friend struct DockManagerPrivate;
|
||||
friend class CDockManager;
|
||||
|
||||
private slots:
|
||||
void onDockWidgetTitleClicked();
|
||||
void onTabsMenuActionTriggered(QAction* Action);
|
||||
void onCloseButtonClicked();
|
||||
void onTabCloseRequested(int Index);
|
||||
|
||||
/**
|
||||
* Reorder the index position of DockWidget at fromIndx to toIndex
|
||||
* if a tab in the tabbar is dragged from one index to another one
|
||||
*/
|
||||
void reorderDockWidget(int fromIndex, int toIndex);
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -87,18 +96,52 @@ protected:
|
||||
void removeDockWidget(CDockWidget* DockWidget);
|
||||
|
||||
/**
|
||||
* Returns the index of contents of the title widget that is located at
|
||||
* mouse position pos
|
||||
* Called from dock widget if it is opened or closed
|
||||
*/
|
||||
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const;
|
||||
void toggleDockWidgetView(CDockWidget* DockWidget, bool Open);
|
||||
|
||||
/**
|
||||
* Reorder the index position of DockWidget at fromIndx to toIndex.
|
||||
* This is a helper function to get the next open dock widget to activate
|
||||
* if the given DockWidget will be closed or removed.
|
||||
* The function returns the next widget that should be activated or
|
||||
* nullptr in case there are no more open widgets in this area.
|
||||
*/
|
||||
void reorderDockWidget(int fromIndex, int toIndex);
|
||||
CDockWidget* nextOpenDockWidget(CDockWidget* DockWidget) const;
|
||||
|
||||
/**
|
||||
* Returns the index of the given DockWidget in the internal layout
|
||||
*/
|
||||
int index(CDockWidget* DockWidget);
|
||||
|
||||
/**
|
||||
* Call this function, if you already know, that the dock does not
|
||||
* contain any visible content (any open dock widgets).
|
||||
*/
|
||||
void hideAreaWithNoVisibleContent();
|
||||
|
||||
/**
|
||||
* Updates the dock area layout and components visibility
|
||||
*/
|
||||
void updateTitleBarVisibility();
|
||||
|
||||
/**
|
||||
* This is the internal private function for setting the current widget.
|
||||
* This function is called by the public setCurrentDockWidget() function
|
||||
* and by the dock manager when restoring the state
|
||||
*/
|
||||
void internalSetCurrentDockWidget(CDockWidget* DockWidget);
|
||||
|
||||
/**
|
||||
* Marks tabs menu to update
|
||||
*/
|
||||
void markTitleBarMenuOutdated();
|
||||
|
||||
protected slots:
|
||||
void toggleView(bool Open);
|
||||
|
||||
public:
|
||||
using Super = QFrame;
|
||||
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
@@ -123,7 +166,7 @@ public:
|
||||
/**
|
||||
* Returns the rectangle of the title area
|
||||
*/
|
||||
QRect titleAreaGeometry() const;
|
||||
QRect titleBarGeometry() const;
|
||||
|
||||
/**
|
||||
* Returns the rectangle of the content
|
||||
@@ -131,9 +174,9 @@ public:
|
||||
QRect contentAreaGeometry() const;
|
||||
|
||||
/**
|
||||
* Returns the tab index of the given DockWidget
|
||||
* Returns the number of dock widgets in this area
|
||||
*/
|
||||
int tabIndex(CDockWidget* DockWidget);
|
||||
int dockWidgetsCount() const;
|
||||
|
||||
/**
|
||||
* Returns a list of all dock widgets in this dock area.
|
||||
@@ -142,14 +185,14 @@ public:
|
||||
QList<CDockWidget*> dockWidgets() const;
|
||||
|
||||
/**
|
||||
* Returns a list of dock widgets that are not closed
|
||||
* Returns the number of open dock widgets in this area
|
||||
*/
|
||||
QList<CDockWidget*> openedDockWidgets() const;
|
||||
int openDockWidgetsCount() const;
|
||||
|
||||
/**
|
||||
* Returns the number of dock widgets in this area
|
||||
* Returns a list of dock widgets that are not closed.
|
||||
*/
|
||||
int count() const;
|
||||
QList<CDockWidget*> openedDockWidgets() const;
|
||||
|
||||
/**
|
||||
* Returns a dock widget by its index
|
||||
@@ -157,12 +200,25 @@ public:
|
||||
CDockWidget* dockWidget(int Index) const;
|
||||
|
||||
/**
|
||||
* Returns the index of the current active dock widget
|
||||
* Returns the index of the current active dock widget or -1 if there
|
||||
* are is no active dock widget (ie.e if all dock widgets are closed)
|
||||
*/
|
||||
int currentIndex() const;
|
||||
|
||||
/**
|
||||
* Returns the current active dock widget
|
||||
* Returns the index of the first open dock widgets in the list of
|
||||
* dock widgets.
|
||||
* This function is here for performance reasons. Normally it would
|
||||
* be possible to take the first dock widget from the list returned by
|
||||
* openedDockWidgets() function. But that function enumerates all
|
||||
* dock widgets while this functions stops after the first open dock widget.
|
||||
* If there are no open dock widgets, the function returns -1.
|
||||
*/
|
||||
int indexOfFirstOpenDockWidget() const;
|
||||
|
||||
/**
|
||||
* Returns the current active dock widget or a nullptr if there is no
|
||||
* active dock widget (i.e. if all dock widgets are closed)
|
||||
*/
|
||||
CDockWidget* currentDockWidget() const;
|
||||
|
||||
@@ -176,16 +232,45 @@ public:
|
||||
*/
|
||||
void saveState(QXmlStreamWriter& Stream) const;
|
||||
|
||||
/**
|
||||
* This functions returns the dock widget features of all dock widget in
|
||||
* this area.
|
||||
* A bitwise and is used to combine the flags of all dock widgets. That
|
||||
* means, if only one single dock widget does not support a certain flag,
|
||||
* the whole dock are does not support the flag. I.e. if one single
|
||||
* dock widget in this area is not closable, the whole dock are is not
|
||||
* closable.
|
||||
*/
|
||||
CDockWidget::DockWidgetFeatures features(eBitwiseOperator Mode = BitwiseAnd) const;
|
||||
|
||||
/**
|
||||
* Returns the title bar button corresponding to the given title bar
|
||||
* button identifier
|
||||
*/
|
||||
QAbstractButton* titleBarButton(TitleBarButton which) const;
|
||||
|
||||
/**
|
||||
* Update the close button if visibility changed
|
||||
*/
|
||||
virtual void setVisible(bool Visible) override;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* This sets the index position of the current tab page.
|
||||
* This activates the tab for the given tab index.
|
||||
* If the dock widget for the given tab is not visible, the this function
|
||||
* call will make it visible.
|
||||
*/
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
/**
|
||||
* Updates the dock area layout and components visibility
|
||||
* Closes the dock area and all dock widgets in this area
|
||||
*/
|
||||
void updateDockArea();
|
||||
void closeArea();
|
||||
|
||||
/**
|
||||
* This function closes all other areas except of this area
|
||||
*/
|
||||
void closeOtherAreas();
|
||||
|
||||
signals:
|
||||
/**
|
||||
@@ -206,6 +291,12 @@ signals:
|
||||
* @param index
|
||||
*/
|
||||
void currentChanged(int index);
|
||||
|
||||
/**
|
||||
* This signal is emitted if the visibility of this dock area is toggled
|
||||
* via toggle view function
|
||||
*/
|
||||
void viewToggled(bool Open);
|
||||
}; // class DockAreaWidget
|
||||
}
|
||||
// namespace ads
|
||||
|
||||
@@ -33,36 +33,46 @@
|
||||
#include <QFrame>
|
||||
|
||||
#include "ads_globals.h"
|
||||
|
||||
#include "DockWidget.h"
|
||||
|
||||
class QXmlStreamWriter;
|
||||
class QXmlStreamReader;
|
||||
|
||||
|
||||
namespace ads
|
||||
{
|
||||
struct DockContainerWidgetPrivate;
|
||||
class DockContainerWidgetPrivate;
|
||||
class CDockAreaWidget;
|
||||
class CDockWidget;
|
||||
class CDockManager;
|
||||
struct DockManagerPrivate;
|
||||
class CFloatingDockContainer;
|
||||
struct FloatingDockContainerPrivate;
|
||||
class CFloatingDragPreview;
|
||||
struct FloatingDragPreviewPrivate;
|
||||
class CDockingStateReader;
|
||||
|
||||
/**
|
||||
* Container that manages a number of dock areas with single dock widgets
|
||||
* or tabyfied dock widgets in each area
|
||||
* or tabyfied dock widgets in each area.
|
||||
* Each window that support docking has a DockContainerWidget. That means
|
||||
* the main application window and all floating windows are ore contain
|
||||
* an DockContainerWidget.
|
||||
*/
|
||||
class ADS_EXPORT CDockContainerWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
DockContainerWidgetPrivate* d; ///< private data (pimpl)
|
||||
friend struct DockContainerWidgetPrivate;
|
||||
friend class DockContainerWidgetPrivate;
|
||||
friend class CDockManager;
|
||||
friend struct DockManagerPrivate;
|
||||
friend class CDockAreaWidget;
|
||||
friend struct DockAreaWidgetPrivate;
|
||||
friend class CFloatingDockContainer;
|
||||
friend struct FloatingDockContainerPrivate;
|
||||
friend class CDockWidget;
|
||||
friend class CFloatingDragPreview;
|
||||
friend struct FloatingDragPreviewPrivate;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -75,11 +85,21 @@ protected:
|
||||
*/
|
||||
QSplitter* rootSplitter() const;
|
||||
|
||||
/**
|
||||
* Helper function for creation of the root splitter
|
||||
*/
|
||||
void createRootSplitter();
|
||||
|
||||
/**
|
||||
* Drop floating widget into the container
|
||||
*/
|
||||
void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
|
||||
|
||||
/**
|
||||
* Drop a dock area or a dock widget given in widget parameter
|
||||
*/
|
||||
void dropWidget(QWidget* Widget, const QPoint& TargetPos);
|
||||
|
||||
/**
|
||||
* Adds the given dock area to this container widget
|
||||
*/
|
||||
@@ -101,7 +121,43 @@ protected:
|
||||
* stream but does not restore anything. You can use this check for
|
||||
* faulty files before you start restoring the state
|
||||
*/
|
||||
bool restoreState(QXmlStreamReader& Stream, bool Testing);
|
||||
bool restoreState(CDockingStateReader& Stream, bool Testing);
|
||||
|
||||
/**
|
||||
* This function returns the last added dock area widget for the given
|
||||
* area identifier or 0 if no dock area widget has been added for the given
|
||||
* area
|
||||
*/
|
||||
CDockAreaWidget* lastAddedDockAreaWidget(DockWidgetArea area) const;
|
||||
|
||||
/**
|
||||
* This function returns true if this dock area has only one single
|
||||
* visible dock widget.
|
||||
* A top level widget is a real floating widget. Only the isFloating()
|
||||
* function of top level widgets may returns true.
|
||||
*/
|
||||
bool hasTopLevelDockWidget() const;
|
||||
|
||||
/**
|
||||
* If hasSingleVisibleDockWidget() returns true, this function returns the
|
||||
* one and only visible dock widget. Otherwise it returns a nullptr.
|
||||
*/
|
||||
CDockWidget* topLevelDockWidget() const;
|
||||
|
||||
/**
|
||||
* Returns the top level dock area.
|
||||
*/
|
||||
CDockAreaWidget* topLevelDockArea() const;
|
||||
|
||||
/**
|
||||
* This function returns a list of all dock widgets in this floating widget.
|
||||
* It may be possible, depending on the implementation, that dock widgets,
|
||||
* that are not visible to the user have no parent widget. Therefore simply
|
||||
* calling findChildren() would not work here. Therefore this function
|
||||
* iterates over all dock areas and creates a list that contains all
|
||||
* dock widgets returned from all dock areas.
|
||||
*/
|
||||
QList<CDockWidget*> dockWidgets() const;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -124,6 +180,11 @@ public:
|
||||
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
||||
CDockAreaWidget* DockAreaWidget = nullptr);
|
||||
|
||||
/**
|
||||
* Removes dockwidget
|
||||
*/
|
||||
void removeDockWidget(CDockWidget* Dockwidget);
|
||||
|
||||
/**
|
||||
* Returns the current zOrderIndex
|
||||
*/
|
||||
@@ -173,6 +234,27 @@ public:
|
||||
*/
|
||||
void dumpLayout();
|
||||
|
||||
/**
|
||||
* This functions returns the dock widget features of all dock widget in
|
||||
* this container.
|
||||
* A bitwise and is used to combine the flags of all dock widgets. That
|
||||
* means, if only dock widget does not support a certain flag, the whole
|
||||
* dock are does not support the flag.
|
||||
*/
|
||||
CDockWidget::DockWidgetFeatures features() const;
|
||||
|
||||
/**
|
||||
* If this dock container is in a floating widget, this function returns
|
||||
* the floating widget.
|
||||
* Else, it returns a nullptr.
|
||||
*/
|
||||
CFloatingDockContainer* floatingWidget() const;
|
||||
|
||||
/**
|
||||
* Call this function to close all dock areas except the KeepOpenArea
|
||||
*/
|
||||
void closeOtherAreas(CDockAreaWidget* KeepOpenArea);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted if one or multiple dock areas has been added to
|
||||
@@ -185,6 +267,12 @@ signals:
|
||||
* This signal is emitted if one or multiple dock areas has been removed
|
||||
*/
|
||||
void dockAreasRemoved();
|
||||
|
||||
/**
|
||||
* This signal is emitted if a dock area is opened or closed via
|
||||
* toggleView() function
|
||||
*/
|
||||
void dockAreaViewToggled(CDockAreaWidget* DockArea, bool Open);
|
||||
}; // class DockContainerWidget
|
||||
} // namespace ads
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <DockWidgetTab.h>
|
||||
#include "DockWidgetTab.h"
|
||||
#include "DockManager.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include <QMainWindow>
|
||||
@@ -39,21 +40,26 @@
|
||||
#include <QVariant>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QApplication>
|
||||
#include <QAction>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QSettings>
|
||||
#include <QMenu>
|
||||
#include <QApplication>
|
||||
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockOverlay.h"
|
||||
#include "DockWidget.h"
|
||||
#include "ads_globals.h"
|
||||
#include "DockStateSerialization.h"
|
||||
#include "DockAreaWidget.h"
|
||||
#include "IconProvider.h"
|
||||
#include "DockingStateReader.h"
|
||||
|
||||
|
||||
|
||||
namespace ads
|
||||
{
|
||||
static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultConfig;
|
||||
|
||||
/**
|
||||
* Private data class of CDockManager class (pimpl)
|
||||
*/
|
||||
@@ -66,6 +72,11 @@ struct DockManagerPrivate
|
||||
CDockOverlay* DockAreaOverlay;
|
||||
QMap<QString, CDockWidget*> DockWidgetsMap;
|
||||
QMap<QString, QByteArray> Perspectives;
|
||||
QMap<QString, QMenu*> ViewMenuGroups;
|
||||
QMenu* ViewMenu;
|
||||
CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted;
|
||||
bool RestoringState = false;
|
||||
QVector<CFloatingDockContainer*> UninitializedFloatingWidgets;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@@ -81,17 +92,48 @@ struct DockManagerPrivate
|
||||
/**
|
||||
* Restores the state
|
||||
*/
|
||||
bool restoreState(const QByteArray &state, int version, bool Testing = internal::Restore);
|
||||
bool restoreStateFromXml(const QByteArray &state, int version, bool Testing = internal::Restore);
|
||||
|
||||
/**
|
||||
* Restore state
|
||||
*/
|
||||
bool restoreState(const QByteArray &state, int version);
|
||||
|
||||
void restoreDockWidgetsOpenState();
|
||||
void restoreDockAreasIndices();
|
||||
void emitTopLevelEvents();
|
||||
|
||||
void hideFloatingWidgets()
|
||||
{
|
||||
// Hide updates of floating widgets from user
|
||||
for (auto FloatingWidget : FloatingWidgets)
|
||||
{
|
||||
FloatingWidget->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void markDockWidgetsDirty()
|
||||
{
|
||||
for (auto DockWidget : DockWidgetsMap)
|
||||
{
|
||||
DockWidget->setProperty("dirty", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the container with the given index
|
||||
*/
|
||||
bool restoreContainer(int Index, QXmlStreamReader& stream, bool Testing);
|
||||
bool restoreContainer(int Index, CDockingStateReader& stream, bool Testing);
|
||||
|
||||
/**
|
||||
* Loads the stylesheet
|
||||
*/
|
||||
void loadStylesheet();
|
||||
|
||||
/**
|
||||
* Adds action to menu - optionally in sorted order
|
||||
*/
|
||||
void addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted);
|
||||
};
|
||||
// struct DockManagerPrivate
|
||||
|
||||
@@ -107,7 +149,11 @@ DockManagerPrivate::DockManagerPrivate(CDockManager* _public) :
|
||||
void DockManagerPrivate::loadStylesheet()
|
||||
{
|
||||
QString Result;
|
||||
#ifdef Q_OS_LINUX
|
||||
QFile StyleSheetFile(":ads/stylesheets/default_linux.css");
|
||||
#else
|
||||
QFile StyleSheetFile(":ads/stylesheets/default.css");
|
||||
#endif
|
||||
StyleSheetFile.open(QIODevice::ReadOnly);
|
||||
QTextStream StyleSheetStream(&StyleSheetFile);
|
||||
Result = StyleSheetStream.readAll();
|
||||
@@ -117,62 +163,78 @@ void DockManagerPrivate::loadStylesheet()
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool DockManagerPrivate::restoreContainer(int Index, QXmlStreamReader& stream, bool Testing)
|
||||
bool DockManagerPrivate::restoreContainer(int Index, CDockingStateReader& stream, bool Testing)
|
||||
{
|
||||
if (Testing)
|
||||
{
|
||||
Index = 0;
|
||||
}
|
||||
|
||||
bool Result = false;
|
||||
if (Index >= Containers.count())
|
||||
{
|
||||
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
|
||||
return FloatingWidget->restoreState(stream, Testing);
|
||||
Result = FloatingWidget->restoreState(stream, Testing);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "d->Containers[i]->restoreState ";
|
||||
return Containers[Index]->restoreState(stream, Testing);
|
||||
ADS_PRINT("d->Containers[i]->restoreState ");
|
||||
auto Container = Containers[Index];
|
||||
if (Container->isFloating())
|
||||
{
|
||||
Result = Container->floatingWidget()->restoreState(stream, Testing);
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = Container->restoreState(stream, Testing);
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool DockManagerPrivate::checkFormat(const QByteArray &state, int version)
|
||||
{
|
||||
return restoreState(state, version, internal::RestoreTesting);
|
||||
return restoreStateFromXml(state, version, internal::RestoreTesting);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool DockManagerPrivate::restoreState(const QByteArray &state, int version,
|
||||
bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version,
|
||||
bool Testing)
|
||||
{
|
||||
Q_UNUSED(version);
|
||||
|
||||
if (state.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
QXmlStreamReader s(state);
|
||||
CDockingStateReader s(state);
|
||||
s.readNextStartElement();
|
||||
if (s.name() != "QtAdvancedDockingSystem")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
qDebug() << s.attributes().value("Version");
|
||||
ADS_PRINT(s.attributes().value("Version"));
|
||||
bool ok;
|
||||
int v = s.attributes().value("Version").toInt(&ok);
|
||||
if (!ok || v != version)
|
||||
if (!ok || v > CurrentVersion)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
s.setFileVersion(v);
|
||||
bool Result = true;
|
||||
int DockContainers = s.attributes().value("DockContainers").toInt();
|
||||
qDebug() << DockContainers;
|
||||
#ifdef ADS_DEBUG_PRINT
|
||||
int DockContainers = s.attributes().value("Containers").toInt();
|
||||
#endif
|
||||
ADS_PRINT(DockContainers);
|
||||
int DockContainerCount = 0;
|
||||
while (s.readNextStartElement())
|
||||
{
|
||||
if (s.name() == "DockContainerWidget")
|
||||
if (s.name() == "Container")
|
||||
{
|
||||
Result = restoreContainer(DockContainerCount, s, Testing);
|
||||
if (!Result)
|
||||
@@ -191,6 +253,7 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version,
|
||||
for (int i = 0; i < DeleteCount; ++i)
|
||||
{
|
||||
FloatingWidgets[FloatingWidgetIndex + i]->deleteLater();
|
||||
_this->removeDockContainer(FloatingWidgets[FloatingWidgetIndex + i]->dockContainer());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,17 +261,163 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version,
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockManagerPrivate::restoreDockWidgetsOpenState()
|
||||
{
|
||||
// All dock widgets, that have not been processed in the restore state
|
||||
// function are invisible to the user now and have no assigned dock area
|
||||
// They do not belong to any dock container, until the user toggles the
|
||||
// toggle view action the next time
|
||||
for (auto DockWidget : DockWidgetsMap)
|
||||
{
|
||||
if (DockWidget->property(internal::DirtyProperty).toBool())
|
||||
{
|
||||
DockWidget->flagAsUnassigned();
|
||||
emit DockWidget->viewToggled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DockWidget->toggleViewInternal(!DockWidget->property(internal::ClosedProperty).toBool());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockManagerPrivate::restoreDockAreasIndices()
|
||||
{
|
||||
// Now all dock areas are properly restored and we setup the index of
|
||||
// The dock areas because the previous toggleView() action has changed
|
||||
// the dock area index
|
||||
int Count = 0;
|
||||
for (auto DockContainer : Containers)
|
||||
{
|
||||
Count++;
|
||||
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
||||
{
|
||||
CDockAreaWidget* DockArea = DockContainer->dockArea(i);
|
||||
QString DockWidgetName = DockArea->property("currentDockWidget").toString();
|
||||
CDockWidget* DockWidget = nullptr;
|
||||
if (!DockWidgetName.isEmpty())
|
||||
{
|
||||
DockWidget = _this->findDockWidget(DockWidgetName);
|
||||
}
|
||||
|
||||
if (!DockWidget || DockWidget->isClosed())
|
||||
{
|
||||
int Index = DockArea->indexOfFirstOpenDockWidget();
|
||||
if (Index < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DockArea->setCurrentIndex(Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
DockArea->internalSetCurrentDockWidget(DockWidget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockManagerPrivate::emitTopLevelEvents()
|
||||
{
|
||||
// Finally we need to send the topLevelChanged() signals for all dock
|
||||
// widgets if top level changed
|
||||
for (auto DockContainer : Containers)
|
||||
{
|
||||
CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget();
|
||||
if (TopLevelDockWidget)
|
||||
{
|
||||
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
||||
{
|
||||
auto DockArea = DockContainer->dockArea(i);
|
||||
for (auto DockWidget : DockArea->dockWidgets())
|
||||
{
|
||||
DockWidget->emitTopLevelChanged(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool DockManagerPrivate::restoreState(const QByteArray& State, int version)
|
||||
{
|
||||
QByteArray state = State.startsWith("<?xml") ? State : qUncompress(State);
|
||||
if (!checkFormat(state, version))
|
||||
{
|
||||
ADS_PRINT("checkFormat: Error checking format!!!!!!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hide updates of floating widgets from use
|
||||
hideFloatingWidgets();
|
||||
markDockWidgetsDirty();
|
||||
|
||||
if (!restoreStateFromXml(state, version))
|
||||
{
|
||||
ADS_PRINT("restoreState: Error restoring state!!!!!!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
restoreDockWidgetsOpenState();
|
||||
restoreDockAreasIndices();
|
||||
emitTopLevelEvents();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockManagerPrivate::addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted)
|
||||
{
|
||||
if (InsertSorted)
|
||||
{
|
||||
auto Actions = Menu->actions();
|
||||
auto it = std::find_if(Actions.begin(), Actions.end(),
|
||||
[&Action](const QAction* a)
|
||||
{
|
||||
return a->text().compare(Action->text(), Qt::CaseInsensitive) > 0;
|
||||
});
|
||||
|
||||
if (it == Actions.end())
|
||||
{
|
||||
Menu->addAction(Action);
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu->insertAction(*it, Action);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu->addAction(Action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockManager::CDockManager(QWidget *parent) :
|
||||
CDockContainerWidget(this, parent),
|
||||
d(new DockManagerPrivate(this))
|
||||
{
|
||||
createRootSplitter();
|
||||
QMainWindow* MainWindow = dynamic_cast<QMainWindow*>(parent);
|
||||
if (MainWindow)
|
||||
{
|
||||
MainWindow->setCentralWidget(this);
|
||||
}
|
||||
|
||||
d->ViewMenu = new QMenu(tr("Show View"), this);
|
||||
d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay);
|
||||
d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
|
||||
d->Containers.append(this);
|
||||
@@ -231,7 +440,7 @@ CDockManager::~CDockManager()
|
||||
void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget)
|
||||
{
|
||||
d->FloatingWidgets.append(FloatingWidget);
|
||||
qDebug() << "d->FloatingWidgets.count() " << d->FloatingWidgets.count();
|
||||
ADS_PRINT("d->FloatingWidgets.count() " << d->FloatingWidgets.count());
|
||||
}
|
||||
|
||||
|
||||
@@ -299,11 +508,12 @@ QByteArray CDockManager::saveState(int version) const
|
||||
{
|
||||
QByteArray xmldata;
|
||||
QXmlStreamWriter s(&xmldata);
|
||||
s.setAutoFormatting(true);
|
||||
auto ConfigFlags = CDockManager::configFlags();
|
||||
s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled));
|
||||
s.writeStartDocument();
|
||||
s.writeStartElement("QtAdvancedDockingSystem");
|
||||
s.writeAttribute("Version", QString::number(version));
|
||||
s.writeAttribute("DockContainers", QString::number(d->Containers.count()));
|
||||
s.writeAttribute("Containers", QString::number(d->Containers.count()));
|
||||
for (auto Container : d->Containers)
|
||||
{
|
||||
Container->saveState(s);
|
||||
@@ -312,64 +522,87 @@ QByteArray CDockManager::saveState(int version) const
|
||||
s.writeEndElement();
|
||||
s.writeEndDocument();
|
||||
|
||||
return xmldata;
|
||||
return ConfigFlags.testFlag(XmlCompressionEnabled)
|
||||
? qCompress(xmldata, 9) : xmldata;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockManager::restoreState(const QByteArray &state, int version)
|
||||
{
|
||||
if (!d->checkFormat(state, version))
|
||||
{
|
||||
qDebug() << "checkFormat: Error checking format!!!!!!!";
|
||||
return false;
|
||||
}
|
||||
// Prevent multiple calls as long as state is not restore. This may
|
||||
// happen, if QApplication::processEvents() is called somewhere
|
||||
if (d->RestoringState)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto DockWidget : d->DockWidgetsMap)
|
||||
{
|
||||
DockWidget->setProperty("dirty", true);
|
||||
}
|
||||
// We hide the complete dock manager here. Restoring the state means
|
||||
// that DockWidgets are removed from the DockArea internal stack layout
|
||||
// which in turn means, that each time a widget is removed the stack
|
||||
// will show and raise the next available widget which in turn
|
||||
// triggers show events for the dock widgets. To avoid this we hide the
|
||||
// dock manager. Because there will be no processing of application
|
||||
// events until this function is finished, the user will not see this
|
||||
// hiding
|
||||
bool IsHidden = this->isHidden();
|
||||
if (!IsHidden)
|
||||
{
|
||||
hide();
|
||||
}
|
||||
d->RestoringState = true;
|
||||
emit restoringState();
|
||||
bool Result = d->restoreState(state, version);
|
||||
d->RestoringState = false;
|
||||
emit stateRestored();
|
||||
if (!IsHidden)
|
||||
{
|
||||
show();
|
||||
}
|
||||
|
||||
if (!d->restoreState(state, version))
|
||||
{
|
||||
qDebug() << "restoreState: Error restoring state!!!!!!!";
|
||||
return false;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// All dock widgets, that have not been processed in the restore state
|
||||
// function are invisible to the user now and have no assigned dock area
|
||||
// They do not belong to any dock container, until the user toggles the
|
||||
// toggle view action the next time
|
||||
for (auto DockWidget : d->DockWidgetsMap)
|
||||
{
|
||||
if (DockWidget->property("dirty").toBool())
|
||||
{
|
||||
DockWidget->flagAsUnassigned();
|
||||
}
|
||||
else
|
||||
{
|
||||
DockWidget->toggleView(!DockWidget->property("closed").toBool());
|
||||
}
|
||||
}
|
||||
|
||||
// Now all dock areas are properly restored and we setup the index of
|
||||
// The dock areas because the previous toggleView() action has changed
|
||||
// the dock area index
|
||||
for (auto DockContainer : d->Containers)
|
||||
{
|
||||
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
||||
{
|
||||
CDockAreaWidget* DockArea = DockContainer->dockArea(i);
|
||||
int CurrentIndex = DockArea->property("currentIndex").toInt();
|
||||
if (CurrentIndex < DockArea->count() && DockArea->count() > 1 && CurrentIndex > -1)
|
||||
{
|
||||
DockArea->setCurrentIndex(CurrentIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
//============================================================================
|
||||
CFloatingDockContainer* CDockManager::addDockWidgetFloating(CDockWidget* Dockwidget)
|
||||
{
|
||||
d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget);
|
||||
CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget();
|
||||
if (OldDockArea)
|
||||
{
|
||||
OldDockArea->removeDockWidget(Dockwidget);
|
||||
}
|
||||
|
||||
emit stateChanged();
|
||||
return true;
|
||||
Dockwidget->setDockManager(this);
|
||||
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(Dockwidget);
|
||||
FloatingWidget->resize(Dockwidget->size());
|
||||
if (isVisible())
|
||||
{
|
||||
FloatingWidget->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
d->UninitializedFloatingWidgets.append(FloatingWidget);
|
||||
}
|
||||
return FloatingWidget;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockManager::showEvent(QShowEvent *event)
|
||||
{
|
||||
Super::showEvent(event);
|
||||
if (d->UninitializedFloatingWidgets.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto FloatingWidget : d->UninitializedFloatingWidgets)
|
||||
{
|
||||
FloatingWidget->show();
|
||||
}
|
||||
d->UninitializedFloatingWidgets.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -383,11 +616,54 @@ CDockAreaWidget* CDockManager::addDockWidget(DockWidgetArea area,
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidget* CDockManager::findDockWidget(const QString& ObjectName)
|
||||
CDockAreaWidget* CDockManager::addDockWidgetTab(DockWidgetArea area,
|
||||
CDockWidget* Dockwidget)
|
||||
{
|
||||
CDockAreaWidget* AreaWidget = lastAddedDockAreaWidget(area);
|
||||
if (AreaWidget)
|
||||
{
|
||||
return addDockWidget(ads::CenterDockWidgetArea, Dockwidget, AreaWidget);
|
||||
}
|
||||
else if (!openedDockAreas().isEmpty())
|
||||
{
|
||||
return addDockWidget(area, Dockwidget, openedDockAreas().last());
|
||||
}
|
||||
else
|
||||
{
|
||||
return addDockWidget(area, Dockwidget, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockAreaWidget* CDockManager::addDockWidgetTabToArea(CDockWidget* Dockwidget,
|
||||
CDockAreaWidget* DockAreaWidget)
|
||||
{
|
||||
return addDockWidget(ads::CenterDockWidgetArea, Dockwidget, DockAreaWidget);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidget* CDockManager::findDockWidget(const QString& ObjectName) const
|
||||
{
|
||||
return d->DockWidgetsMap.value(ObjectName, nullptr);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void CDockManager::removeDockWidget(CDockWidget* Dockwidget)
|
||||
{
|
||||
emit dockWidgetAboutToBeRemoved(Dockwidget);
|
||||
d->DockWidgetsMap.remove(Dockwidget->objectName());
|
||||
CDockContainerWidget::removeDockWidget(Dockwidget);
|
||||
emit dockWidgetRemoved(Dockwidget);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
QMap<QString, CDockWidget*> CDockManager::dockWidgetsMap() const
|
||||
{
|
||||
return d->DockWidgetsMap;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockManager::addPerspective(const QString& UniquePrespectiveName)
|
||||
@@ -397,6 +673,30 @@ void CDockManager::addPerspective(const QString& UniquePrespectiveName)
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockManager::removePerspective(const QString& Name)
|
||||
{
|
||||
removePerspectives({Name});
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockManager::removePerspectives(const QStringList& Names)
|
||||
{
|
||||
int Count = 0;
|
||||
for (auto Name : Names)
|
||||
{
|
||||
Count += d->Perspectives.remove(Name);
|
||||
}
|
||||
|
||||
if (Count)
|
||||
{
|
||||
emit perspectivesRemoved();
|
||||
emit perspectiveListChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QStringList CDockManager::perspectiveNames() const
|
||||
{
|
||||
@@ -413,7 +713,9 @@ void CDockManager::openPerspective(const QString& PerspectiveName)
|
||||
return;
|
||||
}
|
||||
|
||||
emit openingPerspective(PerspectiveName);
|
||||
restoreState(Iterator.value());
|
||||
emit perspectiveOpened(PerspectiveName);
|
||||
}
|
||||
|
||||
|
||||
@@ -459,6 +761,91 @@ void CDockManager::loadPerspectives(QSettings& Settings)
|
||||
|
||||
Settings.endArray();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
QAction* CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
|
||||
const QString& Group, const QIcon& GroupIcon)
|
||||
{
|
||||
bool AlphabeticallySorted = (MenuAlphabeticallySorted == d->MenuInsertionOrder);
|
||||
if (!Group.isEmpty())
|
||||
{
|
||||
QMenu* GroupMenu = d->ViewMenuGroups.value(Group, 0);
|
||||
if (!GroupMenu)
|
||||
{
|
||||
GroupMenu = new QMenu(Group, this);
|
||||
GroupMenu->setIcon(GroupIcon);
|
||||
d->addActionToMenu(GroupMenu->menuAction(), d->ViewMenu, AlphabeticallySorted);
|
||||
d->ViewMenuGroups.insert(Group, GroupMenu);
|
||||
}
|
||||
|
||||
d->addActionToMenu(ToggleViewAction, GroupMenu, AlphabeticallySorted);
|
||||
return GroupMenu->menuAction();
|
||||
}
|
||||
else
|
||||
{
|
||||
d->addActionToMenu(ToggleViewAction, d->ViewMenu, AlphabeticallySorted);
|
||||
return ToggleViewAction;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QMenu* CDockManager::viewMenu() const
|
||||
{
|
||||
return d->ViewMenu;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockManager::setViewMenuInsertionOrder(eViewMenuInsertionOrder Order)
|
||||
{
|
||||
d->MenuInsertionOrder = Order;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
bool CDockManager::isRestoringState() const
|
||||
{
|
||||
return d->RestoringState;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
int CDockManager::startDragDistance()
|
||||
{
|
||||
return QApplication::startDragDistance() * 1.5;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
CDockManager::ConfigFlags CDockManager::configFlags()
|
||||
{
|
||||
return StaticConfigFlags;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockManager::setConfigFlags(const ConfigFlags Flags)
|
||||
{
|
||||
StaticConfigFlags = Flags;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
void CDockManager::setConfigFlag(eConfigFlag Flag, bool On)
|
||||
{
|
||||
internal::setFlag(StaticConfigFlags, Flag, On);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
CIconProvider& CDockManager::iconProvider()
|
||||
{
|
||||
static CIconProvider Instance;
|
||||
return Instance;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -30,11 +30,21 @@
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include "DockContainerWidget.h"
|
||||
|
||||
#include "ads_globals.h"
|
||||
#include <ads_globals.h>
|
||||
#include <DockContainerWidget.h>
|
||||
#include <DockWidget.h>
|
||||
#include <FloatingDockContainer.h>
|
||||
#include <qbytearray.h>
|
||||
#include <qflags.h>
|
||||
#include <qlist.h>
|
||||
#include <qmap.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <qstring.h>
|
||||
#include <qstringlist.h>
|
||||
#include <QtGui/qicon.h>
|
||||
|
||||
class QSettings;
|
||||
class QMenu;
|
||||
|
||||
namespace ads
|
||||
{
|
||||
@@ -42,14 +52,25 @@ struct DockManagerPrivate;
|
||||
class CFloatingDockContainer;
|
||||
struct FloatingDockContainerPrivate;
|
||||
class CDockContainerWidget;
|
||||
class DockContainerWidgetPrivate;
|
||||
class CDockOverlay;
|
||||
class CDockAreaTabBar;
|
||||
class CDockWidgetTab;
|
||||
struct DockWidgetTabPrivate;
|
||||
struct DockAreaWidgetPrivate;
|
||||
class CIconProvider;
|
||||
|
||||
/**
|
||||
* The central dock manager that maintains the complete docking system
|
||||
* The central dock manager that maintains the complete docking system.
|
||||
* With the configuration flags you can globally control the functionality
|
||||
* of the docking system. The dock manager uses an internal stylesheet to
|
||||
* style its components like splitters, tabs and buttons. If you want to
|
||||
* disable this stylesheet because your application uses its own,
|
||||
* just call the function for settings the stylesheet with an empty
|
||||
* string.
|
||||
* \code
|
||||
* DockManager->setStyleSheet("");
|
||||
* \endcode
|
||||
**/
|
||||
class ADS_EXPORT CDockManager : public CDockContainerWidget
|
||||
{
|
||||
@@ -60,10 +81,13 @@ private:
|
||||
friend class CFloatingDockContainer;
|
||||
friend struct FloatingDockContainerPrivate;
|
||||
friend class CDockContainerWidget;
|
||||
friend class DockContainerWidgetPrivate;
|
||||
friend class CDockAreaTabBar;
|
||||
friend class CDockWidgetTab;
|
||||
friend struct DockAreaWidgetPrivate;
|
||||
friend struct DockWidgetTabPrivate;
|
||||
friend class CFloatingDragPreview;
|
||||
friend struct FloatingDragPreviewPrivate;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -99,11 +123,62 @@ protected:
|
||||
*/
|
||||
CDockOverlay* dockAreaOverlay() const;
|
||||
|
||||
/**
|
||||
* Show the floating widgets that has been created floating
|
||||
*/
|
||||
virtual void showEvent(QShowEvent *event) override;
|
||||
|
||||
public:
|
||||
using Super = CDockContainerWidget;
|
||||
|
||||
enum eViewMenuInsertionOrder
|
||||
{
|
||||
MenuSortedByInsertion,
|
||||
MenuAlphabeticallySorted
|
||||
};
|
||||
|
||||
/**
|
||||
* These global configuration flags configure some global dock manager
|
||||
* settings.
|
||||
*/
|
||||
enum eConfigFlag
|
||||
{
|
||||
ActiveTabHasCloseButton = 0x0001, //!< If this flag is set, the active tab in a tab area has a close button
|
||||
DockAreaHasCloseButton = 0x0002, //!< If the flag is set each dock area has a close button
|
||||
DockAreaCloseButtonClosesTab = 0x0004,//!< If the flag is set, the dock area close button closes the active tab, if not set, it closes the complete cock area
|
||||
OpaqueSplitterResize = 0x0008, //!< See QSplitter::setOpaqueResize() documentation
|
||||
XmlAutoFormattingEnabled = 0x0010,//!< If enabled, the XML writer automatically adds line-breaks and indentation to empty sections between elements (ignorable whitespace).
|
||||
XmlCompressionEnabled = 0x0020,//!< If enabled, the XML output will be compressed and is not human readable anymore
|
||||
TabCloseButtonIsToolButton = 0x0040,//! If enabled the tab close buttons will be QToolButtons instead of QPushButtons - disabled by default
|
||||
AllTabsHaveCloseButton = 0x0080, //!< if this flag is set, then all tabs that are closable show a close button
|
||||
RetainTabSizeWhenCloseButtonHidden = 0x0100, //!< if this flag is set, the space for the close button is reserved even if the close button is not visible
|
||||
OpaqueUndocking = 0x0200,///< If enabled, the widgets are immediately undocked into floating widgets, if disabled, only a draw preview is undocked and the real undocking is deferred until the mouse is released
|
||||
DragPreviewIsDynamic = 0x0400,///< If opaque undocking is disabled, this flag defines the behavior of the drag preview window, if this flag is enabled, the preview will be adjusted dynamically to the drop area
|
||||
DragPreviewShowsContentPixmap = 0x0800,///< If opaque undocking is disabled, the created drag preview window shows a copy of the content of the dock widget / dock are that is dragged
|
||||
DragPreviewHasWindowFrame = 0x1000,///< If opaque undocking is disabled, then this flag configures if the drag preview is frameless or looks like a real window
|
||||
DefaultConfig = ActiveTabHasCloseButton
|
||||
| DockAreaHasCloseButton
|
||||
| OpaqueSplitterResize
|
||||
| XmlCompressionEnabled
|
||||
| OpaqueUndocking, ///< the default configuration
|
||||
DefaultNonOpaqueConfig = ActiveTabHasCloseButton
|
||||
| DockAreaHasCloseButton
|
||||
| XmlCompressionEnabled
|
||||
| DragPreviewShowsContentPixmap, ///< the default configuration for non opaque operations
|
||||
NonOpaqueWithWindowFrame = ActiveTabHasCloseButton
|
||||
| DockAreaHasCloseButton
|
||||
| XmlCompressionEnabled
|
||||
| DragPreviewShowsContentPixmap
|
||||
| DragPreviewHasWindowFrame ///< the default configuration for non opaque operations that show a real window with frame
|
||||
};
|
||||
Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag)
|
||||
|
||||
/**
|
||||
* Default Constructor.
|
||||
* If the given parent is a QMainWindow, the dock manager sets itself as the
|
||||
* central widget
|
||||
* central widget.
|
||||
* Before you create any dock widgets, you should properly setup the
|
||||
* configuration flags via setConfigFlags().
|
||||
*/
|
||||
CDockManager(QWidget* parent = 0);
|
||||
|
||||
@@ -112,6 +187,29 @@ public:
|
||||
*/
|
||||
virtual ~CDockManager();
|
||||
|
||||
/**
|
||||
* This function returns the global configuration flags
|
||||
*/
|
||||
static ConfigFlags configFlags();
|
||||
|
||||
/**
|
||||
* Sets the global configuration flags for the whole docking system.
|
||||
* Call this function before you create your first dock widget.
|
||||
*/
|
||||
static void setConfigFlags(const ConfigFlags Flags);
|
||||
|
||||
/**
|
||||
* Set a certain config flag
|
||||
*/
|
||||
static void setConfigFlag(eConfigFlag Flag, bool On = true);
|
||||
|
||||
/**
|
||||
* Returns the global icon provider.
|
||||
* The icon provider enables the use of custom icons in case using
|
||||
* styleheets for icons is not an option.
|
||||
*/
|
||||
static CIconProvider& iconProvider();
|
||||
|
||||
/**
|
||||
* Adds dockwidget into the given area.
|
||||
* If DockAreaWidget is not null, then the area parameter indicates the area
|
||||
@@ -128,12 +226,45 @@ public:
|
||||
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
||||
CDockAreaWidget* DockAreaWidget = nullptr);
|
||||
|
||||
/**
|
||||
* This function will add the given Dockwidget to the given dock area as
|
||||
* a new tab.
|
||||
* If no dock area widget exists for the given area identifier, a new
|
||||
* dock area widget is created.
|
||||
*/
|
||||
CDockAreaWidget* addDockWidgetTab(DockWidgetArea area,
|
||||
CDockWidget* Dockwidget);
|
||||
|
||||
/**
|
||||
* This function will add the given Dockwidget to the given DockAreaWidget
|
||||
* as a new tab.
|
||||
*/
|
||||
CDockAreaWidget* addDockWidgetTabToArea(CDockWidget* Dockwidget,
|
||||
CDockAreaWidget* DockAreaWidget);
|
||||
|
||||
/**
|
||||
* Adds the given DockWidget floating and returns the created
|
||||
* CFloatingDockContainer instance.
|
||||
*/
|
||||
CFloatingDockContainer* addDockWidgetFloating(CDockWidget* Dockwidget);
|
||||
|
||||
/**
|
||||
* Searches for a registered doc widget with the given ObjectName
|
||||
* \return Return the found dock widget or nullptr if a dock widget with the
|
||||
* given name is not registered
|
||||
*/
|
||||
CDockWidget* findDockWidget(const QString& ObjectName);
|
||||
CDockWidget* findDockWidget(const QString& ObjectName) const;
|
||||
|
||||
/**
|
||||
* Remove the given Dock from the dock manager
|
||||
*/
|
||||
void removeDockWidget(CDockWidget* Dockwidget);
|
||||
|
||||
/**
|
||||
* This function returns a readable reference to the internal dock
|
||||
* widgets map so that it is possible to iterate over all dock widgets
|
||||
*/
|
||||
QMap<QString, CDockWidget*> dockWidgetsMap() const;
|
||||
|
||||
/**
|
||||
* Returns the list of all active and visible dock containers
|
||||
@@ -154,9 +285,13 @@ public:
|
||||
|
||||
/**
|
||||
* Saves the current state of the dockmanger and all its dock widgets
|
||||
* into the returned QByteArray
|
||||
* into the returned QByteArray.
|
||||
* The XmlMode enables / disables the auto formatting for the XmlStreamWriter.
|
||||
* If auto formatting is enabled, the output is intended and line wrapped.
|
||||
* The XmlMode XmlAutoFormattingDisabled is better if you would like to have
|
||||
* a more compact XML output - i.e. for storage in ini files.
|
||||
*/
|
||||
QByteArray saveState(int version = 0) const;
|
||||
QByteArray saveState(int version = Version1) const;
|
||||
|
||||
/**
|
||||
* Restores the state of this dockmanagers dockwidgets.
|
||||
@@ -165,7 +300,7 @@ public:
|
||||
* returns false; otherwise, the state is restored, and this function
|
||||
* returns true.
|
||||
*/
|
||||
bool restoreState(const QByteArray &state, int version = 0);
|
||||
bool restoreState(const QByteArray &state, int version = Version1);
|
||||
|
||||
/**
|
||||
* Saves the current perspective to the internal list of perspectives.
|
||||
@@ -177,6 +312,16 @@ public:
|
||||
*/
|
||||
void addPerspective(const QString& UniquePrespectiveName);
|
||||
|
||||
/**
|
||||
* Removes the perspective with the given name from the list of perspectives
|
||||
*/
|
||||
void removePerspective(const QString& Name);
|
||||
|
||||
/**
|
||||
* Removes the given perspectives from the dock manager
|
||||
*/
|
||||
void removePerspectives(const QStringList& Names);
|
||||
|
||||
/**
|
||||
* Returns the names of all available perspectives
|
||||
*/
|
||||
@@ -192,6 +337,56 @@ public:
|
||||
*/
|
||||
void loadPerspectives(QSettings& Settings);
|
||||
|
||||
/**
|
||||
* Adds a toggle view action to the the internal view menu.
|
||||
* You can either manage the insertion of the toggle view actions in your
|
||||
* application or you can add the actions to the internal view menu and
|
||||
* then simply insert the menu object into your.
|
||||
* \param[in] ToggleViewAction The action to insert. If no group is provided
|
||||
* the action is directly inserted into the menu. If a group
|
||||
* is provided, the action is inserted into the group and the
|
||||
* group is inserted into the menu if it is not existing yet.
|
||||
* \param[in] Group This is the text used for the group menu item
|
||||
* \param[in] GroupIcon The icon used for grouping the workbenches in the
|
||||
* view menu. I.e. if there is a workbench for each device
|
||||
* like for spectrometer devices, it is good to group all these
|
||||
* workbenches under a menu item
|
||||
* \return If Group is not empty, this function returns the GroupAction
|
||||
* for this group. If the group is empty, the function returns
|
||||
* the given ToggleViewAction.
|
||||
*/
|
||||
QAction* addToggleViewActionToMenu(QAction* ToggleViewAction,
|
||||
const QString& Group = QString(), const QIcon& GroupIcon = QIcon());
|
||||
|
||||
/**
|
||||
* This function returns the internal view menu.
|
||||
* To fill the view menu, you can use the addToggleViewActionToMenu()
|
||||
* function.
|
||||
*/
|
||||
QMenu* viewMenu() const;
|
||||
|
||||
/**
|
||||
* Define the insertion order for toggle view menu items.
|
||||
* The order defines how the actions are added to the view menu.
|
||||
* The default insertion order is MenuAlphabeticallySorted to make it
|
||||
* easier for users to find the menu entry for a certain dock widget.
|
||||
* You need to call this function befor you insert the first menu item
|
||||
* into the view menu.
|
||||
*/
|
||||
void setViewMenuInsertionOrder(eViewMenuInsertionOrder Order);
|
||||
|
||||
/**
|
||||
* This function returns true between the restoringState() and
|
||||
* stateRestored() signals.
|
||||
*/
|
||||
bool isRestoringState() const;
|
||||
|
||||
/**
|
||||
* The distance the user needs to move the mouse with the left button
|
||||
* hold down before a dock widget start floating
|
||||
*/
|
||||
static int startDragDistance();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Opens the perspective with the given name.
|
||||
@@ -204,12 +399,61 @@ signals:
|
||||
*/
|
||||
void perspectiveListChanged();
|
||||
|
||||
/**
|
||||
* This signal is emitted if perspectives have been removed
|
||||
*/
|
||||
void perspectivesRemoved();
|
||||
|
||||
/**
|
||||
* This signal is emitted, if the restore function is called, just before
|
||||
* the dock manager starts restoring the state.
|
||||
* If this function is called, nothing has changed yet
|
||||
*/
|
||||
void restoringState();
|
||||
|
||||
/**
|
||||
* This signal is emitted if the state changed in restoreState.
|
||||
* The signal is emitted if the restoreState() function is called or
|
||||
* if the openPerspective() function is called
|
||||
*/
|
||||
void stateChanged();
|
||||
void stateRestored();
|
||||
|
||||
/**
|
||||
* This signal is emitted, if the dock manager starts opening a
|
||||
* perspective.
|
||||
* Opening a perspective may take more than a second if there are
|
||||
* many complex widgets. The application may use this signal
|
||||
* to show some progress indicator or to change the mouse cursor
|
||||
* into a busy cursor.
|
||||
*/
|
||||
void openingPerspective(const QString& PerspectiveName);
|
||||
|
||||
/**
|
||||
* This signal is emitted if the dock manager finished opening a
|
||||
* perspective
|
||||
*/
|
||||
void perspectiveOpened(const QString& PerspectiveName);
|
||||
|
||||
/**
|
||||
* This signal is emitted, if a new DockArea has been created.
|
||||
* An application can use this signal to set custom icons or custom
|
||||
* tooltips for the DockArea buttons.
|
||||
*/
|
||||
void dockAreaCreated(CDockAreaWidget* DockArea);
|
||||
|
||||
/**
|
||||
* This signal is emitted just before the given dock widget is removed
|
||||
* from the
|
||||
*/
|
||||
void dockWidgetAboutToBeRemoved(CDockWidget* DockWidget);
|
||||
|
||||
/**
|
||||
* This signal is emitted if a dock widget has been removed with the remove
|
||||
* removeDockWidget() function.
|
||||
* If this signal is emitted, the dock widget has been removed from the
|
||||
* docking system but it is not deleted yet.
|
||||
*/
|
||||
void dockWidgetRemoved(CDockWidget* DockWidget);
|
||||
}; // class DockManager
|
||||
} // namespace ads
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
#include <QWindow>
|
||||
|
||||
#include "DockAreaWidget.h"
|
||||
|
||||
@@ -51,7 +52,6 @@ struct DockOverlayPrivate
|
||||
DockWidgetAreas AllowedAreas = InvalidDockWidgetArea;
|
||||
CDockOverlayCross* Cross;
|
||||
QPointer<QWidget> TargetWidget;
|
||||
QRect TargetRect;
|
||||
DockWidgetArea LastLocation = InvalidDockWidgetArea;
|
||||
bool DropPreviewEnabled = true;
|
||||
CDockOverlay::eMode Mode = CDockOverlay::ModeDockAreaOverlay;
|
||||
@@ -75,6 +75,7 @@ struct DockOverlayCrossPrivate
|
||||
QGridLayout* GridLayout;
|
||||
QColor IconColors[5];
|
||||
bool UpdateRequired = false;
|
||||
double LastDevicePixelRatio = 0.1;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@@ -130,6 +131,21 @@ struct DockOverlayCrossPrivate
|
||||
return Color;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
/**
|
||||
* Helper function that returns the drop indicator width depending on the
|
||||
* operating system
|
||||
*/
|
||||
qreal dropIndicatiorWidth(QLabel* l) const
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
Q_UNUSED(l)
|
||||
return 40;
|
||||
#else
|
||||
return static_cast<qreal>(l->fontMetrics().height()) * 3.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QWidget* createDropIndicatorWidget(DockWidgetArea DockWidgetArea,
|
||||
@@ -138,24 +154,41 @@ struct DockOverlayCrossPrivate
|
||||
QLabel* l = new QLabel();
|
||||
l->setObjectName("DockWidgetAreaLabel");
|
||||
|
||||
const qreal metric = static_cast<qreal>(l->fontMetrics().height()) * 3.f;
|
||||
const qreal metric = dropIndicatiorWidth(l);
|
||||
const QSizeF size(metric, metric);
|
||||
|
||||
l->setPixmap(createDropIndicatorPixmap(size, DockWidgetArea, Mode));
|
||||
l->setPixmap(createHighDpiDropIndicatorPixmap(size, DockWidgetArea, Mode));
|
||||
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||
l->setAttribute(Qt::WA_TranslucentBackground);
|
||||
l->setProperty("dockWidgetArea", DockWidgetArea);
|
||||
return l;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void updateDropIndicatorIcon(QWidget* DropIndicatorWidget)
|
||||
{
|
||||
QLabel* l = qobject_cast<QLabel*>(DropIndicatorWidget);
|
||||
const qreal metric = dropIndicatiorWidth(l);
|
||||
const QSizeF size(metric, metric);
|
||||
|
||||
int Area = l->property("dockWidgetArea").toInt();
|
||||
l->setPixmap(createHighDpiDropIndicatorPixmap(size, (DockWidgetArea)Area, Mode));
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
QPixmap createDropIndicatorPixmap(const QSizeF& size, DockWidgetArea DockWidgetArea,
|
||||
QPixmap createHighDpiDropIndicatorPixmap(const QSizeF& size, DockWidgetArea DockWidgetArea,
|
||||
CDockOverlay::eMode Mode)
|
||||
{
|
||||
QColor borderColor = iconColor(CDockOverlayCross::FrameColor);
|
||||
QColor backgroundColor = iconColor(CDockOverlayCross::WindowBackgroundColor);
|
||||
|
||||
QPixmap pm(size.width(), size.height());
|
||||
#if QT_VERSION >= 0x050600
|
||||
double DevicePixelRatio = _this->window()->devicePixelRatioF();
|
||||
#else
|
||||
double DevicePixelRatio = _this->window()->devicePixelRatio();
|
||||
#endif
|
||||
QSizeF PixmapSize = size * DevicePixelRatio;
|
||||
QPixmap pm(PixmapSize.toSize());
|
||||
pm.fill(QColor(0, 0, 0, 0));
|
||||
|
||||
QPainter p(&pm);
|
||||
@@ -225,6 +258,7 @@ struct DockOverlayCrossPrivate
|
||||
p.drawRect(areaRect);
|
||||
|
||||
pen = p.pen();
|
||||
pen.setWidth(1);
|
||||
pen.setColor(borderColor);
|
||||
pen.setStyle(Qt::DashLine);
|
||||
p.setPen(pen);
|
||||
@@ -284,6 +318,7 @@ struct DockOverlayCrossPrivate
|
||||
p.drawPolygon(Arrow);
|
||||
}
|
||||
|
||||
pm.setDevicePixelRatio(DevicePixelRatio);
|
||||
return pm;
|
||||
}
|
||||
|
||||
@@ -297,7 +332,11 @@ CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) :
|
||||
{
|
||||
d->Mode = Mode;
|
||||
d->Cross = new CDockOverlayCross(this);
|
||||
#ifdef Q_OS_LINUX
|
||||
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
|
||||
#else
|
||||
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||
#endif
|
||||
setWindowOpacity(1);
|
||||
setWindowTitle("DockOverlay");
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
@@ -347,7 +386,7 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
|
||||
return Result;
|
||||
}
|
||||
|
||||
if (DockArea->titleAreaGeometry().contains(DockArea->mapFromGlobal(QCursor::pos())))
|
||||
if (DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(QCursor::pos())))
|
||||
{
|
||||
return CenterDockWidgetArea;
|
||||
}
|
||||
@@ -372,7 +411,6 @@ DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
|
||||
}
|
||||
|
||||
d->TargetWidget = target;
|
||||
d->TargetRect = QRect();
|
||||
d->LastLocation = InvalidDockWidgetArea;
|
||||
|
||||
// Move it over the target.
|
||||
@@ -381,6 +419,7 @@ DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
|
||||
move(TopLeft);
|
||||
show();
|
||||
d->Cross->updatePosition();
|
||||
d->Cross->updateOverlayIcons();
|
||||
return dropAreaUnderCursor();
|
||||
}
|
||||
|
||||
@@ -390,8 +429,8 @@ void CDockOverlay::hideOverlay()
|
||||
{
|
||||
hide();
|
||||
d->TargetWidget.clear();
|
||||
d->TargetRect = QRect();
|
||||
d->LastLocation = InvalidDockWidgetArea;
|
||||
d->DropAreaRect = QRect();
|
||||
}
|
||||
|
||||
|
||||
@@ -403,6 +442,13 @@ void CDockOverlay::enableDropPreview(bool Enable)
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockOverlay::dropPreviewEnabled() const
|
||||
{
|
||||
return d->DropPreviewEnabled;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockOverlay::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
@@ -430,9 +476,16 @@ void CDockOverlay::paintEvent(QPaintEvent* event)
|
||||
}
|
||||
QPainter painter(this);
|
||||
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
|
||||
QPen Pen = painter.pen();
|
||||
Pen.setColor(Color.darker(120));
|
||||
Pen.setStyle(Qt::SolidLine);
|
||||
Pen.setWidth(1);
|
||||
Pen.setCosmetic(true);
|
||||
painter.setPen(Pen);
|
||||
Color = Color.lighter(130);
|
||||
Color.setAlpha(64);
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.fillRect(r, Color);
|
||||
painter.setBrush(Color);
|
||||
painter.drawRect(r.adjusted(0, 0, -1, -1));
|
||||
d->DropAreaRect = r;
|
||||
}
|
||||
|
||||
@@ -524,7 +577,11 @@ CDockOverlayCross::CDockOverlayCross(CDockOverlay* overlay) :
|
||||
d(new DockOverlayCrossPrivate(this))
|
||||
{
|
||||
d->DockOverlay = overlay;
|
||||
#ifdef Q_OS_LINUX
|
||||
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
|
||||
#else
|
||||
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||
#endif
|
||||
setWindowTitle("DockOverlayCross");
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
@@ -552,12 +609,36 @@ void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode)
|
||||
areaWidgets.insert(BottomDockWidgetArea, d->createDropIndicatorWidget(BottomDockWidgetArea, Mode));
|
||||
areaWidgets.insert(LeftDockWidgetArea, d->createDropIndicatorWidget(LeftDockWidgetArea, Mode));
|
||||
areaWidgets.insert(CenterDockWidgetArea, d->createDropIndicatorWidget(CenterDockWidgetArea, Mode));
|
||||
|
||||
#if QT_VERSION >= 0x050600
|
||||
d->LastDevicePixelRatio = devicePixelRatioF();
|
||||
#else
|
||||
d->LastDevicePixelRatio = devicePixelRatio();
|
||||
#endif
|
||||
setAreaWidgets(areaWidgets);
|
||||
d->UpdateRequired = false;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockOverlayCross::updateOverlayIcons()
|
||||
{
|
||||
if (windowHandle()->devicePixelRatio() == d->LastDevicePixelRatio)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto Widget : d->DropIndicatorWidgets)
|
||||
{
|
||||
d->updateDropIndicatorIcon(Widget);
|
||||
}
|
||||
#if QT_VESION >= 0x050600
|
||||
d->LastDevicePixelRatio = devicePixelRatioF();
|
||||
#else
|
||||
d->LastDevicePixelRatio = devicePixelRatio();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockOverlayCross::setIconColor(eIconColor ColorIndex, const QColor& Color)
|
||||
{
|
||||
|
||||
@@ -97,6 +97,11 @@ public:
|
||||
*/
|
||||
void enableDropPreview(bool Enable);
|
||||
|
||||
/**
|
||||
* Returns true if drop preview is enabled
|
||||
*/
|
||||
bool dropPreviewEnabled() const;
|
||||
|
||||
/**
|
||||
* The drop overlay rectangle for the target area
|
||||
*/
|
||||
@@ -214,6 +219,11 @@ public:
|
||||
*/
|
||||
void setupOverlayCross(CDockOverlay::eMode Mode);
|
||||
|
||||
/**
|
||||
* Recreates the overlay icons.
|
||||
*/
|
||||
void updateOverlayIcons();
|
||||
|
||||
/**
|
||||
* Resets and updates the
|
||||
*/
|
||||
@@ -240,9 +250,6 @@ public:
|
||||
protected:
|
||||
virtual void showEvent(QShowEvent* e) override;
|
||||
void setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets);
|
||||
|
||||
private:
|
||||
|
||||
}; // CDockOverlayCross
|
||||
|
||||
} // namespace ads
|
||||
|
||||
@@ -52,7 +52,8 @@ CDockSplitter::CDockSplitter(QWidget *parent)
|
||||
: QSplitter(parent),
|
||||
d(new DockSplitterPrivate(this))
|
||||
{
|
||||
|
||||
setProperty("ads-splitter", true);
|
||||
setChildrenCollapsible(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +68,7 @@ CDockSplitter::CDockSplitter(Qt::Orientation orientation, QWidget *parent)
|
||||
//============================================================================
|
||||
CDockSplitter::~CDockSplitter()
|
||||
{
|
||||
qDebug() << "~CDockSplitter";
|
||||
ADS_PRINT("~CDockSplitter");
|
||||
delete d;
|
||||
}
|
||||
|
||||
@@ -78,7 +79,7 @@ bool CDockSplitter::hasVisibleContent() const
|
||||
// TODO Cache or precalculate this to speed up
|
||||
for (int i = 0; i < count(); ++i)
|
||||
{
|
||||
if (widget(i)->isVisibleTo(this))
|
||||
if (!widget(i)->isHidden())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace ads
|
||||
struct DockSplitterPrivate;
|
||||
|
||||
/**
|
||||
* Splitter used internally instead of QSplitter
|
||||
* Splitter used internally instead of QSplitter with some additional
|
||||
* fuctionality.
|
||||
*/
|
||||
class ADS_EXPORT CDockSplitter : public QSplitter
|
||||
{
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*******************************************************************************
|
||||
** Qt Advanced Docking System
|
||||
** Copyright (C) 2017 Uwe Kindler
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU Lesser General Public
|
||||
** License as published by the Free Software Foundation; either
|
||||
** version 2.1 of the License, or (at your option) any later version.
|
||||
**
|
||||
** This library is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public
|
||||
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DockStateSerialization.cpp
|
||||
/// \author Uwe Kindler
|
||||
/// \date 26.02.2017
|
||||
/// \brief Serialization related data, constants and stuff
|
||||
//============================================================================
|
||||
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include "DockStateSerialization.h"
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef DockStateSerializationH
|
||||
#define DockStateSerializationH
|
||||
/*******************************************************************************
|
||||
** Qt Advanced Docking System
|
||||
** Copyright (C) 2017 Uwe Kindler
|
||||
**
|
||||
** This library is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU Lesser General Public
|
||||
** License as published by the Free Software Foundation; either
|
||||
** version 2.1 of the License, or (at your option) any later version.
|
||||
**
|
||||
** This library is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
** Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public
|
||||
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DockStateSerialization.h
|
||||
/// \author Uwe Kindler
|
||||
/// \date 26.02.2017
|
||||
/// \brief Declaration of serialization related data, constants and stuff
|
||||
//============================================================================
|
||||
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
|
||||
|
||||
namespace ads
|
||||
{
|
||||
|
||||
namespace internal
|
||||
{
|
||||
// sentinel values used to validate state data
|
||||
enum VersionMarkers
|
||||
{
|
||||
VersionMarker = 0xff,
|
||||
ContainerMarker = 0xfe,
|
||||
SplitterMarker = 0xfd,
|
||||
DockAreaMarker = 0xfc,
|
||||
DockWidgetMarker = 0xfb
|
||||
};
|
||||
|
||||
static const bool RestoreTesting = true;
|
||||
static const bool Restore = false;
|
||||
} // internal
|
||||
} // namespace ads
|
||||
//-----------------------------------------------------------------------------
|
||||
#endif // DockManagerH
|
||||
@@ -28,27 +28,35 @@
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <DockWidgetTab.h>
|
||||
#include "DockWidgetTab.h"
|
||||
#include "DockWidget.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QAction>
|
||||
#include <QSplitter>
|
||||
#include <QStack>
|
||||
#include <QScrollArea>
|
||||
#include <QTextStream>
|
||||
#include <QPointer>
|
||||
#include <QEvent>
|
||||
#include <QDebug>
|
||||
#include <QToolBar>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
#include "DockContainerWidget.h"
|
||||
#include "DockAreaWidget.h"
|
||||
#include "DockManager.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockStateSerialization.h"
|
||||
#include "DockSplitter.h"
|
||||
#include "ads_globals.h"
|
||||
|
||||
|
||||
namespace ads
|
||||
{
|
||||
/**
|
||||
@@ -56,15 +64,22 @@ namespace ads
|
||||
*/
|
||||
struct DockWidgetPrivate
|
||||
{
|
||||
CDockWidget* _this;
|
||||
QBoxLayout* Layout;
|
||||
CDockWidget* _this = nullptr;
|
||||
QBoxLayout* Layout = nullptr;
|
||||
QWidget* Widget = nullptr;
|
||||
CDockWidgetTab* TitleWidget;
|
||||
CDockWidget::DockWidgetFeatures Features = CDockWidget::AllDockWidgetFeatures;
|
||||
CDockWidgetTab* TabWidget = nullptr;
|
||||
CDockWidget::DockWidgetFeatures Features = CDockWidget::DefaultDockWidgetFeatures;
|
||||
CDockManager* DockManager = nullptr;
|
||||
CDockAreaWidget* DockArea = nullptr;
|
||||
QAction* ToggleViewAction;
|
||||
QAction* ToggleViewAction = nullptr;
|
||||
bool Closed = false;
|
||||
QScrollArea* ScrollArea = nullptr;
|
||||
QToolBar* ToolBar = nullptr;
|
||||
Qt::ToolButtonStyle ToolBarStyleDocked = Qt::ToolButtonIconOnly;
|
||||
Qt::ToolButtonStyle ToolBarStyleFloating = Qt::ToolButtonTextUnderIcon;
|
||||
QSize ToolBarIconSizeDocked = QSize(16, 16);
|
||||
QSize ToolBarIconSizeFloating = QSize(24, 24);
|
||||
bool IsFloatingTopLevel = false;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@@ -82,20 +97,21 @@ struct DockWidgetPrivate
|
||||
void hideDockWidget();
|
||||
|
||||
/**
|
||||
* Hides a parent splitter if all dock widgets in the splitter are closed
|
||||
* Hides a dock area if all dock widgets in the area are closed.
|
||||
* This function updates the current selected tab and hides the parent
|
||||
* dock area if it is empty
|
||||
*/
|
||||
void hideEmptyParentSplitters();
|
||||
void updateParentDockArea();
|
||||
|
||||
/**
|
||||
* Hides a dock area if all dock widgets in the area are closed
|
||||
* Setup the top tool bar
|
||||
*/
|
||||
void hideEmptyParentDockArea();
|
||||
void setupToolBar();
|
||||
|
||||
/**
|
||||
* Hides a floating widget if all dock areas are empty - that means,
|
||||
* if all dock widgets in all dock areas are closed
|
||||
* Setup the main scroll area
|
||||
*/
|
||||
void hideEmptyFloatingWidget();
|
||||
void setupScrollArea();
|
||||
};
|
||||
// struct DockWidgetPrivate
|
||||
|
||||
@@ -118,9 +134,10 @@ void DockWidgetPrivate::showDockWidget()
|
||||
}
|
||||
else
|
||||
{
|
||||
DockArea->show();
|
||||
DockArea->setCurrentIndex(DockArea->tabIndex(_this));
|
||||
QSplitter* Splitter = internal::findParent<QSplitter*>(_this);
|
||||
DockArea->setCurrentDockWidget(_this);
|
||||
DockArea->toggleView(true);
|
||||
TabWidget->show();
|
||||
QSplitter* Splitter = internal::findParent<QSplitter*>(DockArea);
|
||||
while (Splitter && !Splitter->isVisible())
|
||||
{
|
||||
Splitter->show();
|
||||
@@ -141,63 +158,52 @@ void DockWidgetPrivate::showDockWidget()
|
||||
//============================================================================
|
||||
void DockWidgetPrivate::hideDockWidget()
|
||||
{
|
||||
TitleWidget->hide();
|
||||
hideEmptyParentDockArea();
|
||||
hideEmptyParentSplitters();
|
||||
hideEmptyFloatingWidget();
|
||||
TabWidget->hide();
|
||||
updateParentDockArea();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockWidgetPrivate::hideEmptyParentSplitters()
|
||||
void DockWidgetPrivate::updateParentDockArea()
|
||||
{
|
||||
auto Splitter = internal::findParent<CDockSplitter*>(_this);
|
||||
while (Splitter && Splitter->isVisible())
|
||||
if (!DockArea)
|
||||
{
|
||||
if (!Splitter->hasVisibleContent())
|
||||
{
|
||||
Splitter->hide();
|
||||
}
|
||||
Splitter = internal::findParent<CDockSplitter*>(Splitter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockWidgetPrivate::hideEmptyParentDockArea()
|
||||
{
|
||||
auto OpenDockWidgets = DockArea->openedDockWidgets();
|
||||
if (OpenDockWidgets.count() > 1)
|
||||
auto NextDockWidget = DockArea->nextOpenDockWidget(_this);
|
||||
if (NextDockWidget)
|
||||
{
|
||||
CDockWidget* NextDockWidget;
|
||||
if (OpenDockWidgets.last() == _this)
|
||||
{
|
||||
NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
int NextIndex = OpenDockWidgets.indexOf(_this) + 1;
|
||||
NextDockWidget = OpenDockWidgets[NextIndex];
|
||||
}
|
||||
|
||||
DockArea->setCurrentDockWidget(NextDockWidget);
|
||||
}
|
||||
else
|
||||
{
|
||||
DockArea->hide();
|
||||
DockArea->hideAreaWithNoVisibleContent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockWidgetPrivate::hideEmptyFloatingWidget()
|
||||
void DockWidgetPrivate::setupToolBar()
|
||||
{
|
||||
CDockContainerWidget* Container = _this->dockContainer();
|
||||
if (Container->isFloating() && Container->openedDockAreas().isEmpty())
|
||||
{
|
||||
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(Container);
|
||||
FloatingWidget->hide();
|
||||
}
|
||||
ToolBar = new QToolBar(_this);
|
||||
ToolBar->setObjectName("dockWidgetToolBar");
|
||||
Layout->insertWidget(0, ToolBar);
|
||||
ToolBar->setIconSize(QSize(16, 16));
|
||||
ToolBar->toggleViewAction()->setEnabled(false);
|
||||
ToolBar->toggleViewAction()->setVisible(false);
|
||||
_this->connect(_this, SIGNAL(topLevelChanged(bool)), SLOT(setToolbarFloatingStyle(bool)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockWidgetPrivate::setupScrollArea()
|
||||
{
|
||||
ScrollArea = new QScrollArea(_this);
|
||||
ScrollArea->setObjectName("dockWidgetScrollArea");
|
||||
ScrollArea->setWidgetResizable(true);
|
||||
Layout->addWidget(ScrollArea);
|
||||
}
|
||||
|
||||
|
||||
@@ -213,17 +219,18 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
|
||||
setWindowTitle(title);
|
||||
setObjectName(title);
|
||||
|
||||
d->TitleWidget = new CDockWidgetTab(this);
|
||||
d->ToggleViewAction = new QAction(title);
|
||||
d->TabWidget = new CDockWidgetTab(this);
|
||||
d->ToggleViewAction = new QAction(title, this);
|
||||
d->ToggleViewAction->setCheckable(true);
|
||||
connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this,
|
||||
SLOT(toggleView(bool)));
|
||||
setToolbarFloatingStyle(false);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
CDockWidget::~CDockWidget()
|
||||
{
|
||||
qDebug() << "~CDockWidget()";
|
||||
ADS_PRINT("~CDockWidget()");
|
||||
delete d;
|
||||
}
|
||||
|
||||
@@ -239,18 +246,35 @@ void CDockWidget::setToggleViewActionChecked(bool Checked)
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setWidget(QWidget* widget)
|
||||
void CDockWidget::setWidget(QWidget* widget, eInsertMode InsertMode)
|
||||
{
|
||||
if (d->Widget)
|
||||
QScrollArea* ScrollAreaWidget = qobject_cast<QScrollArea*>(widget);
|
||||
if (ScrollAreaWidget || ForceNoScrollArea == InsertMode)
|
||||
{
|
||||
d->Layout->replaceWidget(d->Widget, widget);
|
||||
d->Layout->addWidget(widget);
|
||||
if (ScrollAreaWidget && ScrollAreaWidget->viewport())
|
||||
{
|
||||
ScrollAreaWidget->viewport()->setProperty("dockWidgetContent", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d->Layout->addWidget(widget);
|
||||
d->setupScrollArea();
|
||||
d->ScrollArea->setWidget(widget);
|
||||
}
|
||||
|
||||
d->Widget = widget;
|
||||
d->Widget->setProperty("dockWidgetContent", true);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QWidget* CDockWidget::takeWidget()
|
||||
{
|
||||
d->ScrollArea->takeWidget();
|
||||
d->Layout->removeWidget(d->Widget);
|
||||
d->Widget->setParent(nullptr);
|
||||
return d->Widget;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,23 +286,31 @@ QWidget* CDockWidget::widget() const
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidgetTab* CDockWidget::titleBar() const
|
||||
CDockWidgetTab* CDockWidget::tabWidget() const
|
||||
{
|
||||
return d->TitleWidget;
|
||||
return d->TabWidget;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setFeatures(DockWidgetFeatures features)
|
||||
{
|
||||
if (d->Features == features)
|
||||
{
|
||||
return;
|
||||
}
|
||||
d->Features = features;
|
||||
emit featuresChanged(d->Features);
|
||||
d->TabWidget->onDockWidgetFeaturesChanged();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setFeature(DockWidgetFeature flag, bool on)
|
||||
{
|
||||
d->Features.setFlag(flag, on);
|
||||
auto Features = features();
|
||||
internal::setFlag(Features, flag, on);
|
||||
setFeatures(Features);
|
||||
}
|
||||
|
||||
|
||||
@@ -306,21 +338,51 @@ void CDockWidget::setDockManager(CDockManager* DockManager)
|
||||
//============================================================================
|
||||
CDockContainerWidget* CDockWidget::dockContainer() const
|
||||
{
|
||||
return internal::findParent<CDockContainerWidget*>(this);
|
||||
if (d->DockArea)
|
||||
{
|
||||
return d->DockArea->dockContainer();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockAreaWidget* CDockWidget::dockAreaWidget() const
|
||||
{
|
||||
return internal::findParent<CDockAreaWidget*>(this);
|
||||
return d->DockArea;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidget::isFloating() const
|
||||
{
|
||||
return dockContainer() ? dockContainer()->isFloating() : false;
|
||||
if (!isInFloatingContainer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return dockContainer()->topLevelDockWidget() == this;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidget::isInFloatingContainer() const
|
||||
{
|
||||
auto Container = dockContainer();
|
||||
if (!Container)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Container->isFloating())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -349,7 +411,7 @@ void CDockWidget::setToggleViewActionMode(eToggleViewActionMode Mode)
|
||||
else
|
||||
{
|
||||
d->ToggleViewAction->setCheckable(false);
|
||||
d->ToggleViewAction->setIcon(d->TitleWidget->icon());
|
||||
d->ToggleViewAction->setIcon(d->TabWidget->icon());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,11 +419,33 @@ void CDockWidget::setToggleViewActionMode(eToggleViewActionMode Mode)
|
||||
//============================================================================
|
||||
void CDockWidget::toggleView(bool Open)
|
||||
{
|
||||
// If the toggle view action mode is ActionModeShow, then Open is always
|
||||
// true if the sender is the toggle view action
|
||||
QAction* Sender = qobject_cast<QAction*>(sender());
|
||||
if (Sender == d->ToggleViewAction && !d->ToggleViewAction->isCheckable())
|
||||
{
|
||||
Open = true;
|
||||
}
|
||||
// If the dock widget state is different, then we really need to toggle
|
||||
// the state. If we are in the right state, then we simply make this
|
||||
// dock widget the current dock widget
|
||||
if (d->Closed != !Open)
|
||||
{
|
||||
toggleViewInternal(Open);
|
||||
}
|
||||
else if (Open && d->DockArea)
|
||||
{
|
||||
d->DockArea->setCurrentDockWidget(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::toggleViewInternal(bool Open)
|
||||
{
|
||||
CDockContainerWidget* DockContainer = dockContainer();
|
||||
CDockWidget* TopLevelDockWidgetBefore = DockContainer
|
||||
? DockContainer->topLevelDockWidget() : nullptr;
|
||||
|
||||
if (Open)
|
||||
{
|
||||
@@ -375,6 +459,29 @@ void CDockWidget::toggleView(bool Open)
|
||||
d->ToggleViewAction->blockSignals(true);
|
||||
d->ToggleViewAction->setChecked(Open);
|
||||
d->ToggleViewAction->blockSignals(false);
|
||||
if (d->DockArea)
|
||||
{
|
||||
d->DockArea->toggleDockWidgetView(this, Open);
|
||||
}
|
||||
|
||||
if (Open && TopLevelDockWidgetBefore)
|
||||
{
|
||||
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetBefore, false);
|
||||
}
|
||||
|
||||
// Here we need to call the dockContainer() function again, because if
|
||||
// this dock widget was unassigned before the call to showDockWidget() then
|
||||
// it has a dock container now
|
||||
DockContainer = dockContainer();
|
||||
CDockWidget* TopLevelDockWidgetAfter = DockContainer
|
||||
? DockContainer->topLevelDockWidget() : nullptr;
|
||||
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetAfter, true);
|
||||
CFloatingDockContainer* FloatingContainer = DockContainer->floatingWidget();
|
||||
if (FloatingContainer)
|
||||
{
|
||||
FloatingContainer->updateWindowTitle();
|
||||
}
|
||||
|
||||
if (!Open)
|
||||
{
|
||||
emit closed();
|
||||
@@ -387,15 +494,15 @@ void CDockWidget::toggleView(bool Open)
|
||||
void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
|
||||
{
|
||||
d->DockArea = DockArea;
|
||||
d->ToggleViewAction->setChecked(DockArea != nullptr);
|
||||
d->ToggleViewAction->setChecked(DockArea != nullptr && !this->isClosed());
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::saveState(QXmlStreamWriter& s) const
|
||||
{
|
||||
s.writeStartElement("DockWidget");
|
||||
s.writeAttribute("ObjectName", objectName());
|
||||
s.writeStartElement("Widget");
|
||||
s.writeAttribute("Name", objectName());
|
||||
s.writeAttribute("Closed", QString::number(d->Closed ? 1 : 0));
|
||||
s.writeEndElement();
|
||||
}
|
||||
@@ -404,27 +511,78 @@ void CDockWidget::saveState(QXmlStreamWriter& s) const
|
||||
//============================================================================
|
||||
void CDockWidget::flagAsUnassigned()
|
||||
{
|
||||
d->Closed = true;
|
||||
setParent(d->DockManager);
|
||||
setVisible(false);
|
||||
setDockArea(nullptr);
|
||||
titleBar()->setParent(this);
|
||||
tabWidget()->setParent(this);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidget::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::WindowTitleChange)
|
||||
switch (e->type())
|
||||
{
|
||||
emit titleChanged(windowTitle());
|
||||
case QEvent::Hide:
|
||||
emit visibilityChanged(false);
|
||||
break;
|
||||
|
||||
case QEvent::Show:
|
||||
emit visibilityChanged(geometry().right() >= 0 && geometry().bottom() >= 0);
|
||||
break;
|
||||
|
||||
case QEvent::WindowTitleChange :
|
||||
{
|
||||
const auto title = windowTitle();
|
||||
if (d->TabWidget)
|
||||
{
|
||||
d->TabWidget->setText(title);
|
||||
}
|
||||
if (d->ToggleViewAction)
|
||||
{
|
||||
d->ToggleViewAction->setText(title);
|
||||
}
|
||||
if (d->DockArea)
|
||||
{
|
||||
d->DockArea->markTitleBarMenuOutdated();//update tabs menu
|
||||
}
|
||||
emit titleChanged(title);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QFrame::event(e);
|
||||
|
||||
return Super::event(e);
|
||||
}
|
||||
|
||||
|
||||
#ifndef QT_NO_TOOLTIP
|
||||
//============================================================================
|
||||
void CDockWidget::setTabToolTip(const QString &text)
|
||||
{
|
||||
if (d->TabWidget)
|
||||
{
|
||||
d->TabWidget->setToolTip(text);
|
||||
}
|
||||
if (d->ToggleViewAction)
|
||||
{
|
||||
d->ToggleViewAction->setToolTip(text);
|
||||
}
|
||||
if (d->DockArea)
|
||||
{
|
||||
d->DockArea->markTitleBarMenuOutdated();//update tabs menu
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setIcon(const QIcon& Icon)
|
||||
{
|
||||
d->TitleWidget->setIcon(Icon);
|
||||
d->TabWidget->setIcon(Icon);
|
||||
if (!d->ToggleViewAction->isCheckable())
|
||||
{
|
||||
d->ToggleViewAction->setIcon(Icon);
|
||||
@@ -435,10 +593,229 @@ void CDockWidget::setIcon(const QIcon& Icon)
|
||||
//============================================================================
|
||||
QIcon CDockWidget::icon() const
|
||||
{
|
||||
return d->TitleWidget->icon();
|
||||
return d->TabWidget->icon();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QToolBar* CDockWidget::toolBar() const
|
||||
{
|
||||
return d->ToolBar;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QToolBar* CDockWidget::createDefaultToolBar()
|
||||
{
|
||||
if (!d->ToolBar)
|
||||
{
|
||||
d->setupToolBar();
|
||||
}
|
||||
|
||||
return d->ToolBar;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setToolBar(QToolBar* ToolBar)
|
||||
{
|
||||
if (d->ToolBar)
|
||||
{
|
||||
delete d->ToolBar;
|
||||
}
|
||||
|
||||
d->ToolBar = ToolBar;
|
||||
d->Layout->insertWidget(0, d->ToolBar);
|
||||
this->connect(this, SIGNAL(topLevelChanged(bool)), SLOT(setToolbarFloatingStyle(bool)));
|
||||
setToolbarFloatingStyle(isFloating());
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setToolBarStyle(Qt::ToolButtonStyle Style, eState State)
|
||||
{
|
||||
if (StateFloating == State)
|
||||
{
|
||||
d->ToolBarStyleFloating = Style;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->ToolBarStyleDocked = Style;
|
||||
}
|
||||
|
||||
setToolbarFloatingStyle(isFloating());
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
Qt::ToolButtonStyle CDockWidget::toolBarStyle(eState State) const
|
||||
{
|
||||
if (StateFloating == State)
|
||||
{
|
||||
return d->ToolBarStyleFloating;
|
||||
}
|
||||
else
|
||||
{
|
||||
return d->ToolBarStyleDocked;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setToolBarIconSize(const QSize& IconSize, eState State)
|
||||
{
|
||||
if (StateFloating == State)
|
||||
{
|
||||
d->ToolBarIconSizeFloating = IconSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->ToolBarIconSizeDocked = IconSize;
|
||||
}
|
||||
|
||||
setToolbarFloatingStyle(isFloating());
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QSize CDockWidget::toolBarIconSize(eState State) const
|
||||
{
|
||||
if (StateFloating == State)
|
||||
{
|
||||
return d->ToolBarIconSizeFloating;
|
||||
}
|
||||
else
|
||||
{
|
||||
return d->ToolBarIconSizeDocked;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setToolbarFloatingStyle(bool Floating)
|
||||
{
|
||||
if (!d->ToolBar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto IconSize = Floating ? d->ToolBarIconSizeFloating : d->ToolBarIconSizeDocked;
|
||||
if (IconSize != d->ToolBar->iconSize())
|
||||
{
|
||||
d->ToolBar->setIconSize(IconSize);
|
||||
}
|
||||
|
||||
auto ButtonStyle = Floating ? d->ToolBarStyleFloating : d->ToolBarStyleDocked;
|
||||
if (ButtonStyle != d->ToolBar->toolButtonStyle())
|
||||
{
|
||||
d->ToolBar->setToolButtonStyle(ButtonStyle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::emitTopLevelEventForWidget(CDockWidget* TopLevelDockWidget, bool Floating)
|
||||
{
|
||||
if (TopLevelDockWidget)
|
||||
{
|
||||
TopLevelDockWidget->dockAreaWidget()->updateTitleBarVisibility();
|
||||
TopLevelDockWidget->emitTopLevelChanged(Floating);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::emitTopLevelChanged(bool Floating)
|
||||
{
|
||||
if (Floating != d->IsFloatingTopLevel)
|
||||
{
|
||||
d->IsFloatingTopLevel = Floating;
|
||||
emit topLevelChanged(d->IsFloatingTopLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setClosedState(bool Closed)
|
||||
{
|
||||
d->Closed = Closed;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QSize CDockWidget::minimumSizeHint() const
|
||||
{
|
||||
return QSize(60, 40);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::setFloating()
|
||||
{
|
||||
if (isClosed())
|
||||
{
|
||||
return;
|
||||
}
|
||||
d->TabWidget->detachDockWidget();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::deleteDockWidget()
|
||||
{
|
||||
dockManager()->removeDockWidget(this);
|
||||
deleteLater();
|
||||
d->Closed = true;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidget::closeDockWidget()
|
||||
{
|
||||
closeDockWidgetInternal(true);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockWidget::closeDockWidgetInternal(bool ForceClose)
|
||||
{
|
||||
if (!ForceClose)
|
||||
{
|
||||
emit closeRequested();
|
||||
}
|
||||
|
||||
if (!ForceClose && features().testFlag(CDockWidget::CustomCloseHandling))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
|
||||
{
|
||||
// If the dock widget is floating, then we check if we also need to
|
||||
// delete the floating widget
|
||||
if (isFloating())
|
||||
{
|
||||
CFloatingDockContainer* FloatingWidget = internal::findParent<
|
||||
CFloatingDockContainer*>(this);
|
||||
if (FloatingWidget->dockWidgets().count() == 1)
|
||||
{
|
||||
FloatingWidget->deleteLater();
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatingWidget->hide();
|
||||
}
|
||||
}
|
||||
deleteDockWidget();
|
||||
}
|
||||
else
|
||||
{
|
||||
toggleView(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ads
|
||||
|
||||
|
||||