Compare commits

...

142 Commits
3.4.2 ... 3.6.0

Author SHA1 Message Date
Uwe Kindler
175c836c93 Added Qt5x11extras to CMake build 2020-08-31 13:04:15 +02:00
githubuser0xFFFF
76304172ab Update linux-builds.yml
Added x11extras to workflow
2020-08-31 13:00:27 +02:00
githubuser0xFFFF
0eb3978aee Update .travis.yml
Added x11extras
2020-08-31 12:51:42 +02:00
Uwe Kindler
73f42d55ca Updated linux stylesheets to fix titlebar issue on KDE 2020-08-31 11:57:30 +02:00
Uwe Kindler
059a055483 Renamed FloatingContainerForceCustomTitleBar to
FloatingWidgetForceQWidgetTitleBar
2020-08-31 09:48:32 +02:00
Uwe Kindler
dcf1ee393e Added support for CSS styling of custom widget titlebar close button 2020-08-31 09:38:18 +02:00
Uwe Kindler
04aecb3693 Some code cleanup, adjustments to match ADS coding style 2020-08-31 08:32:56 +02:00
helywin
533d174abc Finished implementing maximize for linux.
Added FloatingContainerForc*TitleBar to switch between native and custom titlebar.

Co-authored-by: SleepProgger <SleepProgger@users.noreply.github.com>
2020-08-29 05:03:21 +02:00
Uwe Kindler
48fb999bd0 Fix static build of centralwidget example 2020-08-24 15:46:51 +02:00
Uwe Kindler
5443e5f998 Merge branch 'centralwidget' 2020-08-24 13:44:19 +02:00
Uwe Kindler
543d226ba3 Fixed memory leak 2020-08-24 13:32:50 +02:00
Uwe Kindler
03b1848b43 Reverted changed 2020-08-24 13:25:20 +02:00
Uwe Kindler
05ab8d2067 Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-08-24 13:23:40 +02:00
Uwe Kindler
c28a27c81c Reverted changes that cause application crash 2020-08-24 13:22:34 +02:00
Uwe Kindler
1b42048135 Fixed pure virtual function call 2020-08-24 11:33:40 +02:00
Uwe Kindler
bfe6b9bd26 Merge branch 'FixesPack_Parenting_Memory_leaks_etc' of https://github.com/ymiroshnyk/Qt-Advanced-Docking-System into ymiroshnyk-FixesPack_Parenting_Memory_leaks_etc 2020-08-24 11:22:50 +02:00
Uwe Kindler
08a8cee1c6 Updated centralwidget test 2020-08-24 11:14:58 +02:00
Uwe Kindler
835a532e75 Corrected constness of some functions, changed signatur of setCentralWidget function 2020-08-24 10:22:12 +02:00
Uwe Kindler
d383ade03c Merge branch 'Central-Widget' of https://github.com/hulswit/Qt-Advanced-Docking-System into hulswit-Central-Widget 2020-08-24 09:50:12 +02:00
Uwe Kindler
6d9c4cee02 Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-08-24 09:47:34 +02:00
Yurii Miroshnyk
a565239c4a Fixes pack. Parenting, memory leaks, floating widgets deleting.
* DockWidget always has DockAreaWidget as parent. It's not necessary to make it nullptr. This fixes many bugs related to restoring inactive tabbed DockWidgets.

* Fixed memory leaks related to QBoxLayout::takeAt().

* Fixed algorithm of deleting remaining floating widgets after restore.
2020-08-21 19:24:55 +03:00
hulswit
ba69f3e6b9 CMake Fix 2020-08-21 13:42:52 +02:00
hulswit
14c29f695c Central widget update
Updated the setting of central widget with option to set where the possible old central widget will be placed. Fixed option of "unsetting" central widget by setting it to nullptr.
2020-08-21 13:30:59 +02:00
shelomentsev
703a9b3e12 Update the state of close button on titlebar and tabbar when CDockWidget::DockWidgetClosable changed. (#240) 2020-08-21 08:09:13 +02:00
shelomentsev
0eca1b0433 Memory leak (#242)
* Delete widgets without parents in CDockAreaLayout.

* Fixed the place where dock widgets witout parents are destroyed.
2020-08-21 08:08:33 +02:00
hulswit
691c9683ce Merge branch 'master' into Central-Widget 2020-08-20 16:37:05 +02:00
hulswit
1a11e5ddcd Central Widget concept added
Adde option to set a dock widget as central widget. It influences resizing behavior of the splitters. The central widget will be stretched with the main window and remaing dock widgets and threir respective areas will be resized only vertically if docked left or right  and horizontaly if docked top or bottom
2020-08-20 16:36:02 +02:00
shelomentsev
a4d281dbb6 Floating window fixes. (#239)
* Don't show a CFloatingDockContainer if all its CDockWidget were hidden before its first shown.

* Destroy empty CFloatingDockContainer when removing CDockWidget via removeDockWidget function.
2020-08-20 12:58:15 +02:00
shelomentsev
8361f90dce Delete widgets without parents in CDockAreaLayout. (#241) 2020-08-20 12:56:37 +02:00
Uwe Kindler
04b4ff8b4b Fixed typo in DockWidget documentation 2020-08-19 15:16:13 +02:00
Uwe Kindler
121248c3c5 Improved documentation 2020-08-19 13:49:20 +02:00
Uwe Kindler
c44d0c87e3 Fixed broken SimpleExample application 2020-08-19 13:38:53 +02:00
Uwe Kindler
c6cf9487ba Added maximize button svg icon 2020-08-18 20:36:02 +02:00
Uwe Kindler
c78cc17730 Properly persist dock area HideSingleWidgetTitleBar flag (and all other dock area flags) 2020-08-18 10:48:35 +02:00
Uwe Kindler
81a0234b05 Added HiveWE editor to showcase applications 2020-08-18 08:01:45 +02:00
Uwe Kindler
f72a8568c5 Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-08-17 23:51:14 +02:00
Uwe Kindler
11aec65967 Properly persist the AllowedAreas state of CDockAreaWidget 2020-08-17 23:50:37 +02:00
Nicolas Elie
75841415a3 Update Python bindings (#231)
* Update Python bindings to reflect changes in 8443414

* [Python] Fix no such signal error for signals with a reference to an object in ads namespace

* [Python] Update examples
2020-07-30 13:44:05 +02:00
Uwe Kindler
edc799bc54 Added D-Tect X software to showcase 2020-07-29 08:09:00 +02:00
githubuser0xFFFF
1d0b20337f Update README.md 2020-07-23 18:06:57 +02:00
Uwe Kindler
4a6d2d3514 Changed demos to delete the dock manager when the main window is closes to ensure that all floating widgets als "closed" (destroyed) 2020-07-22 11:28:41 +02:00
Some Guy
8443414ae3 Added setHideSingleWidgetTitleBar to DockWidgetArea 2020-07-21 08:20:17 +02:00
Uwe Kindler
81c99745d4 Fixed a bug when dragging a FloatingDragPreview from another floating widget over an empty MainWindow 2020-07-13 09:08:39 +02:00
Uwe Kindler
d6831caea4 Some refatoring in DockFocusController to improve code 2020-07-13 08:43:51 +02:00
Uwe Kindler
aa25e1fd56 Improved emission of focusedDockWidgetChanged signal to ensure, that the application can restore the focus of the focused application dock widget content 2020-07-13 08:41:30 +02:00
Uwe Kindler
0459aff34f Cleanup of debug messages in DockFocusController 2020-07-10 22:08:28 +02:00
Uwe Kindler
aeb0a27401 Improved code documentation 2020-07-08 08:10:27 +02:00
Uwe Kindler
50e3ef3dd8 Fixed stealing of focus by tab close button 2020-07-08 08:08:50 +02:00
Uwe Kindler
9974256d71 Fixed double emission of focusedDockWidgetChanged() signal 2020-07-07 14:38:03 +02:00
Uwe Kindler
8cf4134125 Some changes to ensure emission of focusedDockWidgetChanged signal 2020-07-06 08:22:48 +02:00
Uwe Kindler
ef5b22c616 Merge branch 'master' into focus_changed_fix 2020-07-06 07:35:08 +02:00
Uwe Kindler
42161c807a Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-07-05 22:29:38 +02:00
Uwe Kindler
acfc96f57c Properly update DockAreaTabBar geometry if tab text changed 2020-07-05 22:29:13 +02:00
Uwe Kindler
e6e83d5775 Added test for CDockWidget::setWindowTitle function 2020-07-05 21:48:48 +02:00
Nicolas Elie
5b2bc2297b Update Python bindings and demo to reflect recent changes (#218)
* Generate Python stubs file for linters

* Sort members of ads namespace in generated __init__.py

* Fix pyi generatation in setup.py if building inplace

* Update sip files and demo
2020-07-04 17:07:48 +02:00
Uwe Kindler
2de3e7e3be Deferred focusedDockWidgetChanged signal until dock widget becomes visible 2020-07-03 23:24:20 +02:00
Uwe Kindler
0d242297ff Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-07-03 22:22:52 +02:00
Uwe Kindler
e2080b5cfc Restored default dock manager config flag settings 2020-07-03 22:22:00 +02:00
Uwe Kindler
679fa81f6d Added new CDockWidget feature flag focusable 2020-07-03 14:55:33 +02:00
Nicolas Elie
6d0f14e1a5 Generate Python stubs file for linters (#214)
* Generate Python stubs file for linters

* Sort members of ads namespace in generated __init__.py
2020-07-02 07:47:18 +02:00
Uwe Kindler
281127c2c3 Merge remote-tracking branch 'remotes/origin/issue212' 2020-07-01 07:48:36 +02:00
Uwe Kindler
8e621f1f20 Properly reparent TabWidget to DockWidget if TabWidget is removed from TabBar 2020-06-30 16:34:59 +02:00
Uwe Kindler
0948f73bf8 Properly reset DockManager pointer when removing DockWidget from DockManager 2020-06-30 11:45:23 +02:00
Uwe Kindler
4bc1a18db2 Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-06-30 10:00:03 +02:00
Uwe Kindler
80eb628ea3 Fixed naming of the dock area titlebar actions to be consistent 2020-06-30 09:59:42 +02:00
Uwe Kindler
d811915a0c Reset DockArea pointer of DockWidget when removing DockWidget from DockArea 2020-06-29 22:11:37 +02:00
Hannes Schulze
0225563b46 Fix Undefined Behavior in LastAddedAreaCache (#211) 2020-06-28 21:07:17 +02:00
Uwe Kindler
da20405a6a Fixed a compiler warning 2020-06-26 11:34:17 +02:00
Uwe Kindler
ace6d69695 Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-06-26 11:19:58 +02:00
Uwe Kindler
7baf0f90e8 Converted dock content creation functions to member functions to allow ui access 2020-06-26 11:19:37 +02:00
Uwe Kindler
2ad92ce958 Removed superfluous code to fix issue #209 2020-06-26 11:18:46 +02:00
Nick D'Ademo
50c4a8ed48 Update CMakeLists.txt (#204)
Pass header files to add_library() so they appear in the 'qtadvanceddocking' Visual Studio project.
Add path to header files in PUBLIC include build interface so the 'qtadvanceddocking' target can be built in-source in a CMake project.
2020-06-19 20:01:48 +02:00
githubuser0xFFFF
59d6a64098 Update README.md 2020-06-18 09:31:14 +02:00
Uwe Kindler
3de877fe56 Updated linux stylesheet
Default linux style uses now the provided SVG buttons for the floating widget title bar close button
2020-06-18 09:21:46 +02:00
Uwe Kindler
e2cebd9dcf Updated stylesheet to provide uniform look of icons for all platforms
added detach-button icon
2020-06-18 08:29:41 +02:00
Uwe Kindler
58744408f0 Switched dock area close button icon to ads specific svg icon 2020-06-14 16:25:18 +02:00
Uwe Kindler
e36655a7ab Fixed wrong current index when removing a widget from CDockAreaLayout 2020-06-14 16:12:56 +02:00
Uwe Kindler
ffed6a9c5f Merged pull request #201 but made it configurable via config flag 2020-06-14 10:39:07 +02:00
Davide Faconti
38d8e6aa25 fix 2020-06-13 17:22:25 +02:00
Davide Faconti
c109ef836a use equal splitter size for widget added programmatically 2020-06-13 16:59:13 +02:00
Uwe Kindler
caa1a9f330 Stylesheet update
Updated stylesheet to use svg icon for close button instead of system icon
2020-06-11 08:36:01 +02:00
Uwe Kindler
e71884b23d Replaced configFlags().testFlag() with testConfigFlag() to improve code readibility 2020-06-11 08:06:37 +02:00
Uwe Kindler
d04c386948 Splitted stylesheets into default and focus_highlighting to properly support both use cases 2020-06-11 07:43:06 +02:00
Uwe Kindler
6a25de327c Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-06-10 16:20:22 +02:00
Uwe Kindler
e63d1b1683 Fixed a bug that caused invisible TabWidget for dock widgets that are not part of a restored state 2020-06-10 16:07:42 +02:00
Nicolas Elie
fa2ab356e1 Update PyQt bindings for 3.5.0 (#198) 2020-06-10 15:08:31 +02:00
Uwe Kindler
80f92e5697 Added note about the new focus highlighting feature on the project page 2020-06-10 07:41:14 +02:00
Uwe Kindler
0c13402516 Added documentation for FocusHighlighting flag 2020-06-10 07:16:35 +02:00
Uwe Kindler
97e3d72566 Disabled focus highliighting in demo application 2020-06-09 22:00:46 +02:00
Uwe Kindler
682aaf66eb Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-06-09 21:58:12 +02:00
Uwe Kindler
c939df73fa Merge branch 'focused_dockwidget' 2020-06-09 21:57:23 +02:00
Uwe Kindler
fdf169ce9a Fixed docking of floating widgets for MacOS 2020-06-09 20:29:19 +02:00
githubuser0xFFFF
4b730a4949 Update README.md 2020-06-09 15:39:16 +02:00
Uwe Kindler
788c357cc0 Added missing README.md changes 2020-06-09 15:35:02 +02:00
Uwe Kindler
e3844b8d6c Added Python section to README.md 2020-06-09 15:32:00 +02:00
Uwe Kindler
ff3fcdcacd Removed debug output 2020-06-09 14:40:13 +02:00
Uwe Kindler
a9268e6bf7 Fixed build issues and improved styling
Improved styling of close buttons and focused close buttons
2020-06-07 17:28:23 +02:00
Uwe Kindler
0227bd1786 Added icon for proper styling of focused close icon 2020-06-07 17:19:07 +02:00
Uwe Kindler
227037e42a Added new close button SVG icon 2020-06-07 15:20:24 +02:00
Uwe Kindler
cd495a14ec Fixed MSVC compiler warning 2020-06-07 15:20:08 +02:00
Uwe Kindler
312a8cf500 Enabled ClickFocus for CDockWidget to support focussing in case the content does not support it
Renamed FocusStyling to FocusHighlighting
2020-06-06 14:59:03 +02:00
Uwe Kindler
2fc8bbe9c9 Added mising DockFocusController files 2020-06-05 21:03:47 +02:00
Uwe Kindler
f5c4b26aab Moved focus related functionality into CDockFocusController class to keep the dock manager code clean 2020-06-05 20:42:43 +02:00
Uwe Kindler
c4d2d72e92 Added activateWindow() call in CFloatingDockCiontainer::showEvent
This is required to properly style the floating widget that contains the currently focused widget
2020-06-05 13:40:36 +02:00
Uwe Kindler
f90f0b0427 Properly implemented focusedDockWidgetChanged() signal 2020-06-05 12:14:26 +02:00
Uwe Kindler
d360b4ced2 Merge branch 'master' into focused_dockwidget 2020-06-05 07:40:39 +02:00
Uwe Kindler
f074ea9d67 Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2020-06-05 07:40:10 +02:00
Uwe Kindler
2e8137ad85 Fixed setting of CDockingStateReader file version - use internal file version instead of user file version 2020-06-05 07:39:51 +02:00
Uwe Kindler
a65b1bdcaf Removed new dropped signals 2020-06-05 07:27:44 +02:00
Uwe Kindler
4041aa72cc Implemented proper support for setting floating widget focused widget 2020-06-05 06:55:43 +02:00
Hugo Slepicka
4d2de7bb2a FIX: Update Python bindings for 3.4.2 and current master. (#193)
* FIX: Update python bindings for 3.4.2.

* FIX: Try to fix windows build.

* FIX: Add const at nativeEvent argument.

* FIX: Adjusting sip bindings for changes from 8b6df4aaa5.
2020-06-04 23:55:02 +02:00
Uwe Kindler
bcb7118710 Fixed typos 2020-06-04 20:48:59 +02:00
Uwe Kindler
45390506dd Continued implementation 2020-06-04 20:40:23 +02:00
Uwe Kindler
f58a3d4401 Change to support loading of older files without UserVersion atribute 2020-06-03 19:53:17 +02:00
Uwe Kindler
a3e979a8ad Disabled setFocus in CDockWidget::setActiveTab 2020-06-03 19:49:57 +02:00
Uwe Kindler
adb72737e8 Merge branch 'version_fix' into focused_dockwidget 2020-06-03 17:53:05 +02:00
Uwe Kindler
e626a7e302 Merge branch 'master' into focused_dockwidget 2020-06-03 17:52:46 +02:00
Uwe Kindler
8b6df4aaa5 Fixed saveState() and restoreState() version handling to work like the function from QMainWindow 2020-06-03 07:25:09 +02:00
Uwe Kindler
ae999f132e Improved focus styling 2020-05-23 14:45:49 +02:00
Uwe Kindler
9aa958e8b0 Made all focus related code optional - only if FocusStyling flag is enabled 2020-05-23 11:17:31 +02:00
Uwe Kindler
5652c8440e Added new CDockManger config flag FocusStyling 2020-05-23 11:10:03 +02:00
Uwe Kindler
26f4c9b049 Merge branch 'focused_dockwidget' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System into focused_dockwidget 2020-05-22 21:30:10 +02:00
Uwe Kindler
ce11fa9d10 Merge branch 'master' into focused_dockwidget 2020-05-22 21:28:02 +02:00
Uwe Kindler
333d2920db Merge remote-tracking branch 'origin/focused_dockwidget' into focused_dockwidget 2020-05-22 19:26:54 +02:00
Uwe Kindler
25eb02d07c Added support for focus styling of CFloatingWidgetTitleBra 2020-05-22 19:23:40 +02:00
Uwe Kindler
3b2f940efa Fixed windows build 2020-05-21 10:32:31 +02:00
Uwe Kindler
9dcbe91f02 Merge branch 'focused_dockwidget' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System into focused_dockwidget 2020-05-21 08:29:55 +02:00
Uwe Kindler
4da810ba7c Added window()->activateWindow() dropFloatingWidget() function 2020-05-20 14:20:27 +02:00
Uwe Kindler
819f1effc5 Added support for focus styling of CFloatingWidgetTitleBra 2020-05-19 22:53:52 +02:00
Uwe Kindler
ba94ef3493 Merge branch 'master' into focused_dockwidget 2020-05-19 20:51:19 +02:00
Uwe Kindler
0127fd89a3 Merge branch 'master' into focused_dockwidget 2020-05-17 12:26:22 +02:00
Uwe Kindler
79cb889d83 Improved focus style handling 2020-05-17 08:51:58 +02:00
Uwe Kindler
e760d3e967 Improved focus handling when dropping a dock widget 2020-05-14 09:06:04 +02:00
Uwe Kindler
c5333a2414 Merge branch 'master' into focused_dockwidget 2020-05-14 07:34:31 +02:00
Uwe Kindler
3a0c2a3113 Some refactorings in onFocusChanged() to improve code readibility 2020-05-13 22:51:44 +02:00
Uwe Kindler
789f78354a Merge branch 'master' into focused_dockwidget 2020-05-13 21:27:21 +02:00
Uwe Kindler
4c75168152 Improved focus setting when closing a dock area widget 2020-05-13 13:18:05 +02:00
Uwe Kindler
64a2024513 Removed debug output 2020-05-13 11:20:32 +02:00
Uwe Kindler
056e1ef947 Improved highlighting focused dock widget 2020-05-13 11:17:43 +02:00
Uwe Kindler
f54869fbf7 Improved setting of CDockWidgetTab focus 2020-05-11 16:29:58 +02:00
Uwe Kindler
835a20f03f Merge branch 'master' into focused_dockwidget 2020-05-11 15:50:47 +02:00
Uwe Kindler
067338ef23 Enable styling of focused dockwidget 2020-05-10 19:30:34 +02:00
82 changed files with 5098 additions and 869 deletions

View File

@@ -16,6 +16,7 @@ jobs:
run: |
sudo apt-get update --fix-missing
sudo apt-get install qt5-default
sudo apt-get install libqt5x11extras5-dev
- name: qmake
run: qmake
- name: make

1
.gitignore vendored
View File

@@ -382,3 +382,4 @@ MigrationBackup/
FodyWeavers.xsd
/ build
/Settings.ini
.vscode/settings.json

View File

@@ -18,6 +18,7 @@ matrix:
packages:
- qt55base
- qt55tools
- qt55x11extras
- gcc-9
- g++-9
script:
@@ -44,6 +45,7 @@ matrix:
packages:
- qt514base
- qt514tools
- qt514x11extras
- gcc-9
- g++-9
- libc6-i386
@@ -74,6 +76,7 @@ matrix:
packages:
- qt514base
- qt514tools
- qt514x11extras
- gcc-9
- g++-9
- libc6-i386
@@ -104,6 +107,7 @@ matrix:
packages:
- qt514base
- qt514tools
- qt514x11extras
- gcc-9
- g++-9
- libc6-i386
@@ -140,6 +144,7 @@ matrix:
packages:
- qt514base
- qt514tools
- qt514x11extras
- gcc-9
- g++-9
- libc6-i386

View File

@@ -7,26 +7,28 @@
[What's new](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest) •
[Documentation](doc/user-guide.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 environments (IDEs) such as Visual Studio.
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 environments (IDEs) such as Visual Studio.
[![Video Advanced Docking](doc/advanced-docking_video.png)](https://www.youtube.com/watch?v=7pdNfafg3Qc)
Everything is implemented with standard Qt functionality without any
platform specific code. Basic usage of QWidgets and QLayouts and using basic
styles as much as possible.
## New and Noteworthy
This work is based on and inspired by the
[Advanced Docking System for Qt](https://github.com/mfreiholz/Qt-Advanced-Docking-System)
from Manuel Freiholz. I did an almost complete rewrite of his code to improve
code quality, readibility and to fix all issues from the issue tracker
of his docking system project.
The [release 3.5.0](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.5.0)
adds the new [focus highlighting](doc/user-guide.md#focushighlighting) feature.
This optional feature enables highlighting of the focused dock widget like you
know it from Visual Studio.
![FocusHighlighting](doc/cfg_flag_FocusHighlighting.gif)
[learn more...](doc/user-guide.md#focushighlighting)
## Features
### Overview
- [New and Noteworthy](#new-and-noteworthy)
- [Features](#features)
- [Overview](#overview)
- [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)
@@ -38,6 +40,7 @@ of his docking system project.
- [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)
- [Python PyQt5 Bindings](#python-pyqt5-bindings)
- [Tested Compatible Environments](#tested-compatible-environments)
- [Windows](#windows)
- [macOS](#macos)
@@ -55,6 +58,8 @@ of his docking system project.
- [Qt Design Studio](#qt-design-studio)
- [QmixElements](#qmixelements)
- [ezEditor](#ezeditor)
- [D-Tect X](#d-tect-x)
- [HiveWE](#hivewe)
### Docking everywhere - no central widget
@@ -136,6 +141,20 @@ You can detach dock widgets and also dock areas in the following ways:
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.
### Python PyQt5 Bindings
![Python Logo](doc/python_logo.png)
The Advanced Docking System comes with a complete Python integration based on
PyQt5 bindings. The package is available via [conda-forge](https://github.com/conda-forge/pyqtads-feedstock). The python integration has been contributed to this project
by the following people:
- [n-elie](https://github.com/n-elie)
- [Hugo Slepicka](https://github.com/hhslepicka)
- [K Lauer](https://github.com/klauer)
Latest working version: [3.5.2](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.5.2)
## Tested Compatible Environments
### Windows
@@ -247,7 +266,13 @@ MainWindow::~MainWindow()
## Developers
- Uwe Kindler, Project Maintainer
- Manuel Freiholz
- Manuel Freiholz
This work is based on and inspired by the
[Advanced Docking System for Qt](https://github.com/mfreiholz/Qt-Advanced-Docking-System)
from Manuel Freiholz. I did an almost complete rewrite of his code to improve
code quality, readibility and to fix all issues from the issue tracker
of his docking system project.
## License information
@@ -288,7 +313,7 @@ If this project help you reduce time to develop or if you just like it, you can
From version 4.12 on, Qt Creator uses the Advanced Docking Framework for its
Qt Quick Designer. This improves the usability when using multiple screens.
![Qt Creator](doc/qtcreator.png)
![Qt Creator](doc/showcase_qtcreator.png)
### [Qt Design Studio](https://www.qt.io/ui-design-tools)
@@ -296,7 +321,7 @@ Taken from the [Qt Blog](https://www.qt.io/blog/qt-design-studio-1.5-beta-releas
> The most obvious change in [Qt Design Studio 1.5](https://www.qt.io/blog/qt-design-studio-1.5-beta-released) is the integration of dock widgets using the Qt Advanced Docking System. This allows the user to fully customize the workspace and also to undock any view into its own top level window. This especially improves the usability when using multiple screens.
![Qt Design Studio](doc/qt_design_studio.png)
![Qt Design Studio](doc/showcase_qt_design_studio.png)
### [QmixElements](https://www.cetoni.com/products/qmixelements/)
@@ -304,7 +329,7 @@ The QmixElements software from [CETONI](https://www.cetoni.com) is a comprehensi
plugin-based and modular laboratory automation software for controlling CETONI devices using a joint graphical user interface. The software features a powerful script system to automate processes. This [blog post](https://www.cetoni.com/blog/qmixelements-advanced-docking-system/) gives a nice overview about the use of the Qt
Advanced Docking System in the QmixElements sofware.
![QmixElements](doc/qmix_elements.png)
![QmixElements](doc/showcase_qmix_elements.png)
### [ezEditor](https://github.com/ezEngine/ezEngine)
@@ -312,4 +337,24 @@ The ezEditor is a full blown graphical editor used for editing scenes and
importing and authoring assets for the [ezEngine](https://github.com/ezEngine/ezEngine) -
an open source C++ game engine in active development.
![ezEditor](doc/ezEngine_editor.png)
![ezEditor](doc/showcase_ezEngine_editor.png)
### [D-Tect X](https://www.duerr-ndt.com/products/ndt-software/d-tect-xray-inspection-software.html)
D-Tect X is a X-ray inspection software for industrial radiography. It is a state-of-the-art 64-bit application which supports GPU (Graphics Processing Unit) acceleration and takes full advantage of computers with multiple CPU cores. A large set of tools assist the user in image analysis and evaluation. Thanks to the Qt Advanced Docking System the flexible and intuitive user interface can be completely customized to each users preference.
[learn more...](https://www.duerr-ndt.com/products/ndt-software/d-tect-xray-inspection-software.html)
![D-TectX](doc/showcase_d-tect-x.jpg)
### [HiveWE](https://github.com/stijnherfst/HiveWE)
HiveWE is a Warcraft III world editor. It focusses on speed and ease of use,
especially for large maps where the regular World Editor is often too slow and clunky.
It has a JASS editor with syntax hightlighting, tabs, code completion and more.
The JASS editor uses the Qt Advanced Docking System for the management and layout
of the open editor windows.
[learn more...](https://github.com/stijnherfst/HiveWE)
![HiveWE](doc/showcase_hivewe.png)

View File

@@ -2,4 +2,5 @@ include(CMakeFindDependencyMacro)
find_dependency(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
find_dependency(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
find_dependency(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
find_dependency(Qt5X11Extras ${REQUIRED_QT_VERSION} REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/adsTargets.cmake")

View File

@@ -78,35 +78,6 @@
//============================================================================
static ads::CDockWidget* createLongTextLabelDockWidget(QMenu* ViewMenu)
{
static int LabelCount = 0;
QLabel* l = new QLabel();
l->setWordWrap(true);
l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
l->setText(QString("Label %1 %2 - 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.")
.arg(LabelCount)
.arg(QTime::currentTime().toString("hh:mm:ss:zzz")));
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++));
DockWidget->setWidget(l);
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
/**
* 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
@@ -164,71 +135,6 @@ public:
};
//============================================================================
static ads::CDockWidget* createCalendarDockWidget(QMenu* ViewMenu)
{
static int CalendarCount = 0;
QCalendarWidget* w = new QCalendarWidget();
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
// The following lines are for testing the setWidget() and takeWidget()
// functionality
DockWidget->setWidget(w);
DockWidget->setWidget(w); // what happens if we set a widget if a widget is already set
DockWidget->takeWidget(); // we remove the widget
DockWidget->setWidget(w); // and set the widget again - there should be no error
DockWidget->setToggleViewActionMode(ads::CDockWidget::ActionModeShow);
DockWidget->setIcon(svgIcon(":/adsdemo/images/date_range.svg"));
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
//============================================================================
static ads::CDockWidget* createFileSystemTreeDockWidget(QMenu* ViewMenu)
{
static int FileSystemCount = 0;
QTreeView* w = new QTreeView();
w->setFrameShape(QFrame::NoFrame);
QFileSystemModel* m = new QFileSystemModel(w);
m->setRootPath(QDir::currentPath());
w->setModel(m);
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());
QMenu* OptionsMenu = new QMenu(DockWidget);
OptionsMenu->setTitle(QObject::tr("Options"));
OptionsMenu->setToolTip(OptionsMenu->title());
OptionsMenu->setIcon(svgIcon(":/adsdemo/images/custom-menu-button.svg"));
auto MenuAction = OptionsMenu->menuAction();
// The object name of the action will be set for the QToolButton that
// is created in the dock area title bar. You can use this name for CSS
// styling
MenuAction->setObjectName("optionsMenu");
DockWidget->setTitleBarActions({OptionsMenu->menuAction()});
auto a = OptionsMenu->addAction(QObject::tr("Clear Editor"));
w->connect(a, SIGNAL(triggered()), SLOT(clear()));
return DockWidget;
}
//===========================================================================
/**
@@ -246,58 +152,6 @@ public:
};
//============================================================================
static ads::CDockWidget* createTableWidget(QMenu* ViewMenu)
{
static int TableCount = 0;
auto w = new CMinSizeTableWidget();
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"));
DockWidget->setMinimumSizeHintMode(ads::CDockWidget::MinimumSizeHintFromContent);
auto ToolBar = DockWidget->createDefaultToolBar();
auto Action = ToolBar->addAction(svgIcon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen");
QObject::connect(Action, &QAction::triggered, [=]()
{
if (DockWidget->isFullScreen())
{
DockWidget->showNormal();
}
else
{
DockWidget->showFullScreen();
}
});
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
//============================================================================
/**
@@ -311,6 +165,7 @@ struct MainWindowPrivate
QWidgetAction* PerspectiveListAction = nullptr;
QComboBox* PerspectiveComboBox = nullptr;
ads::CDockManager* DockManager = nullptr;
ads::CDockWidget* WindowTitleTestDockWidget = nullptr;
MainWindowPrivate(CMainWindow* _public) : _this(_public) {}
@@ -343,14 +198,181 @@ struct MainWindowPrivate
* Restore the perspective listo of the dock manager
*/
void restorePerspectives();
/**
* Creates a dock widget with a file system tree view
*/
ads::CDockWidget* createFileSystemTreeDockWidget()
{
static int FileSystemCount = 0;
QTreeView* w = new QTreeView();
w->setFrameShape(QFrame::NoFrame);
QFileSystemModel* m = new QFileSystemModel(w);
m->setRootPath(QDir::currentPath());
w->setModel(m);
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1")
.arg(FileSystemCount++));
DockWidget->setWidget(w);
ui.menuView->addAction(DockWidget->toggleViewAction());
// We disable focus to test focus highlighting if the dock widget content
// does not support focus
w->setFocusPolicy(Qt::NoFocus);
auto ToolBar = DockWidget->createDefaultToolBar();
ToolBar->addAction(ui.actionSaveState);
ToolBar->addAction(ui.actionRestoreState);
return DockWidget;
}
/**
* Create a dock widget with a QCalendarWidget
*/
ads::CDockWidget* createCalendarDockWidget()
{
static int CalendarCount = 0;
QCalendarWidget* w = new QCalendarWidget();
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
// The following lines are for testing the setWidget() and takeWidget()
// functionality
DockWidget->setWidget(w);
DockWidget->setWidget(w); // what happens if we set a widget if a widget is already set
DockWidget->takeWidget(); // we remove the widget
DockWidget->setWidget(w); // and set the widget again - there should be no error
DockWidget->setToggleViewActionMode(ads::CDockWidget::ActionModeShow);
DockWidget->setIcon(svgIcon(":/adsdemo/images/date_range.svg"));
ui.menuView->addAction(DockWidget->toggleViewAction());
auto ToolBar = DockWidget->createDefaultToolBar();
ToolBar->addAction(ui.actionSaveState);
ToolBar->addAction(ui.actionRestoreState);
return DockWidget;
}
/**
* Create dock widget with a text label
*/
ads::CDockWidget* createLongTextLabelDockWidget()
{
static int LabelCount = 0;
QLabel* l = new QLabel();
l->setWordWrap(true);
l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
l->setText(QString("Label %1 %2 - 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.")
.arg(LabelCount)
.arg(QTime::currentTime().toString("hh:mm:ss:zzz")));
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++));
DockWidget->setWidget(l);
ui.menuView->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
/**
* Creates as imple editor widget
*/
ads::CDockWidget* createEditorWidget()
{
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);
ui.menuView->addAction(DockWidget->toggleViewAction());
QMenu* OptionsMenu = new QMenu(DockWidget);
OptionsMenu->setTitle(QObject::tr("Options"));
OptionsMenu->setToolTip(OptionsMenu->title());
OptionsMenu->setIcon(svgIcon(":/adsdemo/images/custom-menu-button.svg"));
auto MenuAction = OptionsMenu->menuAction();
// The object name of the action will be set for the QToolButton that
// is created in the dock area title bar. You can use this name for CSS
// styling
MenuAction->setObjectName("optionsMenu");
DockWidget->setTitleBarActions({OptionsMenu->menuAction()});
auto a = OptionsMenu->addAction(QObject::tr("Clear Editor"));
w->connect(a, SIGNAL(triggered()), SLOT(clear()));
return DockWidget;
}
/**
* Create a table widget
*/
ads::CDockWidget* createTableWidget()
{
static int TableCount = 0;
auto w = new CMinSizeTableWidget();
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"));
DockWidget->setMinimumSizeHintMode(ads::CDockWidget::MinimumSizeHintFromContent);
auto ToolBar = DockWidget->createDefaultToolBar();
auto Action = ToolBar->addAction(svgIcon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen");
QObject::connect(Action, &QAction::triggered, [=]()
{
if (DockWidget->isFullScreen())
{
DockWidget->showNormal();
}
else
{
DockWidget->showFullScreen();
}
});
ui.menuView->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
#ifdef Q_OS_WIN
/**
* Creates an ActiveX widget on windows
*/
ads::CDockWidget* createActiveXWidget(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);
ui.menuView->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
#endif
};
//============================================================================
void MainWindowPrivate::createContent()
{
// Test container docking
QMenu* ViewMenu = ui.menuView;
auto DockWidget = createCalendarDockWidget(ViewMenu);
auto DockWidget = createCalendarDockWidget();
DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
auto SpecialDockArea = DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
@@ -360,19 +382,16 @@ void MainWindowPrivate::createContent()
//SpecialDockArea->setAllowedAreas({ads::LeftDockWidgetArea, ads::RightDockWidgetArea}); // just for testing
}
DockManager->addDockWidget(ads::LeftDockWidgetArea, createLongTextLabelDockWidget(ViewMenu));
auto FileSystemWidget = createFileSystemTreeDockWidget(ViewMenu);
auto ToolBar = FileSystemWidget->createDefaultToolBar();
ToolBar->addAction(ui.actionSaveState);
ToolBar->addAction(ui.actionRestoreState);
DockWidget = createLongTextLabelDockWidget();
WindowTitleTestDockWidget = DockWidget;
DockWidget->setFeature(ads::CDockWidget::DockWidgetFocusable, false);
DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
auto FileSystemWidget = createFileSystemTreeDockWidget();
FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetFloatable, false);
appendFeaturStringToWindowTitle(FileSystemWidget);
DockManager->addDockWidget(ads::BottomDockWidgetArea, FileSystemWidget);
FileSystemWidget = createFileSystemTreeDockWidget(ViewMenu);
ToolBar = FileSystemWidget->createDefaultToolBar();
ToolBar->addAction(ui.actionSaveState);
ToolBar->addAction(ui.actionRestoreState);
FileSystemWidget = createFileSystemTreeDockWidget();
FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetMovable, false);
FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetFloatable, false);
appendFeaturStringToWindowTitle(FileSystemWidget);
@@ -380,11 +399,14 @@ void MainWindowPrivate::createContent()
// Test custom factory - we inject a help button into the title bar
ads::CDockComponentsFactory::setFactory(new CCustomComponentsFactory());
auto TopDockArea = DockManager->addDockWidget(ads::TopDockWidgetArea, FileSystemWidget);
// Uncomment the next line if you would like to test the
// HideSingleWidgetTitleBar functionality
// TopDockArea->setDockAreaFlag(ads::CDockAreaWidget::HideSingleWidgetTitleBar, true);
ads::CDockComponentsFactory::resetDefaultFactory();
// We create a calendar widget and clear all flags to prevent the dock area
// from closing
DockWidget = createCalendarDockWidget(ViewMenu);
DockWidget = createCalendarDockWidget();
DockWidget->setTabToolTip(QString("Tab ToolTip\nHodie est dies magna"));
auto DockArea = DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, TopDockArea);
@@ -400,18 +422,18 @@ void MainWindowPrivate::createContent()
TitleBar->insertWidget(Index + 1, CustomButton);
QObject::connect(CustomButton, &QToolButton::clicked, [=]()
{
auto DockWidget = createEditorWidget(ui.menuView);
auto DockWidget = createEditorWidget();
DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
DockManager->addDockWidgetTabToArea(DockWidget, DockArea);
_this->connect(DockWidget, SIGNAL(closeRequested()), SLOT(onEditorCloseRequested()));
});
// 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::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), BottomDockArea);
auto RighDockArea = DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(), TopDockArea);
DockManager->addDockWidget(ads::TopDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
auto BottomDockArea = DockManager->addDockWidget(ads::BottomDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), BottomDockArea);
auto Action = ui.menuTests->addAction(QString("Set %1 Floating").arg(DockWidget->windowTitle()));
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setFloating()));
@@ -421,9 +443,9 @@ void MainWindowPrivate::createContent()
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(raise()));
#ifdef Q_OS_WIN
if (!DockManager->configFlags().testFlag(ads::CDockManager::OpaqueUndocking))
if (!ads::CDockManager::testConfigFlag(ads::CDockManager::OpaqueUndocking))
{
DockManager->addDockWidget(ads::CenterDockWidgetArea, createActiveXWidget(ViewMenu), RighDockArea);
DockManager->addDockWidget(ads::CenterDockWidgetArea, createActiveXWidget(), RighDockArea);
}
#endif
@@ -479,6 +501,9 @@ void MainWindowPrivate::createActions()
ui.menuTests->addSeparator();
a = ui.menuTests->addAction("Show Status Dialog");
_this->connect(a, SIGNAL(triggered()), SLOT(showStatusDialog()));
a = ui.menuTests->addAction("Toggle Label 0 Window Title");
_this->connect(a, SIGNAL(triggered()), SLOT(toggleDockWidgetWindowTitle()));
ui.menuTests->addSeparator();
}
@@ -571,6 +596,14 @@ CMainWindow::CMainWindow(QWidget *parent) :
// dock widget.
// CDockManager::setConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar, true);
// uncomment the following line to enable focus highlighting of the dock
// widget that has the focus
CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
// uncomment if you would like to enable an equal distribution of the
// available size of a splitter to all contained dock widgets
// CDockManager::setConfigFlag(CDockManager::EqualSplitOnInsertion, true);
// Now create the dock manager and its content
d->DockManager = new CDockManager(this);
@@ -601,6 +634,9 @@ CMainWindow::~CMainWindow()
void CMainWindow::closeEvent(QCloseEvent* event)
{
d->saveState();
// Delete dock manager here to delete all floating widgets. This ensures
// that all top level windows of the dock manager are properly closed
d->DockManager->deleteLater();
QMainWindow::closeEvent(event);
}
@@ -656,13 +692,14 @@ void CMainWindow::onViewToggled(bool Open)
//============================================================================
void CMainWindow::onViewVisibilityChanged(bool Visible)
{
Q_UNUSED(Visible);
auto DockWidget = qobject_cast<ads::CDockWidget*>(sender());
if (!DockWidget)
{
return;
}
qDebug() << DockWidget->objectName() << " visibilityChanged(" << Visible << ")";
//qDebug() << DockWidget->objectName() << " visibilityChanged(" << Visible << ")";
}
@@ -672,7 +709,7 @@ void CMainWindow::createEditor()
QObject* Sender = sender();
QVariant vFloating = Sender->property("Floating");
bool Floating = vFloating.isValid() ? vFloating.toBool() : true;
auto DockWidget = createEditorWidget(d->ui.menuView);
auto DockWidget = d->createEditorWidget();
DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
connect(DockWidget, SIGNAL(closeRequested()), SLOT(onEditorCloseRequested()));
@@ -705,7 +742,7 @@ void CMainWindow::onEditorCloseRequested()
//============================================================================
void CMainWindow::createTable()
{
auto DockWidget = createTableWidget(d->ui.menuView);
auto DockWidget = d->createTableWidget();
DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
auto FloatingWidget = d->DockManager->addDockWidgetFloating(DockWidget);
FloatingWidget->move(QPoint(40, 40));
@@ -719,3 +756,20 @@ void CMainWindow::showStatusDialog()
Dialog.exec();
}
//============================================================================
void CMainWindow::toggleDockWidgetWindowTitle()
{
QString Title = d->WindowTitleTestDockWidget->windowTitle();
int i = Title.indexOf(" (Test)");
if (-1 == i)
{
Title += " (Test)";
}
else
{
Title = Title.left(i);
}
d->WindowTitleTestDockWidget->setWindowTitle(Title);
}

View File

@@ -64,6 +64,7 @@ private slots:
void createTable();
void onEditorCloseRequested();
void showStatusDialog();
void toggleDockWidgetWindowTitle();
};
#endif // MAINWINDOW_H

View File

@@ -10,11 +10,11 @@ from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker,
QtCriticalMsg, QtFatalMsg, QSize)
from PyQt5.QtGui import (QGuiApplication, QIcon, QCloseEvent)
from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel,
QMenu, QTreeView, QAction, QWidgetAction,
QComboBox, QStyle, QSizePolicy, QInputDialog, QMenu,
QToolButton, QWidget, QPlainTextEdit,
QTableWidget, QTableWidgetItem, QApplication,
QMessageBox)
QMenu, QTreeView, QAction, QWidgetAction,
QComboBox, QStyle, QSizePolicy, QInputDialog, QMenu,
QToolButton, QWidget, QPlainTextEdit,
QTableWidget, QTableWidgetItem, QApplication,
QMessageBox)
try:
from PyQt5.QAxContainer import QAxWidget
except ImportError:
@@ -48,7 +48,7 @@ def features_string(dock_widget: QtAds.CDockWidget) -> str:
f = dock_widget.features()
closable = f & QtAds.CDockWidget.DockWidgetClosable
movable = f & QtAds.CDockWidget.DockWidgetMovable
floatable = f &QtAds.CDockWidget.DockWidgetFloatable
floatable = f & QtAds.CDockWidget.DockWidgetFloatable
return "c{} m{} f{}".format("+" if closable else "-",
"+" if movable else "-",
@@ -69,91 +69,7 @@ def svg_icon(filename: str):
icon = QIcon(filename)
icon.addPixmap(icon.pixmap(92))
return icon
def create_long_text_label_dock_widget(view_menu: QMenu) -> 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, datetime.datetime.now().strftime("%H:%M:%S:%f")))
dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count))
_State.label_count += 1
dock_widget.setWidget(label)
view_menu.addAction(dock_widget.toggleViewAction())
return dock_widget
def create_calendar_dock_widget(view_menu: QMenu) -> QtAds.CDockWidget:
widget = QCalendarWidget()
dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count))
_State.calendar_count += 1
# The following lines are for testing the setWidget() and takeWidget()
# functionality
dock_widget.setWidget(widget)
dock_widget.setWidget(widget) # what happens if we set a widget if a widget is already set
dock_widget.takeWidget() # we remove the widget
dock_widget.setWidget(widget) # and set the widget again - there should be no error
dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow)
dock_widget.setIcon(svg_icon(":/adsdemo/images/date_range.svg"))
view_menu.addAction(dock_widget.toggleViewAction())
return dock_widget
def create_file_system_tree_dock_widget(view_menu: QMenu) -> 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
def create_editor_widget(view_menu: QMenu) -> QtAds.CDockWidget:
widget = QPlainTextEdit()
widget.setPlaceholderText("This is an editor. If you close the editor, it will be "
"deleted. Enter your text here.")
widget.setStyleSheet("border: none")
dock_widget = QtAds.CDockWidget("Editor {}".format(_State.editor_count))
_State.editor_count += 1
dock_widget.setWidget(widget)
dock_widget.setIcon(svg_icon(":/adsdemo/images/edit.svg"))
dock_widget.setFeature(QtAds.CDockWidget.CustomCloseHandling, True)
view_menu.addAction(dock_widget.toggleViewAction())
options_menu = QMenu(dock_widget)
options_menu.setTitle("Options")
options_menu.setToolTip(options_menu.title())
options_menu.setIcon(svg_icon(":/adsdemo/images/custom-menu-button.svg"))
menu_action = options_menu.menuAction()
# The object name of the action will be set for the QToolButton that
# is created in the dock area title bar. You can use this name for CSS
# styling
menu_action.setObjectName("options_menu")
dock_widget.setTitleBarActions([options_menu.menuAction()])
a = options_menu.addAction("Clear Editor")
a.triggered.connect(widget.clear)
return dock_widget
class CMinSizeTableWidget(QTableWidget):
"""Custom QTableWidget with a minimum size hint to test CDockWidget
@@ -162,43 +78,6 @@ class CMinSizeTableWidget(QTableWidget):
def minimumSizeHint(self) -> QSize:
return QSize(300, 100)
def create_table_widget(view_menu: QMenu) -> QtAds.CDockWidget:
widget = CMinSizeTableWidget()
dock_widget = QtAds.CDockWidget("Table {}".format(_State.table_count))
_State.table_count += 1
COLCOUNT = 5
ROWCOUNT = 30
widget.setColumnCount(COLCOUNT)
widget.setRowCount(ROWCOUNT)
for col in range(ROWCOUNT):
widget.setHorizontalHeaderItem(col, QTableWidgetItem("Col {}".format(col+1)))
for row in range(ROWCOUNT):
widget.setItem(row, col, QTableWidgetItem("T {:}-{:}".format(row+1, col+1)))
dock_widget.setWidget(widget)
dock_widget.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromContent)
toolbar = dock_widget.createDefaultToolBar()
action = toolbar.addAction(svg_icon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen")
def on_toggle_fullscreen():
if dock_widget.isFullScreen():
dock_widget.showNormal()
else:
dock_widget.showFullScreen()
action.triggered.connect(on_toggle_fullscreen)
view_menu.addAction(dock_widget.toggleViewAction())
return dock_widget
if ACTIVEX_AVAILABLE:
def create_activex_widget(view_menu: QMenu, parent: QWidget = None) -> QtAds.CDockWidget:
widget = QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent)
dock_widget = QtAds.CDockWidget("Active X {}".format(_State.activex_count))
_State.activex_count += 1
dock_widget.setWidget(widget)
view_menu.addAction(dock_widget.toggleViewAction())
return dock_widget
class CCustomComponentsFactory(QtAds.CDockComponentsFactory):
@@ -235,37 +114,45 @@ class MainWindow(MainWindowUI, MainWindowBase):
# uncomment the following line if you want to use opaque undocking and
# opaque splitter resizing
#QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultOpaqueConfig);
#QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultOpaqueConfig)
# uncomment the following line if you want a fixed tab width that does
# not change if the visibility of the close button changes
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.RetainTabSizeWhenCloseButtonHidden, True)
# uncomment the following line if you don't want close button on DockArea's title bar
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasCloseButton, false);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasCloseButton, False)
# uncomment the following line if you don't want undock button on DockArea's title bar
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasUndockButton, false);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasUndockButton, False)
# uncomment the following line if you don't want tabs menu button on DockArea's title bar
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasTabsMenuButton, false);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasTabsMenuButton, False)
# uncomment the following line if you don't want disabled buttons to appear on DockArea's title bar
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHideDisabledButtons, true);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHideDisabledButtons, True)
# uncomment the following line if you want to show tabs menu button on DockArea's title bar only when there are more than one tab and at least of them has elided title
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaDynamicTabsMenuButtonVisibility, true);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaDynamicTabsMenuButtonVisibility, True)
# uncomment the following line if you want floating container to always show application title instead of active dock widget's title
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetTitle, false);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetTitle, False)
# uncomment the following line if you want floating container to show active dock widget's icon instead of always showing application icon
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetIcon, true);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetIcon, True)
# uncomment the following line if you want a central widget in the main dock container (the dock manager) without a titlebar
# If you enable this code, you can test it in the demo with the Calendar 0
# dock widget.
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.HideSingleCentralWidgetTitleBar, true);
#QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.HideSingleCentralWidgetTitleBar, True)
# uncomment the following line to enable focus highlighting of the dock
# widget that has the focus
QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
# uncomment if you would like to enable an equal distribution of the
# available size of a splitter to all contained dock widgets
# QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.EqualSplitOnInsertion, True)
# Now create the dock manager and its content
self.dock_manager = QtAds.CDockManager(self)
@@ -288,8 +175,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
def create_content(self):
# Test container docking
view_menu = self.menuView
dock_widget = create_calendar_dock_widget(view_menu)
dock_widget = self.create_calendar_dock_widget()
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
special_dock_area = self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
@@ -297,8 +183,10 @@ class MainWindow(MainWindowUI, MainWindowBase):
special_dock_area.setAllowedAreas(QtAds.OuterDockAreas)
# special_dock_area.setAllowedAreas(QtAds.LeftDockWidgetArea | QtAds.RightDockWidgetArea) # just for testing
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)
dock_widget = self.create_long_text_label_dock_widget()
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetFocusable, False)
self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
file_system_widget = self.create_file_system_tree_dock_widget()
tool_bar = file_system_widget.createDefaultToolBar()
tool_bar.addAction(self.actionSaveState)
tool_bar.addAction(self.actionRestoreState)
@@ -306,10 +194,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
append_feature_string_to_window_title(file_system_widget)
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.actionSaveState)
tool_bar.addAction(self.actionRestoreState)
file_system_widget = self.create_file_system_tree_dock_widget()
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
append_feature_string_to_window_title(file_system_widget)
@@ -317,11 +202,14 @@ class MainWindow(MainWindowUI, MainWindowBase):
# Test custom factory - we inject a help button into the title bar
QtAds.CDockComponentsFactory.setFactory(CCustomComponentsFactory())
top_dock_area = self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, file_system_widget)
# Uncomment the next line if you would like to test the
# setHideSingleWidgetTitleBar() functionality
# top_dock_area.setHideSingleWidgetTitleBar(True)
QtAds.CDockComponentsFactory.resetDefaultFactory()
# We create a calendar widget and clear all flags to prevent the dock area
# from closing
dock_widget = create_calendar_dock_widget(view_menu)
dock_widget = self.create_calendar_dock_widget()
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
@@ -336,7 +224,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
index = title_bar.indexOf(title_bar.tabBar())
title_bar.insertWidget(index + 1, custom_button)
def on_button_clicked():
dock_widget = create_editor_widget(self.menuView)
dock_widget = self.create_editor_widget()
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
self.dock_manager.addDockWidgetTabToArea(dock_widget, dock_area)
dock_widget.closeRequested.connect(self.on_editor_close_requested)
@@ -345,21 +233,21 @@ class MainWindow(MainWindowUI, MainWindowBase):
# 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.create_long_text_label_dock_widget(), top_dock_area)
self.dock_manager.addDockWidget(
QtAds.TopDockWidgetArea,
create_long_text_label_dock_widget(view_menu), right_dock_area)
self.create_long_text_label_dock_widget(), right_dock_area)
bottom_dock_area = self.dock_manager.addDockWidget(
QtAds.BottomDockWidgetArea,
create_long_text_label_dock_widget(view_menu), right_dock_area)
self.create_long_text_label_dock_widget(), right_dock_area)
self.dock_manager.addDockWidget(
QtAds.CenterDockWidgetArea,
create_long_text_label_dock_widget(view_menu), right_dock_area)
self.create_long_text_label_dock_widget(), right_dock_area)
self.dock_manager.addDockWidget(
QtAds.CenterDockWidgetArea,
create_long_text_label_dock_widget(view_menu), bottom_dock_area)
self.create_long_text_label_dock_widget(), bottom_dock_area)
action = self.menuTests.addAction("Set {} Floating".format(dock_widget.windowTitle()))
@@ -373,7 +261,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
flags = self.dock_manager.configFlags()
if flags & QtAds.CDockManager.OpaqueUndocking:
self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea,
create_activex_widget(view_menu), right_dock_area)
self.create_activex_widget(), right_dock_area)
for dock_widget in self.dock_manager.dockWidgetsMap().values():
dock_widget.viewToggled.connect(self.on_view_toggled)
@@ -425,6 +313,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
def closeEvent(self, event: QCloseEvent):
self.save_state()
self.dock_manager.deleteLater()
super().closeEvent(event)
def on_actionSaveState_triggered(self, state: bool):
@@ -460,13 +349,13 @@ class MainWindow(MainWindowUI, MainWindowBase):
if dock_widget is None:
return
qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible))
# qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible))
def create_editor(self):
sender = self.sender()
floating = sender.property("Floating")
print("Floating:", floating)
dock_widget = create_editor_widget(self.menuView)
dock_widget = self.create_editor_widget()
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
dock_widget.closeRequested.connect(self.on_editor_close_requested)
@@ -484,7 +373,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
dock_widget.closeDockWidget()
def create_table(self):
dock_widget = create_table_widget(self.menuView)
dock_widget = self.create_table_widget()
dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget)
floating_widget.move(QPoint(40, 40))
@@ -545,6 +434,124 @@ class MainWindow(MainWindowUI, MainWindowBase):
self.perspective_combo_box.setCurrentText(perspective_name)
self.save_perspectives()
def create_long_text_label_dock_widget(self) -> 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, datetime.datetime.now().strftime("%H:%M:%S:%f")))
dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count))
_State.label_count += 1
dock_widget.setWidget(label)
self.menuView.addAction(dock_widget.toggleViewAction())
return dock_widget
def create_calendar_dock_widget(self) -> QtAds.CDockWidget:
widget = QCalendarWidget()
dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count))
_State.calendar_count += 1
# The following lines are for testing the setWidget() and takeWidget()
# functionality
dock_widget.setWidget(widget)
dock_widget.setWidget(widget) # what happens if we set a widget if a widget is already set
dock_widget.takeWidget() # we remove the widget
dock_widget.setWidget(widget) # and set the widget again - there should be no error
dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow)
dock_widget.setIcon(svg_icon(":/adsdemo/images/date_range.svg"))
self.menuView.addAction(dock_widget.toggleViewAction())
return dock_widget
def create_file_system_tree_dock_widget(self) -> 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)
self.menuView.addAction(dock_widget.toggleViewAction())
return dock_widget
def create_editor_widget(self) -> QtAds.CDockWidget:
widget = QPlainTextEdit()
widget.setPlaceholderText("This is an editor. If you close the editor, it will be "
"deleted. Enter your text here.")
widget.setStyleSheet("border: none")
dock_widget = QtAds.CDockWidget("Editor {}".format(_State.editor_count))
_State.editor_count += 1
dock_widget.setWidget(widget)
dock_widget.setIcon(svg_icon(":/adsdemo/images/edit.svg"))
dock_widget.setFeature(QtAds.CDockWidget.CustomCloseHandling, True)
self.menuView.addAction(dock_widget.toggleViewAction())
options_menu = QMenu(dock_widget)
options_menu.setTitle("Options")
options_menu.setToolTip(options_menu.title())
options_menu.setIcon(svg_icon(":/adsdemo/images/custom-menu-button.svg"))
menu_action = options_menu.menuAction()
# The object name of the action will be set for the QToolButton that
# is created in the dock area title bar. You can use this name for CSS
# styling
menu_action.setObjectName("options_menu")
dock_widget.setTitleBarActions([options_menu.menuAction()])
a = options_menu.addAction("Clear Editor")
a.triggered.connect(widget.clear)
return dock_widget
def create_table_widget(self) -> QtAds.CDockWidget:
widget = CMinSizeTableWidget()
dock_widget = QtAds.CDockWidget("Table {}".format(_State.table_count))
_State.table_count += 1
COLCOUNT = 5
ROWCOUNT = 30
widget.setColumnCount(COLCOUNT)
widget.setRowCount(ROWCOUNT)
for col in range(ROWCOUNT):
widget.setHorizontalHeaderItem(col, QTableWidgetItem("Col {}".format(col + 1)))
for row in range(ROWCOUNT):
widget.setItem(row, col, QTableWidgetItem("T {:}-{:}".format(row + 1, col + 1)))
dock_widget.setWidget(widget)
dock_widget.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromContent)
toolbar = dock_widget.createDefaultToolBar()
action = toolbar.addAction(svg_icon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen")
def on_toggle_fullscreen():
if dock_widget.isFullScreen():
dock_widget.showNormal()
else:
dock_widget.showFullScreen()
action.triggered.connect(on_toggle_fullscreen)
self.menuView.addAction(dock_widget.toggleViewAction())
return dock_widget
def create_activex_widget(self, parent: QWidget = None) -> QtAds.CDockWidget:
widget = QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent)
dock_widget = QtAds.CDockWidget("Active X {}".format(_State.activex_count))
_State.activex_count += 1
dock_widget.setWidget(widget)
self.menuView.addAction(dock_widget.toggleViewAction())
return dock_widget
def my_message_output(type, context, msg):
if type == QtDebugMsg:

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
doc/python_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
doc/showcase_d-tect-x.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

Before

Width:  |  Height:  |  Size: 385 KiB

After

Width:  |  Height:  |  Size: 385 KiB

BIN
doc/showcase_hivewe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

View File

Before

Width:  |  Height:  |  Size: 539 KiB

After

Width:  |  Height:  |  Size: 539 KiB

View File

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 157 KiB

View File

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -23,13 +23,14 @@
- [`FloatingContainerHasWidgetTitle`](#floatingcontainerhaswidgettitle)
- [`FloatingContainerHasWidgetIcon`](#floatingcontainerhaswidgeticon)
- [`HideSingleCentralWidgetTitleBar`](#hidesinglecentralwidgettitlebar)
- [`FocusHighlighting`](#focushighlighting)
- [Styling](#styling)
- [Disabling the Internal Style Sheet](#disabling-the-internal-style-sheet)
## Configuration Flags
The Advanced Docking System has a number of global configuration options to
configure the design and the functionality of the docking system. Each
configure the design and the functionality of the docking system. Eachs
configuration will be explained in detail in the following sections.
### Setting Configuration Flags
@@ -284,7 +285,8 @@ otherwise (default setting) it displays application icon.
### `HideSingleCentralWidgetTitleBar`
If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden.
If there is only one single visible dock widget in the main dock container (the dock manager)
and if this flag is set, then the titlebar of this dock widget will be hidden.
This only makes sense for non draggable and non floatable dock widgets and enables
the creation of some kind of "central" static widget. Because the titlebar is
hidden, it is not possible to drag out the central widget to make it floating
@@ -299,6 +301,114 @@ still has a titlebar to drag it out of the main window.
![HideSingleCentralWidgetTitleBar false](cfg_flag_HideSingleCentralWidgetTitleBar_false.png)
### `FocusHighlighting`
If this is enabled, the docking system is able to highlight the tab and the
components of a dock area with a different style (i.e. a different color).
This option is disabled by default and needs to be enabled explicitely
because it adds some overhead. The dock manager needs to react on focus
changes and dock widget dragging to highlight the right dock widget. You should
enable it only, if you really need it for your application.
If the feature is enabled, you can also connect to the new dock manager
signal `focusedDockWidgetChanged(CDockWidget* old, CDockWidget* now)` to
react on focus changes and to prepare the content of the focused dock
widget.
You can click into the tab, the titlebar or the content of a dock widget
to focus it.
![FocusHighlighting](cfg_flag_FocusHighlighting.gif)
For the focused dock widget and dock widget tab, the property `focused` will
be set to true and you can use this property to style the focused dock
widget differently. The picture above uses the following styling:
```css
/* Color the tab with the nhighlight color */
ads--CDockWidgetTab[focused="true"]
{
background: palette(highlight);
border-color: palette(highlight);
}
/* Use a different colored close button icon to match the test color */
ads--CDockWidgetTab[focused="true"] > #tabCloseButton
{
qproperty-icon: url(:/ads/images/close-button-focused.svg)
}
/* Make a hovered focused close button a little bit lighter */
ads--CDockWidgetTab[focused="true"] > #tabCloseButton:hover
{
background: rgba(255, 255, 255, 48);
}
/* Make a pressed focused close button even more lighter */
ads--CDockWidgetTab[focused="true"] > #tabCloseButton:pressed
{
background: rgba(255, 255, 255, 92);
}
/* Use a different color for the tab label */
ads--CDockWidgetTab[focused="true"] QLabel
{
color: palette(light);
}
/* Paint a nice solid line for the whole title bar to create the illusion
of an active tab */
ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar
{
background: transparent;
border-bottom: 2px solid palette(highlight);
padding-bottom: 0px;
}
```
If you have a content widget that does not support focussing for some reason
(like `QVTKOpenGLStereoWidget` from the [VTK library](https://github.com/Kitware/VTK)),
then you can manually switch the focus by reacting on mouse events. The
following code shows, how to install en event filter on the `QVTKOpenGLStereoWidget`
to properly switch the focus on `QEvent::MouseButtonPress`:
```c++
static ads::CDockWidget* createVTK2DWindow(QMenu* ViewMenu, QObject* EventFilter)
{
QVTKOpenGLStereoWidget* qvtkOpenGLStereoWidget = new QVTKOpenGLStereoWidget;
ads::CDockWidget* DockWidget = new ads::CDockWidget("2D Window");
DockWidget->setWidget(qvtkOpenGLStereoWidget);
qvtkOpenGLStereoWidget->installEventFilter(EventFilter);
qvtkOpenGLStereoWidget->setProperty("DockWidget", QVariant::fromValue(DockWidget));
return DockWidget;
}
```
Now we can use the event filter function to react on mouse events and then
use the dock manager function `setDockWidgetFocused()` to switch the focus:
```c++
bool CMainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress)
{
QVTKOpenGLStereoWidget* vtkWidget = qobject_cast<QVTKOpenGLStereoWidget*>(watched);
auto vDockWidget = vtkWidget->property("DockWidget");
ads::CDockWidget* DockWidget = nullptr;
if (vDockWidget.isValid())
{
DockWidget = qvariant_cast<ads::CDockWidget*>(vDockWidget);
}
if (DockWidget)
{
d->DockManager->setDockWidgetFocused(DockWidget);
}
}
return false;
}
```
## Styling
The Advanced Docking System supports styling via [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet.html). All components like splitters, tabs, buttons, titlebar and

View File

@@ -2,4 +2,5 @@ cmake_minimum_required(VERSION 3.5)
project(QtADSExamples LANGUAGES CXX VERSION ${VERSION_SHORT})
add_subdirectory(simple)
add_subdirectory(sidebar)
add_subdirectory(deleteonclose)
add_subdirectory(deleteonclose)
add_subdirectory(centralwidget)

View File

@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.5)
project(ads_example_centralwidget VERSION ${VERSION_SHORT})
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_executable(CentralWidgetExample WIN32
main.cpp
mainwindow.cpp
mainwindow.ui
)
target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
target_link_libraries(CentralWidgetExample PRIVATE qtadvanceddocking)
target_link_libraries(CentralWidgetExample PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
set_target_properties(CentralWidgetExample PROPERTIES
AUTOMOC ON
AUTORCC ON
AUTOUIC ON
CXX_STANDARD 14
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
VERSION ${VERSION_SHORT}
EXPORT_NAME "Qt Advanced Docking System Central Widget 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"
)

View File

@@ -0,0 +1,50 @@
ADS_OUT_ROOT = $${OUT_PWD}/../..
QT += core gui widgets
TARGET = CentralWidgetExample
DESTDIR = $${ADS_OUT_ROOT}/lib
TEMPLATE = app
CONFIG += c++14
CONFIG += debug_and_release
adsBuildStatic {
DEFINES += ADS_STATIC
}
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
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

View File

@@ -0,0 +1,10 @@
#include <mainwindow.h>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CMainWindow w;
w.show();
return a.exec();
}

View File

@@ -0,0 +1,83 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QWidgetAction>
#include <QLabel>
#include <QCalendarWidget>
#include <QTreeView>
#include <QFileSystemModel>
#include <QTableWidget>
#include <QHBoxLayout>
#include <QRadioButton>
#include <QPushButton>
#include <QInputDialog>
#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>
#include "DockAreaWidget.h"
#include "DockAreaTitleBar.h"
#include "DockAreaTabBar.h"
#include "FloatingDockContainer.h"
#include "DockComponentsFactory.h"
using namespace ads;
CMainWindow::CMainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::CMainWindow)
{
ui->setupUi(this);
CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true);
CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false);
DockManager = new CDockManager(this);
// Set central widget
QCalendarWidget* calendar = new QCalendarWidget();
CDockWidget* CentralDockWidget = new CDockWidget("CentralWidget");
CentralDockWidget->setWidget(calendar);
auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);
CentralDockArea->setAllowedAreas(DockWidgetArea::OuterDockAreas);
// create other dock widgets
QTreeView* fileTree = new QTreeView();
fileTree->setFrameShape(QFrame::NoFrame);
QFileSystemModel* fileModel = new QFileSystemModel(fileTree);
fileModel->setRootPath(QDir::currentPath());
fileTree->setModel(fileModel);
CDockWidget* DataDockWidget = new CDockWidget("File system");
DataDockWidget->setWidget(fileTree);
DataDockWidget->resize(150, 250);
DataDockWidget->setMinimumSize(100, 250);
auto* fileArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, DataDockWidget, CentralDockArea);
ui->menuView->addAction(DataDockWidget->toggleViewAction());
QTableWidget* table = new QTableWidget();
table->setColumnCount(3);
table->setRowCount(10);
CDockWidget* TableDockWidget = new CDockWidget("Table");
TableDockWidget->setWidget(table);
TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
TableDockWidget->resize(250, 150);
TableDockWidget->setMinimumSize(200,150);
DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, fileArea);
ui->menuView->addAction(TableDockWidget->toggleViewAction());
QTableWidget* propertiesTable = new QTableWidget();
table->setColumnCount(3);
table->setRowCount(10);
CDockWidget* PropertiesDockWidget = new CDockWidget("Properties");
PropertiesDockWidget->setWidget(propertiesTable);
PropertiesDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
PropertiesDockWidget->resize(250, 150);
PropertiesDockWidget->setMinimumSize(200,150);
DockManager->addDockWidget(DockWidgetArea::RightDockWidgetArea, PropertiesDockWidget, CentralDockArea);
ui->menuView->addAction(PropertiesDockWidget->toggleViewAction());
}
CMainWindow::~CMainWindow()
{
delete ui;
}

View File

@@ -0,0 +1,32 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "DockManager.h"
#include "DockAreaWidget.h"
#include "DockWidget.h"
QT_BEGIN_NAMESPACE
namespace Ui { class CMainWindow; }
QT_END_NAMESPACE
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
CMainWindow(QWidget *parent = nullptr);
~CMainWindow();
private:
static const QString kTableTopLayout;
static const QString kTableBottomLayout;
Ui::CMainWindow *ui;
ads::CDockManager* DockManager;
ads::CDockAreaWidget* StatusDockArea;
ads::CDockWidget* TimelineDockWidget;
};
#endif // MAINWINDOW_H

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CMainWindow</class>
<widget class="QMainWindow" name="CMainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1284</width>
<height>757</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>1284</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
</widget>
<addaction name="menuView"/>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,73 @@
import sys
from PyQtAds import QtAds
from PyQt5.QtGui import QCloseEvent
from PyQt5.QtCore import (qDebug, pyqtSlot, QObject, pyqtSignal)
from PyQt5.QtWidgets import (QMainWindow, QAction, QTextEdit, QApplication,
QMenuBar)
class MainWindow(QMainWindow):
dock_manager = None
def closeEvent(self, event: QCloseEvent):
super().closeEvent(event)
if self.dock_manager is not None:
self.dock_manager.deleteLater()
def setDockManager(self, dock_manager: QtAds.CDockManager):
self.dock_manager = dock_manager
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.AllTabsHaveCloseButton, True)
dock_manager = QtAds.CDockManager(w)
w.setDockManager(dock_manager)
count = 0
def on_focused_dock_widget_changed(old: QtAds.CDockWidget, now: QtAds.CDockWidget):
global count
qDebug( "{:d} CDockManager::focusedDockWidgetChanged old: {} now: {} visible: {}".format(
count,
old.objectName() if old else "-",
now.objectName(),
now.isVisible()))
count += 1
now.widget().setFocus()
dock_manager.focusedDockWidgetChanged.connect(on_focused_dock_widget_changed)
action = QAction("New Delete On Close", w)
w.menuBar().addAction(action)
i = 0
def on_action_triggered():
global i
dw = QtAds.CDockWidget("test doc {:d}".format(i))
i += 1
editor = QTextEdit("lorem ipsum...", dw)
dw.setWidget(editor)
dw.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
area = dock_manager.addDockWidgetTab(QtAds.CenterDockWidgetArea, dw)
qDebug("doc dock widget created! {} {}".format(dw, area))
action.triggered.connect(on_action_triggered)
action = QAction("New", w)
w.menuBar().addAction(action)
def on_action2_triggered():
global i
dw = QtAds.CDockWidget("test {:d}".format(i))
i += 1
editor = QTextEdit("lorem ipsum...", dw)
dw.setWidget(editor)
area = dock_manager.addDockWidgetTab(QtAds.CenterDockWidgetArea, dw)
qDebug("dock widget created! {} {}".format(dw, area))
action.triggered.connect(on_action2_triggered)
w.show()
app.exec_()

View File

@@ -5,12 +5,41 @@
#include <QMenuBar>
#include "DockManager.h"
class MainWindow : public QMainWindow
{
private:
ads::CDockManager* m_DockManager = nullptr;
protected:
virtual void closeEvent(QCloseEvent *event) override
{
QMainWindow::closeEvent(event);
if (m_DockManager)
{
m_DockManager->deleteLater();
}
}
public:
void setDockManager(ads::CDockManager* DockManager) {m_DockManager = DockManager;}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
MainWindow w;
ads::CDockManager::setConfigFlag(ads::CDockManager::FocusHighlighting, true);
ads::CDockManager::setConfigFlag(ads::CDockManager::AllTabsHaveCloseButton, true);
auto dockManager = new ads::CDockManager(&w);
w.setDockManager(dockManager);
QObject::connect(dockManager, &ads::CDockManager::focusedDockWidgetChanged, [] (ads::CDockWidget* old, ads::CDockWidget* now) {
static int Count = 0;
qDebug() << Count++ << " CDockManager::focusedDockWidgetChanged old: " << (old ? old->objectName() : "-") << " now: " << now->objectName() << " visible: " << now->isVisible();
now->widget()->setFocus();
});
QAction *action = new QAction("New Delete On Close", &w);
w.menuBar()->addAction(action);

View File

@@ -1,6 +1,7 @@
TEMPLATE = subdirs
SUBDIRS = \
centralwidget \
simple \
sidebar \
deleteonclose

View File

@@ -51,3 +51,13 @@ MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::closeEvent(QCloseEvent *event)
{
QMainWindow::closeEvent(event);
if (m_DockManager)
{
m_DockManager->deleteLater();
}
}

View File

@@ -22,6 +22,9 @@ public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
virtual void closeEvent(QCloseEvent *event) override;
private:
Ui::MainWindow *ui;
ads::CDockManager* m_DockManager;

View File

@@ -3,6 +3,7 @@
#include "ui_MainWindow.h"
#include <QLabel>
#include <QTimer>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
@@ -38,3 +39,4 @@ MainWindow::~MainWindow()
{
delete ui;
}

View File

@@ -2,7 +2,8 @@ import os
import sys
from PyQt5 import uic
from PyQt5.QtCore import Qt
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QCloseEvent
from PyQt5.QtWidgets import QApplication, QLabel
from PyQtAds import QtAds
@@ -20,7 +21,7 @@ class MainWindow(MainWindowUI, MainWindowBase):
# Create the dock manager. Because the parent parameter is a QMainWindow
# the dock manager registers itself as the central widget.
self.dock_manager = QtAds.CDockManager(self)
self.dock_manager1 = QtAds.CDockManager(self)
# Create example content label - this can be any application specific
# widget
@@ -33,13 +34,42 @@ class MainWindow(MainWindowUI, MainWindowBase):
# as the dock widget content
dock_widget = QtAds.CDockWidget("Label 1")
dock_widget.setWidget(l)
l = 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
dock_widget2 = QtAds.CDockWidget("Label 2")
dock_widget2.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
self.menuView.addAction(dock_widget.toggleViewAction())
# Add the dock widget to the top dock widget area
self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, dock_widget)
self.dock_manager1.addDockWidget(QtAds.TopDockWidgetArea, dock_widget)
def remove_first_manager():
self.dock_manager1.removeDockWidget(dock_widget)
del self.dock_manager1
QTimer.singleShot(3000, remove_first_manager)
def add_second_manager():
self.dock_manager2 = QtAds.CDockManager(self)
self.dock_manager2.addDockWidget(QtAds.TopDockWidgetArea, dock_widget)
QTimer.singleShot(5000, add_second_manager)
def closeEvent(self, event: QCloseEvent):
super().closeEvent(event)
if hasattr(self, 'dock_manager1'):
self.dock_manager1.deleteLater()
if hasattr(self, 'dock_manager2'):
self.dock_manager2.deleteLater()
if __name__ == '__main__':

View File

@@ -159,8 +159,20 @@ class build_ext(sipdistutils.build_ext):
return sip_bin
raise SystemExit('Could not find PyQt SIP binary.')
def _sip_sipfiles_dir(self):
sip_dir = super()._sip_sipfiles_dir()
if os.path.exists(sip_dir):
return sip_dir
return os.path.join(sys.prefix, 'sip', 'PyQt5')
def _sip_compile(self, sip_bin, source, sbf):
target_dir = os.path.dirname(__file__) if self.inplace else self.build_lib
pyi = os.path.join(target_dir, "PyQtAds", "QtAds", "ads.pyi")
if not os.path.exists(os.path.dirname(pyi)):
os.makedirs(os.path.dirname(pyi))
cmd = [sip_bin]
if hasattr(self, 'sip_opts'):
cmd += self.sip_opts
@@ -173,11 +185,20 @@ class build_ext(sipdistutils.build_ext):
"-I", self.inc_dir,
"-c", self._sip_output_dir(),
"-b", sbf,
"-y", pyi,
"-w", "-o"]
cmd += shlex.split(self.pyqt_sip_flags) # use same SIP flags as for PyQt5
cmd.append(source)
self.spawn(cmd)
if os.path.exists(pyi):
with open(pyi) as f:
content = f.readlines()
with open(pyi, "w") as f:
for line in content:
if not line.startswith("class ads"):
f.write(line)
def swig_sources (self, sources, extension=None):
if not self.extensions:
@@ -210,10 +231,9 @@ class build_ext(sipdistutils.build_ext):
return super().swig_sources(sources, extension)
def build_extension(self, ext):
# /usr/bin/rcc -name ads ../../Qt-Advanced-Docking-System/src/ads.qrc -o release/qrc_ads.cpp
def build_extension(self, ext):
cppsources = [source for source in ext.sources if source.endswith(".cpp")]
headersources = ['src/DockAreaTitleBar_p.h']
dir_util.mkpath(self.build_temp, dry_run=self.dry_run)
@@ -247,6 +267,30 @@ class build_ext(sipdistutils.build_ext):
if os.path.getsize(out_file) > 0:
ext.sources.append(out_file)
# Run moc on all orphan header files.
for source in headersources:
# *.cpp -> *.moc
moc_file = os.path.basename(source).replace(".h", ".moc")
out_file = os.path.join(self.build_temp, moc_file)
if newer(source, out_file) or self.force:
spawn.spawn(get_moc_args(out_file, source),
dry_run=self.dry_run)
header = source
if os.path.exists(header):
# *.h -> moc_*.cpp
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:
spawn.spawn(get_moc_args(out_file, header),
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()]
@@ -263,6 +307,17 @@ class build_ext(sipdistutils.build_ext):
ext.sources.append(out_file)
sipdistutils.build_ext.build_extension(self, ext)
import inspect
sys.path.append(os.path.join(self.build_lib, 'PyQtAds', 'QtAds'))
import ads
with open(os.path.join(self.build_lib, 'PyQtAds', 'QtAds', '__init__.py'), 'w') as f:
f.write('from .._version import *\n')
f.write('from .ads import ads\n')
for name, member in sorted(inspect.getmembers(ads.ads)):
if not name.startswith('_'):
f.write('{0} = ads.{0}\n'.format(name))
class ProcessResourceCommand(cmd.Command):

View File

@@ -0,0 +1,37 @@
%Import QtWidgets/QtWidgetsmod.sip
%If (Qt_5_0_0 -)
namespace ads
{
class CTitleBarButton : QToolButton
{
%TypeHeaderCode
#include <DockAreaTitleBar_p.h>
%End
protected:
bool event(QEvent *ev);
public:
CTitleBarButton(bool visible = true, QWidget* parent /TransferThis/ = Q_NULLPTR );
virtual void setVisible(bool visible);
};
class CSpacerWidget : QWidget
{
%TypeHeaderCode
#include <DockAreaTitleBar_p.h>
%End
public:
CSpacerWidget(QWidget* Parent /TransferThis/ = 0 );
virtual QSize sizeHint() const;
virtual QSize minimumSizeHint() const;
};
};
%End

View File

@@ -4,7 +4,7 @@
namespace ads
{
class CDockAreaWidget : QFrame
{
@@ -32,6 +32,7 @@ public:
virtual ~CDockAreaWidget();
ads::CDockManager* dockManager() const;
ads::CDockContainerWidget* dockContainer() const;
virtual QSize minimumSizeHint() const;
QRect titleBarGeometry() const;
QRect contentAreaGeometry() const;
int dockWidgetsCount() const;
@@ -50,6 +51,7 @@ public:
void setAllowedAreas(DockWidgetAreas areas);
DockWidgetAreas allowedAreas() const;
void setHideSingleWidgetTitleBar(bool hide);
CDockAreaTitleBar* titleBar() const;
public slots:

View File

@@ -0,0 +1,31 @@
%Import QtWidgets/QtWidgetsmod.sip
%If (Qt_5_0_0 -)
namespace ads
{
/**
* Manages focus styling of dock widgets and handling of focus changes
*/
class CDockFocusController : QObject
{
%TypeHeaderCode
#include <DockFocusController.h>
%End
public:
CDockFocusController(ads::CDockManager* DockManager);
virtual ~CDockFocusController();
void notifyWidgetOrAreaRelocation(QWidget* RelocatedWidget);
void notifyFloatingWidgetDrop(ads::CFloatingDockContainer* FloatingWidget);
public slots:
void setDockWidgetFocused(ads::CDockWidget* focusedNow);
}; // class DockFocusController
};
// namespace ads
%End

View File

@@ -1,7 +1,7 @@
%Import QtWidgets/QtWidgetsmod.sip
%If (Qt_5_0_0 -)
%MappedType QMap<QString, ads::CDockWidget*>
/TypeHint="Dict[QString, CDockWidget*]", TypeHintValue="{}"/
{
@@ -133,6 +133,8 @@ protected:
void removeDockContainer(ads::CDockContainerWidget* DockContainer /TransferBack/);
ads::CDockOverlay* containerOverlay() const;
ads::CDockOverlay* dockAreaOverlay() const;
void notifyWidgetOrAreaRelocation(QWidget* RelocatedWidget);
void notifyFloatingWidgetDrop(ads::CFloatingDockContainer* FloatingWidget);
virtual void showEvent(QShowEvent *event);
@@ -166,6 +168,8 @@ public:
FloatingContainerHasWidgetTitle,
FloatingContainerHasWidgetIcon,
HideSingleCentralWidgetTitleBar,
FocusHighlighting,
EqualSplitOnInsertion,
DefaultDockAreaButtons,
DefaultBaseConfig,
DefaultOpaqueConfig,
@@ -194,8 +198,8 @@ public:
const QList<ads::CDockContainerWidget*> dockContainers() const;
const QList<ads::CFloatingDockContainer*> floatingWidgets() const;
unsigned int zOrderIndex() const;
QByteArray saveState(int version = 1) const;
bool restoreState(const QByteArray &state, int version = 1);
QByteArray saveState(int version = 0) const;
bool restoreState(const QByteArray &state, int version = 0);
void addPerspective(const QString& UniquePrespectiveName);
void removePerspective(const QString& Name);
void removePerspectives(const QStringList& Names);
@@ -211,6 +215,7 @@ public:
public slots:
void openPerspective(const QString& PerspectiveName);
void setDockWidgetFocused(ads::CDockWidget* DockWidget);
signals:
void perspectiveListChanged();
@@ -219,10 +224,11 @@ signals:
void stateRestored();
void openingPerspective(const QString& PerspectiveName);
void perspectiveOpened(const QString& PerspectiveName);
void floatingWidgetCreated(CFloatingDockContainer* FloatingWidget);
void dockAreaCreated(ads::CDockAreaWidget* DockArea);
void dockWidgetAboutToBeRemoved(ads::CDockWidget* DockWidget);
void dockWidgetRemoved(ads::CDockWidget* DockWidget);
void floatingWidgetCreated(ads::CFloatingDockContainer*);
void dockAreaCreated(ads::CDockAreaWidget*);
void dockWidgetAboutToBeRemoved(ads::CDockWidget*);
void dockWidgetRemoved(ads::CDockWidget*);
void focusedDockWidgetChanged(ads::CDockWidget*, ads::CDockWidget*);
};
};

View File

@@ -31,6 +31,7 @@ public:
DockWidgetFloatable,
DockWidgetDeleteOnClose,
CustomCloseHandling,
DockWidgetFocusable,
DefaultDockWidgetFeatures,
AllDockWidgetFeatures,
NoDockWidgetFeatures

View File

@@ -34,6 +34,7 @@ public:
bool isClosable() const;
virtual bool event(QEvent *e);
void setElideMode(Qt::TextElideMode mode);
void updateStyle();
public slots:
virtual void setVisible(bool visible);

View File

@@ -27,6 +27,7 @@ public:
virtual void moveFloating() = 0;
virtual void finishDragging() = 0;
virtual ~IFloatingWidget();
};
@@ -56,6 +57,10 @@ protected:
virtual void closeEvent(QCloseEvent *event);
virtual void hideEvent(QHideEvent *event);
virtual void showEvent(QShowEvent *event);
%If (WS_WIN)
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result);
%End
public:
CFloatingDockContainer(ads::CDockManager* DockManager /TransferThis/);

View File

@@ -13,7 +13,6 @@ class CFloatingDragPreview : QWidget, ads::IFloatingWidget
%End
protected:
virtual void moveEvent(QMoveEvent *event);
virtual void paintEvent(QPaintEvent *e);
CFloatingDragPreview(QWidget* Content /TransferThis/, QWidget* parent /TransferThis/);

View File

@@ -5,11 +5,13 @@
%Include ads_globals.sip
%Include DockWidget.sip
%Include DockAreaTabBar.sip
%Include DockAreaTitleBar_p.sip
%Include DockAreaTitleBar.sip
%Include DockAreaWidget.sip
%Include DockComponentsFactory.sip
%Include DockContainerWidget.sip
%Include DockingStateReader.sip
%Include DockFocusController.sip
%Include DockManager.sip
%Include DockOverlay.sip
%Include DockSplitter.sip

View File

@@ -8,13 +8,6 @@ namespace ads
#include <ads_globals.h>
%End
enum eStateFileVersion
{
InitialVersion,
Version1,
CurrentVersion
};
enum DockWidgetArea
{
NoDockWidgetArea,

View File

@@ -17,6 +17,7 @@ set(ads_SRCS
DockWidget.cpp
DockWidgetTab.cpp
DockingStateReader.cpp
DockFocusController.cpp
ElidingLabel.cpp
FloatingDockContainer.cpp
FloatingDragPreview.cpp
@@ -24,7 +25,7 @@ set(ads_SRCS
DockComponentsFactory.cpp
ads.qrc
)
set(ads_INSTALL_INCLUDE
set(ads_HEADERS
ads_globals.h
DockAreaTabBar.h
DockAreaTitleBar.h
@@ -37,6 +38,7 @@ set(ads_INSTALL_INCLUDE
DockWidget.h
DockWidgetTab.h
DockingStateReader.h
DockFocusController.h
ElidingLabel.h
FloatingDockContainer.h
FloatingDragPreview.h
@@ -45,13 +47,13 @@ set(ads_INSTALL_INCLUDE
)
if (UNIX)
set(ads_SRCS linux/FloatingWidgetTitleBar.cpp ${ads_SRCS})
set(ads_INSTALL_INCLUDE linux/FloatingWidgetTitleBar.h ${ads_INSTALL_INCLUDE})
set(ads_HEADERS linux/FloatingWidgetTitleBar.h ${ads_HEADERS})
endif()
if(BUILD_STATIC)
add_library(qtadvanceddocking STATIC ${ads_SRCS})
add_library(qtadvanceddocking STATIC ${ads_SRCS} ${ads_HEADERS})
target_compile_definitions(qtadvanceddocking PUBLIC ADS_STATIC)
else()
add_library(qtadvanceddocking SHARED ${ads_SRCS})
add_library(qtadvanceddocking SHARED ${ads_SRCS} ${ads_HEADERS})
target_compile_definitions(qtadvanceddocking PRIVATE ADS_SHARED_EXPORT)
endif()
target_link_libraries(qtadvanceddocking PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
@@ -73,7 +75,7 @@ write_basic_package_version_file(
VERSION ${VERSION_SHORT}
COMPATIBILITY SameMajorVersion
)
install(FILES ${ads_INSTALL_INCLUDE}
install(FILES ${ads_HEADERS}
DESTINATION include
COMPONENT headers
)
@@ -102,5 +104,5 @@ install(FILES qtadvanceddockingConfig.cmake "${CMAKE_CURRENT_BINARY_DIR}/qtadvan
target_include_directories(qtadvanceddocking PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)

View File

@@ -138,6 +138,8 @@ CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) :
d->TabsLayout->addStretch(1);
d->TabsContainerWidget->setLayout(d->TabsLayout);
setWidget(d->TabsContainerWidget);
setFocusPolicy(Qt::NoFocus);
}
@@ -456,6 +458,11 @@ bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
updateGeometry();
break;
// Setting the text of a tab will cause a LayoutRequest event
case QEvent::LayoutRequest:
updateGeometry();
break;
default:
break;
}

View File

@@ -103,10 +103,11 @@ struct DockAreaTitleBarPrivate
/**
* Returns true if the given config flag is set
* Convenience function to ease config flag testing
*/
static bool testConfigFlag(CDockManager::eConfigFlag Flag)
{
return CDockManager::configFlags().testFlag(Flag);
return CDockManager::testConfigFlag(Flag);
}
/**
@@ -162,7 +163,7 @@ void DockAreaTitleBarPrivate::createButtons()
// Undock button
UndockButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasUndockButton));
UndockButton->setObjectName("undockButton");
UndockButton->setObjectName("detachGroupButton");
UndockButton->setAutoRaise(true);
internal::setToolTip(UndockButton, QObject::tr("Detach Group"));
internal::setButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon);
@@ -172,7 +173,7 @@ void DockAreaTitleBarPrivate::createButtons()
// Close button
CloseButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasCloseButton));
CloseButton->setObjectName("closeButton");
CloseButton->setObjectName("dockAreaCloseButton");
CloseButton->setAutoRaise(true);
internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon);
if (testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
@@ -212,7 +213,7 @@ IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset,
{
QSize Size = DockArea->size();
this->DragState = DragState;
bool OpaqueUndocking = CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking) ||
bool OpaqueUndocking = CDockManager::testConfigFlag(CDockManager::OpaqueUndocking) ||
(DraggingFloatingWidget != DragState);
CFloatingDockContainer* FloatingDockContainer = nullptr;
IFloatingWidget* FloatingWidget;
@@ -268,6 +269,8 @@ CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) :
d->createTabBar();
d->Layout->addWidget(new CSpacerWidget(this));
d->createButtons();
setFocusPolicy(Qt::NoFocus);
}
@@ -465,6 +468,11 @@ void CDockAreaTitleBar::mousePressEvent(QMouseEvent* ev)
ev->accept();
d->DragStartMousePos = ev->pos();
d->DragState = DraggingMousePressed;
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
d->TabBar->currentTab()->setFocus(Qt::OtherFocusReason);
}
return;
}
Super::mousePressEvent(ev);
@@ -485,6 +493,7 @@ void CDockAreaTitleBar::mouseReleaseEvent(QMouseEvent* ev)
{
d->FloatingWidget->finishDragging();
}
return;
}
Super::mouseReleaseEvent(ev);
@@ -570,12 +579,12 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev)
}
QMenu Menu(this);
auto Action = Menu.addAction(tr("Detach Area"), this, SLOT(onUndockButtonClicked()));
auto Action = Menu.addAction(tr("Detach Group"), this, SLOT(onUndockButtonClicked()));
Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable));
Menu.addSeparator();
Action = Menu.addAction(tr("Close Area"), this, SLOT(onCloseButtonClicked()));
Action = Menu.addAction(tr("Close Group"), this, SLOT(onCloseButtonClicked()));
Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable));
Menu.addAction(tr("Close Other Areas"), d->DockArea, SLOT(closeOtherAreas()));
Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas()));
Menu.exec(ev->globalPos());
}
@@ -594,11 +603,12 @@ int CDockAreaTitleBar::indexOf(QWidget *widget) const
}
//============================================================================
CTitleBarButton::CTitleBarButton(bool visible /*= true*/, QWidget* parent /*= nullptr*/) : tTitleBarButton(parent),
Visible(visible),
HideWhenDisabled(DockAreaTitleBarPrivate::testConfigFlag(CDockManager::DockAreaHideDisabledButtons))
CTitleBarButton::CTitleBarButton(bool visible, QWidget* parent)
: tTitleBarButton(parent),
Visible(visible),
HideWhenDisabled(CDockManager::testConfigFlag(CDockManager::DockAreaHideDisabledButtons))
{
setFocusPolicy(Qt::NoFocus);
}
//============================================================================

View File

@@ -30,8 +30,6 @@
//============================================================================
#include "DockAreaWidget.h"
#include <iostream>
#include <QStackedLayout>
#include <QScrollBar>
#include <QScrollArea>
@@ -136,6 +134,10 @@ public:
m_CurrentWidget = nullptr;
m_CurrentIndex = -1;
}
else if (indexOf(Widget) < m_CurrentIndex)
{
--m_CurrentIndex;
}
m_Widgets.removeOne(Widget);
}
@@ -173,6 +175,7 @@ public:
{
LayoutItem->widget()->setParent(nullptr);
}
delete LayoutItem;
m_ParentLayout->addWidget(next);
if (prev)
@@ -233,6 +236,7 @@ public:
using DockAreaLayout = CDockAreaLayout;
static const DockWidgetAreas DefaultAllowedAreas = AllDockAreas;
/**
@@ -246,8 +250,9 @@ struct DockAreaWidgetPrivate
CDockAreaTitleBar* TitleBar = nullptr;
CDockManager* DockManager = nullptr;
bool UpdateTitleBarButtons = false;
DockWidgetAreas AllowedAreas = AllDockAreas;
DockWidgetAreas AllowedAreas = DefaultAllowedAreas;
QSize MinSizeHint;
CDockAreaWidget::DockAreaFlags Flags{CDockAreaWidget::DefaultFlags};
/**
* Private data constructor
@@ -413,6 +418,7 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
bool Activate)
{
d->ContentsLayout->insertWidget(index, DockWidget);
DockWidget->setDockArea(this);
DockWidget->tabWidget()->setDockAreaWidget(this);
auto TabWidget = DockWidget->tabWidget();
// Inserting the tab will change the current index which in turn will
@@ -428,7 +434,6 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
{
setCurrentIndex(index);
}
DockWidget->setDockArea(this);
// If this dock area is hidden, then we need to make it visible again
// by calling DockWidget->toggleViewInternal(true);
if (!this->isVisible() && d->ContentsLayout->count() > 1 && !dockManager()->isRestoringState())
@@ -436,6 +441,7 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
DockWidget->toggleViewInternal(true);
}
d->updateTitleBarButtonStates();
updateTitleBarVisibility();
}
@@ -443,12 +449,15 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
{
ADS_PRINT("CDockAreaWidget::removeDockWidget");
auto NextOpenDockWidget = nextOpenDockWidget(DockWidget);
auto CurrentDockWidget = currentDockWidget();
auto NextOpenDockWidget = (DockWidget == CurrentDockWidget) ? nextOpenDockWidget(DockWidget) : nullptr;
d->ContentsLayout->removeWidget(DockWidget);
auto TabWidget = DockWidget->tabWidget();
TabWidget->hide();
d->tabBar()->removeTab(TabWidget);
TabWidget->setParent(DockWidget);
DockWidget->setDockArea(nullptr);
CDockContainerWidget* DockContainer = dockContainer();
if (NextOpenDockWidget)
{
@@ -459,8 +468,16 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
ADS_PRINT("Dock Area empty");
DockContainer->removeDockArea(this);
this->deleteLater();
if(DockContainer->dockAreaCount() == 0)
{
if(CFloatingDockContainer* FloatingDockContainer = DockContainer->floatingWidget())
{
FloatingDockContainer->hide();
FloatingDockContainer->deleteLater();
}
}
}
else
else if (DockWidget == CurrentDockWidget)
{
// 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
@@ -731,7 +748,7 @@ void CDockAreaWidget::updateTitleBarVisibility()
return;
}
if (CDockManager::configFlags().testFlag(CDockManager::AlwaysShowTabs))
if (CDockManager::testConfigFlag(CDockManager::AlwaysShowTabs))
{
return;
}
@@ -739,7 +756,8 @@ void CDockAreaWidget::updateTitleBarVisibility()
if (d->TitleBar)
{
bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating()
|| CDockManager::configFlags().testFlag(CDockManager::HideSingleCentralWidgetTitleBar));
|| CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar));
Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1);
d->TitleBar->setVisible(!Hidden);
}
}
@@ -764,6 +782,17 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
auto CurrentDockWidget = currentDockWidget();
QString Name = CurrentDockWidget ? CurrentDockWidget->objectName() : "";
s.writeAttribute("Current", Name);
// To keep the saved XML data small, we only save the allowed areas and the
// dock area flags if the values are different from the default values
if (d->AllowedAreas != DefaultAllowedAreas)
{
s.writeAttribute("AllowedAreas", QString::number(d->AllowedAreas, 16));
}
if (d->Flags != DefaultFlags)
{
s.writeAttribute("Flags", QString::number(d->Flags, 16));
}
ADS_PRINT("CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
<< " Current: " << Name);
for (int i = 0; i < d->ContentsLayout->count(); ++i)
@@ -843,16 +872,49 @@ void CDockAreaWidget::setVisible(bool Visible)
}
}
//============================================================================
void CDockAreaWidget::setAllowedAreas(DockWidgetAreas areas)
{
d->AllowedAreas = areas;
}
//============================================================================
DockWidgetAreas CDockAreaWidget::allowedAreas() const
{
return d->AllowedAreas;
}
//============================================================================
CDockAreaWidget::DockAreaFlags CDockAreaWidget::dockAreaFlags() const
{
return d->Flags;
}
//============================================================================
void CDockAreaWidget::setDockAreaFlags(DockAreaFlags Flags)
{
auto ChangedFlags = d->Flags ^ Flags;
d->Flags = Flags;
if (ChangedFlags.testFlag(HideSingleWidgetTitleBar))
{
updateTitleBarVisibility();
}
}
//============================================================================
void CDockAreaWidget::setDockAreaFlag(eDockAreaFlag Flag, bool On)
{
auto flags = dockAreaFlags();
internal::setFlag(flags, Flag, On);
setDockAreaFlags(flags);
}
//============================================================================
QAbstractButton* CDockAreaWidget::titleBarButton(TitleBarButton which) const
{
@@ -894,11 +956,35 @@ CDockAreaTitleBar* CDockAreaWidget::titleBar() const
}
//============================================================================
bool CDockAreaWidget::isCentralWidgetArea() const
{
if (dockWidgetsCount()!= 1)
{
return false;
}
return dockManager()->centralWidget() == dockWidgets()[0];
}
//============================================================================
QSize CDockAreaWidget::minimumSizeHint() const
{
return d->MinSizeHint.isValid() ? d->MinSizeHint : Super::minimumSizeHint();
}
//============================================================================
void CDockAreaWidget::onDockWidgetFeaturesChanged()
{
if (d->TitleBar)
{
d->updateTitleBarButtonStates();
}
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@@ -65,6 +65,7 @@ private:
friend class CDockWidget;
friend struct DockManagerPrivate;
friend class CDockManager;
void onDockWidgetFeaturesChanged();
private slots:
void onTabCloseRequested(int Index);
@@ -144,6 +145,16 @@ public:
using Super = QFrame;
/**
* Dock area related flags
*/
enum eDockAreaFlag
{
HideSingleWidgetTitleBar = 0x0001,
DefaultFlags = 0x0000
};
Q_DECLARE_FLAGS(DockAreaFlags, eDockAreaFlag)
/**
* Default Constructor
*/
CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent);
@@ -277,6 +288,30 @@ public:
*/
CDockAreaTitleBar* titleBar() const;
/**
* Returns the dock area flags - a combination of flags that configure the
* appearance and features of the dock area.
* \see setDockAreaFlasg()
*/
DockAreaFlags dockAreaFlags() const;
/**
* Sets the dock area flags - a combination of flags that configure the
* appearance and features of the dock area
*/
void setDockAreaFlags(DockAreaFlags Flags);
/**
* Sets the dock area flag Flag on this widget if on is true; otherwise
* clears the flag.
*/
void setDockAreaFlag(eDockAreaFlag Flag, bool On);
/**
* Returns true if the area contains the central widget of it's manager.
*/
bool isCentralWidgetArea() const;
public slots:
/**
* This activates the tab for the given tab index.

View File

@@ -147,12 +147,12 @@ public:
* Adds dock widget to container and returns the dock area that contains
* the inserted dock widget
*/
CDockAreaWidget* dockWidgetIntoContainer(DockWidgetArea area, CDockWidget* Dockwidget);
CDockAreaWidget* addDockWidgetToContainer(DockWidgetArea area, CDockWidget* Dockwidget);
/**
* Adds dock widget to a existing DockWidgetArea
*/
CDockAreaWidget* dockWidgetIntoDockArea(DockWidgetArea area, CDockWidget* Dockwidget,
CDockAreaWidget* addDockWidgetToDockArea(DockWidgetArea area, CDockWidget* Dockwidget,
CDockAreaWidget* TargetDockArea);
/**
@@ -299,11 +299,41 @@ public:
CDockSplitter* newSplitter(Qt::Orientation orientation, QWidget* parent = nullptr)
{
CDockSplitter* s = new CDockSplitter(orientation, parent);
s->setOpaqueResize(CDockManager::configFlags().testFlag(CDockManager::OpaqueSplitterResize));
s->setOpaqueResize(CDockManager::testConfigFlag(CDockManager::OpaqueSplitterResize));
s->setChildrenCollapsible(false);
return s;
}
/**
* Ensures equal distribution of the sizes of a splitter if an dock widget
* is inserted from code
*/
void adjustSplitterSizesOnInsertion(QSplitter* Splitter, qreal LastRatio = 1.0)
{
int AreaSize = (Splitter->orientation() == Qt::Horizontal) ? Splitter->width() : Splitter->height();
auto SplitterSizes = Splitter->sizes();
qreal TotRatio = SplitterSizes.size() - 1.0 + LastRatio;
for(int i = 0; i < SplitterSizes.size() -1; i++)
{
SplitterSizes[i] = AreaSize / TotRatio;
}
SplitterSizes.back() = AreaSize * LastRatio / TotRatio;
Splitter->setSizes(SplitterSizes);
}
/**
* This function forces the dock container widget to update handles of splitters
* based if a central widget exists.
*/
void updateSplitterHandles(QSplitter* splitter);
/**
* If no central widget exists, the widgets resize with the container.
* If a central widget exists, the widgets surrounding the central widget
* do not resize its height or width.
*/
bool widgetResizesWithContainer(QWidget* widget);
// private slots: ------------------------------------------------------------
void onDockAreaViewToggled(bool Visible)
@@ -403,7 +433,8 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
NewSplitter->addWidget(Splitter);
Splitter = NewSplitter;
updateSplitterHandles(NewSplitter);
Splitter = NewSplitter;
delete li;
}
@@ -412,19 +443,21 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
if (FloatingSplitter->count() == 1)
{
insertWidgetIntoSplitter(Splitter, FloatingSplitter->widget(0), InsertParam.append());
}
updateSplitterHandles(Splitter);
}
else if (FloatingSplitter->orientation() == InsertParam.orientation())
{
int InsertIndex = InsertParam.append() ? Splitter->count() : 0;
while (FloatingSplitter->count())
{
Splitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
}
}
updateSplitterHandles(Splitter);
}
}
else
{
insertWidgetIntoSplitter(Splitter, FloatingSplitter, InsertParam.append());
}
}
RootSplitter = Splitter;
addDockAreasToList(NewDockAreas);
@@ -435,7 +468,7 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
if (!Splitter->isVisible())
{
Splitter->show();
}
}
_this->dumpLayout();
}
@@ -497,7 +530,8 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin
QSplitter* Splitter = newSplitter(InsertParam.orientation());
Layout->replaceWidget(TargetArea, Splitter);
Splitter->addWidget(TargetArea);
TargetAreaSplitter = Splitter;
updateSplitterHandles(Splitter);
TargetAreaSplitter = Splitter;
}
int AreaIndex = TargetAreaSplitter->indexOf(TargetArea);
auto Widget = FloatingWidget->dockContainer()->findChild<QWidget*>(QString(), Qt::FindDirectChildrenOnly);
@@ -511,7 +545,8 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin
if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
{
TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), Widget);
}
updateSplitterHandles(TargetAreaSplitter);
}
else
{
AdjustSplitterSizes = (FloatingSplitter->count() == 1);
@@ -519,8 +554,9 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin
while (FloatingSplitter->count())
{
TargetAreaSplitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0));
}
}
updateSplitterHandles(TargetAreaSplitter);
}
}
if (AdjustSplitterSizes)
{
@@ -539,28 +575,32 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin
if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1)
{
NewSplitter->addWidget(Widget);
}
updateSplitterHandles(NewSplitter);
}
else
{
AdjustSplitterSizes = (FloatingSplitter->count() == 1);
while (FloatingSplitter->count())
{
NewSplitter->addWidget(FloatingSplitter->widget(0));
}
}
updateSplitterHandles(NewSplitter);
}
}
// Save the sizes before insertion and restore it later to prevent
// shrinking of existing area
auto Sizes = TargetAreaSplitter->sizes();
insertWidgetIntoSplitter(NewSplitter, TargetArea, !InsertParam.append());
if (AdjustSplitterSizes)
updateSplitterHandles(NewSplitter);
if (AdjustSplitterSizes)
{
int Size = TargetAreaSize / 2;
NewSplitter->setSizes({Size, Size});
}
TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
TargetAreaSplitter->setSizes(Sizes);
}
updateSplitterHandles(TargetAreaSplitter);
}
addDockAreasToList(NewDockAreas);
_this->dumpLayout();
@@ -645,7 +685,8 @@ void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidg
{
int TargetAreaSize = (InsertParam.orientation() == Qt::Horizontal) ? TargetArea->width() : TargetArea->height();
TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), NewDockArea);
int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
updateSplitterHandles(TargetAreaSplitter);
int Size = (TargetAreaSize - TargetAreaSplitter->handleWidth()) / 2;
Sizes[AreaIndex] = Size;
Sizes.insert(AreaIndex, Size);
}
@@ -656,16 +697,58 @@ void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidg
QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
NewSplitter->addWidget(TargetArea);
insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append());
int Size = TargetAreaSize / 2;
updateSplitterHandles(NewSplitter);
int Size = TargetAreaSize / 2;
NewSplitter->setSizes({Size, Size});
TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter);
}
updateSplitterHandles(TargetAreaSplitter);
}
TargetAreaSplitter->setSizes(Sizes);
addDockAreasToList({NewDockArea});
}
//============================================================================
void DockContainerWidgetPrivate::updateSplitterHandles( QSplitter* splitter )
{
if (!DockManager->centralWidget() || !splitter)
{
return;
}
for (int i = 0; i < splitter->count(); ++i)
{
splitter->setStretchFactor(i, widgetResizesWithContainer(splitter->widget(i)) ? 1 : 0);
}
}
//============================================================================
bool DockContainerWidgetPrivate::widgetResizesWithContainer(QWidget* widget)
{
if (!DockManager->centralWidget())
{
return true;
}
auto Area = qobject_cast<CDockAreaWidget*>(widget);
if(Area)
{
return Area->isCentralWidgetArea();
}
auto innerSplitter = qobject_cast<CDockSplitter*>(widget);
if (innerSplitter)
{
return innerSplitter->isResizingWithContainer();
}
return false;
}
//============================================================================
void DockContainerWidgetPrivate::moveToContainer(QWidget* Widget, DockWidgetArea area)
{
@@ -874,6 +957,10 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s,
Splitter->addWidget(ChildNode);
Visible |= ChildNode->isVisibleTo(Splitter);
}
if(!Testing)
{
updateSplitterHandles(Splitter);
}
if (Sizes.count() != WidgetCount)
{
@@ -924,6 +1011,17 @@ bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s,
if (!Testing)
{
DockArea = new CDockAreaWidget(DockManager, _this);
const auto AllowedAreasAttribute = s.attributes().value("AllowedAreas");
if (!AllowedAreasAttribute.isEmpty())
{
DockArea->setAllowedAreas((DockWidgetArea)AllowedAreasAttribute.toInt(nullptr, 16));
}
const auto FlagsAttribute = s.attributes().value("Flags");
if (!FlagsAttribute.isEmpty())
{
DockArea->setDockAreaFlags((CDockAreaWidget::DockAreaFlags)FlagsAttribute.toInt(nullptr, 16));
}
}
while (s.readNextStartElement())
@@ -1013,7 +1111,7 @@ bool DockContainerWidgetPrivate::restoreChildNodes(CDockingStateReader& s,
//============================================================================
CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetArea area,
CDockAreaWidget* DockContainerWidgetPrivate::addDockWidgetToContainer(DockWidgetArea area,
CDockWidget* Dockwidget)
{
CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this);
@@ -1040,7 +1138,8 @@ void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockW
if (Splitter->orientation() == InsertParam.orientation())
{
insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append());
if (Splitter->isHidden())
updateSplitterHandles(Splitter);
if (Splitter->isHidden())
{
Splitter->show();
}
@@ -1053,14 +1152,16 @@ void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockW
QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
NewSplitter->addWidget(Splitter);
NewSplitter->addWidget(NewDockArea);
delete li;
updateSplitterHandles(NewSplitter);
delete li;
}
else
{
NewSplitter->addWidget(NewDockArea);
QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
NewSplitter->addWidget(Splitter);
delete li;
updateSplitterHandles(NewSplitter);
delete li;
}
RootSplitter = NewSplitter;
}
@@ -1126,7 +1227,7 @@ void DockContainerWidgetPrivate::dumpRecursive(int level, QWidget* widget)
//============================================================================
CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoDockArea(DockWidgetArea area,
CDockAreaWidget* DockContainerWidgetPrivate::addDockWidgetToDockArea(DockWidgetArea area,
CDockWidget* Dockwidget, CDockAreaWidget* TargetDockArea)
{
if (CenterDockWidgetArea == area)
@@ -1144,16 +1245,32 @@ CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoDockArea(DockWidgetAr
int index = TargetAreaSplitter ->indexOf(TargetDockArea);
if (TargetAreaSplitter->orientation() == InsertParam.orientation())
{
ADS_PRINT("TargetAreaSplitter->orientation() == InsertParam.orientation()");
ADS_PRINT("TargetAreaSplitter->orientation() == InsertParam.orientation()");
TargetAreaSplitter->insertWidget(index + InsertParam.insertOffset(), NewDockArea);
updateSplitterHandles(TargetAreaSplitter);
// do nothing, if flag is not enabled
if (CDockManager::testConfigFlag(CDockManager::EqualSplitOnInsertion))
{
adjustSplitterSizesOnInsertion(TargetAreaSplitter);
}
}
else
{
ADS_PRINT("TargetAreaSplitter->orientation() != InsertParam.orientation()");
ADS_PRINT("TargetAreaSplitter->orientation() != InsertParam.orientation()");
auto TargetAreaSizes = TargetAreaSplitter->sizes();
QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
NewSplitter->addWidget(TargetDockArea);
insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append());
TargetAreaSplitter->insertWidget(index, NewSplitter);
updateSplitterHandles(NewSplitter);
TargetAreaSplitter->insertWidget(index, NewSplitter);
updateSplitterHandles(TargetAreaSplitter);
if (CDockManager::testConfigFlag(CDockManager::EqualSplitOnInsertion))
{
TargetAreaSplitter->setSizes(TargetAreaSizes);
adjustSplitterSizesOnInsertion(NewSplitter);
}
}
appendDockAreas({NewDockArea});
@@ -1211,11 +1328,11 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW
Dockwidget->setDockManager(d->DockManager);
if (DockAreaWidget)
{
return d->dockWidgetIntoDockArea(area, Dockwidget, DockAreaWidget);
return d->addDockWidgetToDockArea(area, Dockwidget, DockAreaWidget);
}
else
{
return d->dockWidgetIntoContainer(area, Dockwidget);
return d->addDockWidgetToContainer(area, Dockwidget);
}
}
@@ -1288,9 +1405,9 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
internal::hideEmptyParentSplitters(Splitter);
// Remove this area from cached areas
const auto& cache = d->LastAddedAreaCache;
if (auto p = std::find(cache, cache+sizeof(cache)/sizeof(cache[0]), area)) {
d->LastAddedAreaCache[std::distance(cache, p)] = nullptr;
auto p = std::find(std::begin(d->LastAddedAreaCache), std::end(d->LastAddedAreaCache), area);
if (p != std::end(d->LastAddedAreaCache)) {
*p = nullptr;
}
// If splitter has more than 1 widgets, we are finished and can leave
@@ -1339,9 +1456,11 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
}
delete Splitter;
Splitter = nullptr;
emitAndExit:
CDockWidget* TopLevelWidget = topLevelDockWidget();
updateSplitterHandles(Splitter);
CDockWidget* TopLevelWidget = topLevelDockWidget();
// Updated the title bar visibility of the dock widget if there is only
// one single visible dock widget
@@ -1459,6 +1578,13 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
// level widget anymore
CDockWidget::emitTopLevelEventForWidget(SingleDockWidget, false);
}
window()->activateWindow();
if (SingleDroppedDockWidget)
{
d->DockManager->notifyWidgetOrAreaRelocation(SingleDroppedDockWidget);
}
d->DockManager->notifyFloatingWidgetDrop(FloatingWidget);
}
@@ -1478,6 +1604,9 @@ void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea,
// If there was a top level widget before the drop, then it is not top
// level widget anymore
CDockWidget::emitTopLevelEventForWidget(SingleDockWidget, false);
window()->activateWindow();
d->DockManager->notifyWidgetOrAreaRelocation(Widget);
}
@@ -1680,6 +1809,13 @@ QList<CDockWidget*> CDockContainerWidget::dockWidgets() const
}
//============================================================================
void CDockContainerWidget::updateSplitterHandles(QSplitter* splitter)
{
d->updateSplitterHandles(splitter);
}
//============================================================================
CDockWidget::DockWidgetFeatures CDockContainerWidget::features() const
{

View File

@@ -155,6 +155,12 @@ protected:
*/
QList<CDockWidget*> dockWidgets() const;
/**
* This function forces the dock container widget to update handles of splitters
* based on resize modes of dock widgets contained in the container.
*/
void updateSplitterHandles(QSplitter* splitter);
public:
/**
* Default Constructor
@@ -193,7 +199,7 @@ public:
bool isInFrontOf(CDockContainerWidget* Other) const;
/**
* Returns the dock area at teh given global position or 0 if there is no
* Returns the dock area at the given global position or 0 if there is no
* dock area at this position
*/
CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const;
@@ -276,7 +282,7 @@ signals:
* This signal is emitted if a dock area is opened or closed via
* toggleView() function
*/
void dockAreaViewToggled(CDockAreaWidget* DockArea, bool Open);
void dockAreaViewToggled(ads::CDockAreaWidget* DockArea, bool Open);
}; // class DockContainerWidget
} // namespace ads
//-----------------------------------------------------------------------------

387
src/DockFocusController.cpp Normal file
View File

@@ -0,0 +1,387 @@
//============================================================================
/// \file DockFocusController.cpp
/// \author Uwe Kindler
/// \date 05.06.2020
/// \brief Implementation of CDockFocusController class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "DockFocusController.h"
#include <algorithm>
#include <iostream>
#include <QPointer>
#include <QApplication>
#include <QAbstractButton>
#include "DockWidget.h"
#include "DockAreaWidget.h"
#include "DockWidgetTab.h"
#include "DockContainerWidget.h"
#include "FloatingDockContainer.h"
#include "DockManager.h"
#include "DockAreaTitleBar.h"
#ifdef Q_OS_LINUX
#include "linux/FloatingWidgetTitleBar.h"
#endif
namespace ads
{
/**
* Private data class of CDockFocusController class (pimpl)
*/
struct DockFocusControllerPrivate
{
CDockFocusController *_this;
QPointer<CDockWidget> FocusedDockWidget = nullptr;
QPointer<CDockAreaWidget> FocusedArea = nullptr;
CDockWidget* OldFocusedDockWidget = nullptr;
#ifdef Q_OS_LINUX
QPointer<CFloatingDockContainer> FloatingWidget = nullptr;
#endif
CDockManager* DockManager;
bool ForceFocusChangedSignal = false;
/**
* Private data constructor
*/
DockFocusControllerPrivate(CDockFocusController *_public);
/**
* This function updates the focus style of the given dock widget and
* the dock area that it belongs to
*/
void updateDockWidgetFocus(CDockWidget* DockWidget);
};
// struct DockFocusControllerPrivate
//===========================================================================
static void updateDockWidgetFocusStyle(CDockWidget* DockWidget, bool Focused)
{
DockWidget->setProperty("focused", Focused);
DockWidget->tabWidget()->setProperty("focused", Focused);
DockWidget->tabWidget()->updateStyle();
internal::repolishStyle(DockWidget);
}
//===========================================================================
static void updateDockAreaFocusStyle(CDockAreaWidget* DockArea, bool Focused)
{
DockArea->setProperty("focused", Focused);
internal::repolishStyle(DockArea);
internal::repolishStyle(DockArea->titleBar());
}
//===========================================================================
#ifdef Q_OS_LINUX
static void updateFloatingWidgetFocusStyle(CFloatingDockContainer* FloatingWidget, bool Focused)
{
if (FloatingWidget->hasNativeTitleBar())
{
return;
}
auto TitleBar = qobject_cast<CFloatingWidgetTitleBar*>(FloatingWidget->titleBarWidget());
if (!TitleBar)
{
return;
}
TitleBar->setProperty("focused", Focused);
TitleBar->updateStyle();
}
#endif
//============================================================================
DockFocusControllerPrivate::DockFocusControllerPrivate(
CDockFocusController *_public) :
_this(_public)
{
}
//============================================================================
void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget)
{
if (!DockWidget->features().testFlag(CDockWidget::DockWidgetFocusable))
{
return;
}
CDockAreaWidget* NewFocusedDockArea = nullptr;
if (FocusedDockWidget)
{
updateDockWidgetFocusStyle(FocusedDockWidget, false);
}
CDockWidget* old = FocusedDockWidget;
FocusedDockWidget = DockWidget;
updateDockWidgetFocusStyle(FocusedDockWidget, true);
NewFocusedDockArea = FocusedDockWidget->dockAreaWidget();
if (NewFocusedDockArea && (FocusedArea != NewFocusedDockArea))
{
if (FocusedArea)
{
QObject::disconnect(FocusedArea, SIGNAL(viewToggled(bool)), _this, SLOT(onFocusedDockAreaViewToggled(bool)));
updateDockAreaFocusStyle(FocusedArea, false);
}
FocusedArea = NewFocusedDockArea;
updateDockAreaFocusStyle(FocusedArea, true);
QObject::connect(FocusedArea, SIGNAL(viewToggled(bool)), _this, SLOT(onFocusedDockAreaViewToggled(bool)));
}
auto NewFloatingWidget = FocusedDockWidget->dockContainer()->floatingWidget();
if (NewFloatingWidget)
{
NewFloatingWidget->setProperty("FocusedDockWidget", QVariant::fromValue(DockWidget));
}
#ifdef Q_OS_LINUX
// This code is required for styling the floating widget titlebar for linux
// depending on the current focus state
if (FloatingWidget == NewFloatingWidget)
{
return;
}
if (FloatingWidget)
{
updateFloatingWidgetFocusStyle(FloatingWidget, false);
}
FloatingWidget = NewFloatingWidget;
if (FloatingWidget)
{
updateFloatingWidgetFocusStyle(FloatingWidget, true);
}
#endif
if (old == DockWidget && !ForceFocusChangedSignal)
{
return;
}
ForceFocusChangedSignal = false;
if (DockWidget->isVisible())
{
emit DockManager->focusedDockWidgetChanged(old, DockWidget);
}
else
{
OldFocusedDockWidget = old;
QObject::connect(DockWidget, SIGNAL(visibilityChanged(bool)), _this, SLOT(onDockWidgetVisibilityChanged(bool)));
}
}
//============================================================================
void CDockFocusController::onDockWidgetVisibilityChanged(bool Visible)
{
auto Sender = sender();
auto DockWidget = qobject_cast<ads::CDockWidget*>(Sender);
disconnect(Sender, SIGNAL(visibilityChanged(bool)), this, SLOT(onDockWidgetVisibilityChanged(bool)));
if (DockWidget && Visible)
{
emit d->DockManager->focusedDockWidgetChanged(d->OldFocusedDockWidget, DockWidget);
}
}
//============================================================================
CDockFocusController::CDockFocusController(CDockManager* DockManager) :
Super(DockManager),
d(new DockFocusControllerPrivate(this))
{
d->DockManager = DockManager;
connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)),
this, SLOT(onApplicationFocusChanged(QWidget*, QWidget*)));
connect(d->DockManager, SIGNAL(stateRestored()), SLOT(onStateRestored()));
}
//============================================================================
CDockFocusController::~CDockFocusController()
{
delete d;
}
//===========================================================================
void CDockFocusController::onApplicationFocusChanged(QWidget* focusedOld, QWidget* focusedNow)
{
if (d->DockManager->isRestoringState())
{
return;
}
ADS_PRINT("CDockFocusController::onApplicationFocusChanged "
<< " old: " << focusedOld << " new: " << focusedNow);
if (!focusedNow)
{
return;
}
// If the close button in another tab steals the focus from the current
// active dock widget content, i.e. if the user clicks its close button,
// then we immediately give the focus back to the previous focused widget
// focusedOld
if (CDockManager::testConfigFlag(CDockManager::AllTabsHaveCloseButton))
{
auto OtherDockWidgetTab = internal::findParent<CDockWidgetTab*>(focusedNow);
if (OtherDockWidgetTab && focusedOld)
{
focusedOld->setFocus();
return;
}
}
CDockWidget* DockWidget = nullptr;
auto DockWidgetTab = qobject_cast<CDockWidgetTab*>(focusedNow);
if (DockWidgetTab)
{
DockWidget = DockWidgetTab->dockWidget();
// If the DockWidgetTab "steals" the focus from a widget in the same
// DockWidget, then we immediately give the focus back to the previous
// focused widget focusedOld
if (focusedOld)
{
auto OldFocusedDockWidget = internal::findParent<CDockWidget*>(focusedOld);
if (OldFocusedDockWidget && OldFocusedDockWidget == DockWidget)
{
focusedOld->setFocus();
}
}
}
if (!DockWidget)
{
DockWidget = qobject_cast<CDockWidget*>(focusedNow);
}
if (!DockWidget)
{
DockWidget = internal::findParent<CDockWidget*>(focusedNow);
}
#ifdef Q_OS_LINUX
if (!DockWidget)
{
return;
}
#else
if (!DockWidget || DockWidget->tabWidget()->isHidden())
{
return;
}
#endif
d->updateDockWidgetFocus(DockWidget);
}
//===========================================================================
void CDockFocusController::setDockWidgetFocused(CDockWidget* focusedNow)
{
d->updateDockWidgetFocus(focusedNow);
}
//===========================================================================
void CDockFocusController::onFocusedDockAreaViewToggled(bool Open)
{
if (d->DockManager->isRestoringState())
{
return;
}
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(sender());
if (!DockArea || Open)
{
return;
}
auto Container = DockArea->dockContainer();
auto OpenedDockAreas = Container->openedDockAreas();
if (OpenedDockAreas.isEmpty())
{
return;
}
CDockManager::setWidgetFocus(OpenedDockAreas[0]->currentDockWidget()->tabWidget());
}
//===========================================================================
void CDockFocusController::notifyWidgetOrAreaRelocation(QWidget* DroppedWidget)
{
if (d->DockManager->isRestoringState())
{
return;
}
CDockWidget* DockWidget = qobject_cast<CDockWidget*>(DroppedWidget);
if (!DockWidget)
{
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(DroppedWidget);
if (DockArea)
{
DockWidget = DockArea->currentDockWidget();
}
}
if (!DockWidget)
{
return;
}
d->ForceFocusChangedSignal = true;
CDockManager::setWidgetFocus(DockWidget->tabWidget());
}
//===========================================================================
void CDockFocusController::notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget)
{
if (!FloatingWidget || d->DockManager->isRestoringState())
{
return;
}
auto vDockWidget = FloatingWidget->property("FocusedDockWidget");
if (!vDockWidget.isValid())
{
return;
}
auto DockWidget = vDockWidget.value<CDockWidget*>();
if (DockWidget)
{
d->FocusedDockWidget = nullptr;
DockWidget->dockAreaWidget()->setCurrentDockWidget(DockWidget);
CDockManager::setWidgetFocus(DockWidget->tabWidget());
}
}
//==========================================================================
void CDockFocusController::onStateRestored()
{
if (d->FocusedDockWidget)
{
updateDockWidgetFocusStyle(d->FocusedDockWidget, false);
}
}
} // namespace ads
//---------------------------------------------------------------------------
// EOF DockFocusController.cpp

90
src/DockFocusController.h Normal file
View File

@@ -0,0 +1,90 @@
#ifndef DockFocusControllerH
#define DockFocusControllerH
//============================================================================
/// \file DockFocusController.h
/// \author Uwe Kindler
/// \date 05.06.2020
/// \brief Declaration of CDockFocusController class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include <QObject>
#include "ads_globals.h"
#include "DockManager.h"
namespace ads
{
struct DockFocusControllerPrivate;
class CDockManager;
class CFloatingDockContainer;
/**
* Manages focus styling of dock widgets and handling of focus changes
*/
class ADS_EXPORT CDockFocusController : public QObject
{
Q_OBJECT
private:
DockFocusControllerPrivate* d; ///< private data (pimpl)
friend struct DockFocusControllerPrivate;
private slots:
void onApplicationFocusChanged(QWidget *old, QWidget *now);
void onFocusedDockAreaViewToggled(bool Open);
void onStateRestored();
void onDockWidgetVisibilityChanged(bool Visible);
public:
using Super = QObject;
/**
* Default Constructor
*/
CDockFocusController(CDockManager* DockManager);
/**
* Virtual Destructor
*/
virtual ~CDockFocusController();
/**
* Helper function to set focus depending on the configuration of the
* FocusStyling flag
*/
template <class QWidgetPtr>
static void setWidgetFocus(QWidgetPtr widget)
{
if (!CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
return;
}
widget->setFocus(Qt::OtherFocusReason);
}
/**
* A container needs to call this function if a widget has been dropped
* into it
*/
void notifyWidgetOrAreaRelocation(QWidget* RelocatedWidget);
/**
* This function is called, if a floating widget has been dropped into
* an new position.
* When this function is called, all dock widgets of the FloatingWidget
* are already inserted into its new position
*/
void notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget);
public slots:
/**
* Request a focus change to the given dock widget
*/
void setDockWidgetFocused(CDockWidget* focusedNow);
}; // class DockFocusController
}
// namespace ads
//-----------------------------------------------------------------------------
#endif // DockFocusControllerH

View File

@@ -53,6 +53,12 @@
#include "DockAreaWidget.h"
#include "IconProvider.h"
#include "DockingStateReader.h"
#include "DockAreaTitleBar.h"
#include "DockFocusController.h"
#ifdef Q_OS_LINUX
#include "linux/FloatingWidgetTitleBar.h"
#endif
/**
@@ -60,7 +66,7 @@
* name. Normally, when resources are built as part of the application, the
* resources are loaded automatically at startup. The Q_INIT_RESOURCE() macro
* is necessary on some platforms for resources stored in a static library.
* Because GCC caues a linker error if we put Q_INIT_RESOURCE into the
* Because GCC causes a linker error if we put Q_INIT_RESOURCE into the
* loadStyleSheet() function, we place it into a function outside of the ads
* namespace
*/
@@ -72,6 +78,16 @@ static void initResource()
namespace ads
{
/**
* Internal file version in case the structure changes internally
*/
enum eStateFileVersion
{
InitialVersion = 0, //!< InitialVersion
Version1 = 1, //!< Version1
CurrentVersion = Version1//!< CurrentVersion
};
static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultNonOpaqueConfig;
/**
@@ -91,6 +107,8 @@ struct DockManagerPrivate
CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted;
bool RestoringState = false;
QVector<CFloatingDockContainer*> UninitializedFloatingWidgets;
CDockFocusController* FocusController = nullptr;
CDockWidget* CentralWidget = nullptr;
/**
* Private data constructor
@@ -164,11 +182,14 @@ void DockManagerPrivate::loadStylesheet()
{
initResource();
QString Result;
QString FileName = ":ads/stylesheets/";
FileName += CDockManager::testConfigFlag(CDockManager::FocusHighlighting)
? "focus_highlighting" : "default";
#ifdef Q_OS_LINUX
QFile StyleSheetFile(":ads/stylesheets/default_linux.css");
#else
QFile StyleSheetFile(":ads/stylesheets/default.css");
FileName += "_linux";
#endif
FileName += ".css";
QFile StyleSheetFile(FileName);
StyleSheetFile.open(QIODevice::ReadOnly);
QTextStream StyleSheetStream(&StyleSheetFile);
Result = StyleSheetStream.readAll();
@@ -239,8 +260,20 @@ bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int versi
{
return false;
}
s.setFileVersion(v);
ADS_PRINT(s.attributes().value("UserVersion"));
// Older files do not support UserVersion but we still want to load them so
// we first test if the attribute exists
if (!s.attributes().value("UserVersion").isEmpty())
{
v = s.attributes().value("UserVersion").toInt(&ok);
if (!ok || v != version)
{
return false;
}
}
bool Result = true;
#ifdef ADS_DEBUG_PRINT
int DockContainers = s.attributes().value("Containers").toInt();
@@ -264,11 +297,11 @@ bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int versi
{
// Delete remaining empty floating widgets
int FloatingWidgetIndex = DockContainerCount - 1;
int DeleteCount = FloatingWidgets.count() - FloatingWidgetIndex;
for (int i = 0; i < DeleteCount; ++i)
for (int i = FloatingWidgetIndex; i < FloatingWidgets.count(); ++i)
{
FloatingWidgets[FloatingWidgetIndex + i]->deleteLater();
_this->removeDockContainer(FloatingWidgets[FloatingWidgetIndex + i]->dockContainer());
auto* floatingWidget = FloatingWidgets[i];
_this->removeDockContainer(floatingWidget->dockContainer());
floatingWidget->deleteLater();
}
}
@@ -335,8 +368,6 @@ void DockManagerPrivate::restoreDockAreasIndices()
}
}
//============================================================================
void DockManagerPrivate::emitTopLevelEvents()
{
@@ -374,6 +405,7 @@ bool DockManagerPrivate::restoreState(const QByteArray& State, int version)
return false;
}
CentralWidget = nullptr;
// Hide updates of floating widgets from use
hideFloatingWidgets();
markDockWidgetsDirty();
@@ -437,6 +469,15 @@ CDockManager::CDockManager(QWidget *parent) :
d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
d->Containers.append(this);
d->loadStylesheet();
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
d->FocusController = new CDockFocusController(this);
}
#ifdef Q_OS_LINUX
window()->installEventFilter(this);
#endif
}
//============================================================================
@@ -450,6 +491,70 @@ CDockManager::~CDockManager()
delete d;
}
//============================================================================
#ifdef Q_OS_LINUX
bool CDockManager::eventFilter(QObject *obj, QEvent *e)
{
// Emulate Qt:Tool behaviour.
// Required because on some WMs Tool windows can't be maximized.
// Window always on top of the MainWindow.
if (e->type() == QEvent::WindowActivate)
{
for (auto _window : floatingWidgets())
{
if (!_window->isVisible() || window()->isMinimized())
{
continue;
}
// setWindowFlags(Qt::WindowStaysOnTopHint) will hide the window and thus requires a show call.
// This then leads to flickering and a nasty endless loop (also buggy behaviour on Ubuntu).
// So we just do it ourself.
internal::xcb_update_prop(true, _window->window()->winId(),
"_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");
}
}
else if (e->type() == QEvent::WindowDeactivate)
{
for (auto _window : floatingWidgets())
{
if (!_window->isVisible() || window()->isMinimized())
{
continue;
}
internal::xcb_update_prop(false, _window->window()->winId(),
"_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");
_window->raise();
}
}
// Sync minimize with MainWindow
if (e->type() == QEvent::WindowStateChange)
{
for (auto _window : floatingWidgets())
{
if (! _window->isVisible())
{
continue;
}
if (window()->isMinimized())
{
_window->showMinimized();
}
else
{
_window->setWindowState(_window->windowState() & (~Qt::WindowMinimized));
}
}
if (!window()->isMinimized())
{
QApplication::setActiveWindow(window());
}
}
return Super::eventFilter(obj, e);
}
#endif
//============================================================================
void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget)
@@ -528,7 +633,8 @@ QByteArray CDockManager::saveState(int version) const
s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled));
s.writeStartDocument();
s.writeStartElement("QtAdvancedDockingSystem");
s.writeAttribute("Version", QString::number(version));
s.writeAttribute("Version", QString::number(CurrentVersion));
s.writeAttribute("UserVersion", QString::number(version));
s.writeAttribute("Containers", QString::number(d->Containers.count()));
for (auto Container : d->Containers)
{
@@ -570,12 +676,11 @@ bool CDockManager::restoreState(const QByteArray &state, int version)
emit restoringState();
bool Result = d->restoreState(state, version);
d->RestoringState = false;
emit stateRestored();
if (!IsHidden)
{
show();
}
emit stateRestored();
return Result;
}
@@ -671,6 +776,7 @@ void CDockManager::removeDockWidget(CDockWidget* Dockwidget)
emit dockWidgetAboutToBeRemoved(Dockwidget);
d->DockWidgetsMap.remove(Dockwidget->objectName());
CDockContainerWidget::removeDockWidget(Dockwidget);
Dockwidget->setDockManager(nullptr);
emit dockWidgetRemoved(Dockwidget);
}
@@ -778,6 +884,40 @@ void CDockManager::loadPerspectives(QSettings& Settings)
Settings.endArray();
}
//============================================================================
CDockWidget* CDockManager::centralWidget() const
{
return d->CentralWidget;
}
//============================================================================
CDockAreaWidget* CDockManager::setCentralWidget(CDockWidget* widget)
{
if (!widget)
{
d->CentralWidget = nullptr;
return nullptr;
}
// Setting a new central widget is now allowed if there is alread a central
// widget
if (d->CentralWidget)
{
return nullptr;
}
widget->setFeature(CDockWidget::DockWidgetClosable, false);
widget->setFeature(CDockWidget::DockWidgetMovable, false);
widget->setFeature(CDockWidget::DockWidgetFloatable, false);
d->CentralWidget = widget;
CDockAreaWidget* CentralArea = addDockWidget(CenterDockWidgetArea, widget);
CentralArea->setDockAreaFlag(CDockAreaWidget::eDockAreaFlag::HideSingleWidgetTitleBar, true);
return CentralArea;
}
//============================================================================
QAction* CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
const QString& Group, const QIcon& GroupIcon)
@@ -872,6 +1012,36 @@ CIconProvider& CDockManager::iconProvider()
}
//===========================================================================
void CDockManager::notifyWidgetOrAreaRelocation(QWidget* DroppedWidget)
{
if (d->FocusController)
{
d->FocusController->notifyWidgetOrAreaRelocation(DroppedWidget);
}
}
//===========================================================================
void CDockManager::notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget)
{
if (d->FocusController)
{
d->FocusController->notifyFloatingWidgetDrop(FloatingWidget);
}
}
//===========================================================================
void CDockManager::setDockWidgetFocused(CDockWidget* DockWidget)
{
if (d->FocusController)
{
d->FocusController->setDockWidgetFocused(DockWidget);
}
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@@ -84,6 +84,7 @@ private:
friend struct FloatingDragPreviewPrivate;
friend class CDockAreaTitleBar;
protected:
/**
* Registers the given floating widget in the internal list of
@@ -118,6 +119,22 @@ protected:
*/
CDockOverlay* dockAreaOverlay() const;
/**
* A container needs to call this function if a widget has been dropped
* into it
*/
void notifyWidgetOrAreaRelocation(QWidget* RelocatedWidget);
/**
* This function is called, if a floating widget has been dropped into
* an new position.
* When this function is called, all dock widgets of the FloatingWidget
* are already inserted into its new position
*/
void notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget);
/**
* Show the floating widgets that has been created floating
*/
@@ -162,6 +179,15 @@ public:
HideSingleCentralWidgetTitleBar = 0x100000, //!< If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden
//!< this only makes sense for non draggable and non floatable widgets and enables the creation of some kind of "central" widget
FocusHighlighting = 0x200000, //!< enables styling of focused dock widget tabs or floating widget titlebar
EqualSplitOnInsertion = 0x400000, ///!< if enabled, the space is equally distributed to all widgets in a splitter
FloatingContainerForceNativeTitleBar = 0x800000, //!< Linux only ! Forces all FloatingContainer to use the native title bar. This might break docking for FloatinContainer on some Window Managers (like Kwin/KDE).
//!< If neither this nor FloatingContainerForceCustomTitleBar is set (the default) native titlebars are used except on known bad systems.
//! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0".
FloatingContainerForceQWidgetTitleBar = 0x1000000,//!< Linux only ! Forces all FloatingContainer to use a QWidget based title bar.
//!< If neither this nor FloatingContainerForceNativeTitleBar is set (the default) native titlebars are used except on known bad systems.
//! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0".
DefaultDockAreaButtons = DockAreaHasCloseButton
| DockAreaHasUndockButton
@@ -308,8 +334,12 @@ public:
* 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.
* The version number is stored as part of the data.
* To restore the saved state, pass the return value and version number
* to restoreState().
* \see restoreState()
*/
QByteArray saveState(int version = Version1) const;
QByteArray saveState(int version = 0) const;
/**
* Restores the state of this dockmanagers dockwidgets.
@@ -317,8 +347,9 @@ public:
* not match, the dockmanager's state is left unchanged, and this function
* returns false; otherwise, the state is restored, and this function
* returns true.
* \see saveState()
*/
bool restoreState(const QByteArray &state, int version = Version1);
bool restoreState(const QByteArray &state, int version = 0);
/**
* Saves the current perspective to the internal list of perspectives.
@@ -355,7 +386,28 @@ public:
*/
void loadPerspectives(QSettings& Settings);
/**
/**
* This function returns managers central widget or nullptr if no central widget is set.
*/
CDockWidget* centralWidget() const;
/**
* Adds dockwidget widget into the central area and marks it as central widget.
* If central widget is set, it will be the only dock widget
* that will resize with the dock container. A central widget if not
* movable, floatable or closable and the titlebar of the central
* dock area is not visible.
* If the given widget could be set as central widget, the function returns
* the created cok area. If the widget could not be set, because there
* is already a central widget, this function returns a nullptr.
* To clear the central widget, pass a nullptr to the function.
* \retval != 0 The dock area that contains the central widget
* \retval nullptr Indicates that the given widget can not be set as central
* widget because there is already a central widget.
*/
CDockAreaWidget* setCentralWidget(CDockWidget* widget);
/**
* 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
@@ -405,12 +457,38 @@ public:
*/
static int startDragDistance();
/**
* Helper function to set focus depending on the configuration of the
* FocusStyling flag
*/
template <class QWidgetPtr>
static void setWidgetFocus(QWidgetPtr widget)
{
if (!CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
return;
}
widget->setFocus(Qt::OtherFocusReason);
}
#ifdef Q_OS_LINUX
bool eventFilter(QObject *obj, QEvent *e) override;
#endif
public slots:
/**
* Opens the perspective with the given name.
*/
void openPerspective(const QString& PerspectiveName);
/**
* Request a focus change to the given dock widget.
* This function only has an effect, if the flag CDockManager::FocusStyling
* is enabled
*/
void setDockWidgetFocused(CDockWidget* DockWidget);
signals:
/**
* This signal is emitted if the list of perspectives changed
@@ -457,20 +535,20 @@ signals:
* An application can use this signal to e.g. subscribe to events of
* the newly created window.
*/
void floatingWidgetCreated(CFloatingDockContainer* FloatingWidget);
void floatingWidgetCreated(ads::CFloatingDockContainer* FloatingWidget);
/**
* 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);
void dockAreaCreated(ads::CDockAreaWidget* DockArea);
/**
* This signal is emitted just before the given dock widget is removed
* from the
* from the dock manager
*/
void dockWidgetAboutToBeRemoved(CDockWidget* DockWidget);
void dockWidgetAboutToBeRemoved(ads::CDockWidget* DockWidget);
/**
* This signal is emitted if a dock widget has been removed with the remove
@@ -478,7 +556,14 @@ signals:
* 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);
void dockWidgetRemoved(ads::CDockWidget* DockWidget);
/**
* This signal is emitted if the focused dock widget changed.
* Both old and now can be nullptr.
* The focused dock widget is the one that is highlighted in the GUI
*/
void focusedDockWidgetChanged(ads::CDockWidget* old, ads::CDockWidget* now);
}; // class DockManager
} // namespace ads
//-----------------------------------------------------------------------------

View File

@@ -102,6 +102,20 @@ QWidget* CDockSplitter::lastWidget() const
return (count() > 0) ? widget(count() - 1) : nullptr;
}
//============================================================================
bool CDockSplitter::isResizingWithContainer() const
{
for (auto area : findChildren<CDockAreaWidget*>())
{
if(area->isCentralWidgetArea())
{
return true;
}
}
return false;
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@@ -71,6 +71,11 @@ public:
* Returns last widget of nullptr is splitter is empty
*/
QWidget* lastWidget() const;
/**
* Returns true if the splitter contains central widget of dock manager.
*/
bool isResizingWithContainer() const;
}; // class CDockSplitter
} // namespace ads

View File

@@ -134,6 +134,7 @@ void DockWidgetPrivate::showDockWidget()
{
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
FloatingWidget->resize(_this->size());
TabWidget->show();
FloatingWidget->show();
}
else
@@ -235,6 +236,11 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this,
SLOT(toggleView(bool)));
setToolbarFloatingStyle(false);
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
setFocusPolicy(Qt::ClickFocus);
}
}
//============================================================================
@@ -334,6 +340,8 @@ void CDockWidget::setFeatures(DockWidgetFeatures features)
d->Features = features;
emit featuresChanged(d->Features);
d->TabWidget->onDockWidgetFeaturesChanged();
if(CDockAreaWidget* DockArea = dockAreaWidget())
DockArea->onDockWidgetFeaturesChanged();
}
@@ -455,6 +463,13 @@ void CDockWidget::setMinimumSizeHintMode(eMinimumSizeHintMode Mode)
}
//============================================================================
bool CDockWidget::isCentralWidget() const
{
return dockManager()->centralWidget() == this;
}
//============================================================================
void CDockWidget::toggleView(bool Open)
{
@@ -534,6 +549,7 @@ void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
{
d->DockArea = DockArea;
d->ToggleViewAction->setChecked(DockArea != nullptr && !this->isClosed());
setParent(DockArea);
}

View File

@@ -149,10 +149,11 @@ public:
{
DockWidgetClosable = 0x01,///< dock widget has a close button
DockWidgetMovable = 0x02,///< dock widget is movable and can be moved to a new position in the current dock container
DockWidgetFloatable = 0x04,
DockWidgetFloatable = 0x04,///< dock widget can be dragged into a floating window
DockWidgetDeleteOnClose = 0x08, ///< deletes the dock widget when it is closed
CustomCloseHandling = 0x10,
DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable,
CustomCloseHandling = 0x10, ///< clicking the close button will not close the dock widget but emits the closeRequested() signal instead
DockWidgetFocusable = 0x20, ///< if this is enabled, a dock widget can get focus highlighting
DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable | DockWidgetFocusable,
AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose | CustomCloseHandling,
NoDockWidgetFeatures = 0x00
};
@@ -196,7 +197,7 @@ public:
* To ensure, that a dock widget does not block resizing, the dock widget
* reimplements minimumSizeHint() function to return a very small minimum
* size hint. If you would like to adhere the minimumSizeHint() from the
* content widget, the set the minimumSizeHintMode() to
* content widget, then set the minimumSizeHintMode() to
* MinimumSizeHintFromContent.
*/
enum eMinimumSizeHintMode
@@ -359,6 +360,11 @@ public:
*/
void setMinimumSizeHintMode(eMinimumSizeHintMode Mode);
/**
* Returns true if the dock widget is set as central widget of it's dock manager
*/
bool isCentralWidget() const;
/**
* Sets the dock widget icon that is shown in tabs and in toggle view
* actions
@@ -576,7 +582,7 @@ signals:
* This signal is emitted when the features property changes.
* The features parameter gives the new value of the property.
*/
void featuresChanged(DockWidgetFeatures features);
void featuresChanged(ads::CDockWidget::DockWidgetFeatures features);
}; // class DockWidget
}
// namespace ads

View File

@@ -114,7 +114,7 @@ struct DockWidgetTabPrivate
*/
bool testConfigFlag(CDockManager::eConfigFlag Flag) const
{
return CDockManager::configFlags().testFlag(Flag);
return CDockManager::testConfigFlag(Flag);
}
/**
@@ -134,6 +134,18 @@ struct DockWidgetTabPrivate
}
}
/**
* Update the close button visibility from current feature/config
*/
void updateCloseButtonVisibility(bool active)
{
bool DockWidgetClosable = DockWidget->features().testFlag(CDockWidget::DockWidgetClosable);
bool ActiveTabHasCloseButton = testConfigFlag(CDockManager::ActiveTabHasCloseButton);
bool AllTabsHaveCloseButton = testConfigFlag(CDockManager::AllTabsHaveCloseButton);
bool TabHasCloseButton = (ActiveTabHasCloseButton && active) | AllTabsHaveCloseButton;
CloseButton->setVisible(DockWidgetClosable && TabHasCloseButton);
}
template <typename T>
IFloatingWidget* createFloatingWidget(T* Widget, bool OpaqueUndocking)
{
@@ -160,6 +172,7 @@ struct DockWidgetTabPrivate
GlobalDragStartMousePosition = GlobalPos;
DragStartMousePosition = _this->mapFromGlobal(GlobalPos);
}
};
// struct DockWidgetTabPrivate
@@ -242,7 +255,7 @@ bool DockWidgetTabPrivate::startFloating(eDragState DraggingState)
ADS_PRINT("startFloating");
DragState = DraggingState;
IFloatingWidget* FloatingWidget = nullptr;
bool OpaqueUndocking = CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking) ||
bool OpaqueUndocking = CDockManager::testConfigFlag(CDockManager::OpaqueUndocking) ||
(DraggingFloatingWidget != DraggingState);
// If section widget has multiple tabs, we take only one tab
@@ -284,6 +297,10 @@ CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) :
setAttribute(Qt::WA_NoMousePropagation, true);
d->DockWidget = DockWidget;
d->createLayout();
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
setFocusPolicy(Qt::ClickFocus);
}
}
//============================================================================
@@ -394,7 +411,7 @@ void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev)
{
// If we undock, we need to restore the initial position of this
// tab because it looks strange if it remains on its dragged position
if (d->isDraggingState(DraggingTab) && !CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking))
if (d->isDraggingState(DraggingTab) && !CDockManager::testConfigFlag(CDockManager::OpaqueUndocking))
{
parentWidget()->layout()->update();
}
@@ -456,21 +473,34 @@ bool CDockWidgetTab::isActiveTab() const
//============================================================================
void CDockWidgetTab::setActiveTab(bool active)
{
bool DockWidgetClosable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetClosable);
bool ActiveTabHasCloseButton = d->testConfigFlag(CDockManager::ActiveTabHasCloseButton);
bool AllTabsHaveCloseButton = d->testConfigFlag(CDockManager::AllTabsHaveCloseButton);
bool TabHasCloseButton = (ActiveTabHasCloseButton && active) | AllTabsHaveCloseButton;
d->CloseButton->setVisible(DockWidgetClosable && TabHasCloseButton);
if (d->IsActiveTab == active)
d->updateCloseButtonVisibility(active);
// Focus related stuff
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting) && !d->DockWidget->dockManager()->isRestoringState())
{
bool UpdateFocusStyle = false;
if (active && !hasFocus())
{
setFocus(Qt::OtherFocusReason);
UpdateFocusStyle = true;
}
if (d->IsActiveTab == active)
{
if (UpdateFocusStyle)
{
updateStyle();
}
return;
}
}
else if (d->IsActiveTab == active)
{
return;
}
d->IsActiveTab = active;
style()->unpolish(this);
style()->polish(this);
d->TitleLabel->style()->unpolish(d->TitleLabel);
d->TitleLabel->style()->polish(d->TitleLabel);
updateStyle();
update();
updateGeometry();
@@ -631,6 +661,7 @@ void CDockWidgetTab::onDockWidgetFeaturesChanged()
SizePolicy.setRetainSizeWhenHidden(Features.testFlag(CDockWidget::DockWidgetClosable)
&& d->testConfigFlag(CDockManager::RetainTabSizeWhenCloseButtonHidden));
d->CloseButton->setSizePolicy(SizePolicy);
d->updateCloseButtonVisibility(isActiveTab());
}
@@ -641,6 +672,13 @@ void CDockWidgetTab::setElideMode(Qt::TextElideMode mode)
}
//============================================================================
void CDockWidgetTab::updateStyle()
{
internal::repolishStyle(this, internal::RepolishDirectChildren);
}
} // namespace ads

View File

@@ -39,6 +39,7 @@ namespace ads
class CDockWidget;
class CDockAreaWidget;
struct DockWidgetTabPrivate;
class CDockManager;
/**
* A dock widget tab that shows a title and an icon.
@@ -54,6 +55,7 @@ private:
DockWidgetTabPrivate* d; ///< private data (pimpl)
friend struct DockWidgetTabPrivate;
friend class CDockWidget;
friend class CDockManager;
void onDockWidgetFeaturesChanged();
private slots:
@@ -152,6 +154,10 @@ public:
*/
void setElideMode(Qt::TextElideMode mode);
/**
* Update stylesheet style if a property changes
*/
void updateStyle();
public slots:
virtual void setVisible(bool visible) override;

View File

@@ -376,6 +376,7 @@ struct FloatingDockContainerPrivate
#ifdef Q_OS_LINUX
QWidget* MouseEventHandler = nullptr;
CFloatingWidgetTitleBar* TitleBar = nullptr;
bool IsResizing = false;
#endif
/**
@@ -391,7 +392,7 @@ struct FloatingDockContainerPrivate
*/
static bool testConfigFlag(CDockManager::eConfigFlag Flag)
{
return CDockManager::configFlags().testFlag(Flag);
return CDockManager::testConfigFlag(Flag);
}
/**
@@ -410,10 +411,12 @@ struct FloatingDockContainerPrivate
void setWindowTitle(const QString &Text)
{
#ifdef Q_OS_LINUX
TitleBar->setTitle(Text);
#else
_this->setWindowTitle(Text);
if (TitleBar)
{
TitleBar->setTitle(Text);
}
#endif
_this->setWindowTitle(Text);
}
/**
@@ -604,13 +607,52 @@ CFloatingDockContainer::CFloatingDockContainer(CDockManager *DockManager) :
SLOT(onDockAreasAddedOrRemoved()));
#ifdef Q_OS_LINUX
d->TitleBar = new CFloatingWidgetTitleBar(this);
setWindowFlags(windowFlags() | Qt::Tool);
QDockWidget::setWidget(d->DockContainer);
QDockWidget::setFloating(true);
QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
setTitleBarWidget(d->TitleBar);
connect(d->TitleBar, SIGNAL(closeRequested()), SLOT(close()));
QDockWidget::setWidget(d->DockContainer);
QDockWidget::setFloating(true);
QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
bool native_window = true;
// FloatingContainerForce*TitleBar is overwritten by the "ADS_UseNativeTitle" environment variable if set.
auto env = qgetenv("ADS_UseNativeTitle").toUpper();
if (env == "1")
{
native_window = true;
}
else if (env == "0")
{
native_window = false;
}
else if (DockManager->testConfigFlag(CDockManager::FloatingContainerForceNativeTitleBar))
{
native_window = true;
}
else if (DockManager->testConfigFlag(CDockManager::FloatingContainerForceQWidgetTitleBar))
{
native_window = false;
}
else
{
// KDE doesn't seem to fire MoveEvents while moving windows, so for now no native titlebar for everything using KWin.
QString window_manager = internal::windowManager().toUpper().split(" ")[0];
native_window = window_manager != "KWIN";
}
if (native_window)
{
setTitleBarWidget(new QWidget());
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
}
else
{
d->TitleBar = new CFloatingWidgetTitleBar(this);
setTitleBarWidget(d->TitleBar);
setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint);
d->TitleBar->enableCloseButton(isClosable());
connect(d->TitleBar, SIGNAL(closeRequested()), SLOT(close()));
connect(d->TitleBar, &CFloatingWidgetTitleBar::maximizeRequested,
this, &CFloatingDockContainer::onMaximizeRequest);
}
#else
setWindowFlags(
Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
@@ -629,14 +671,14 @@ CFloatingDockContainer::CFloatingDockContainer(CDockAreaWidget *DockArea) :
CFloatingDockContainer(DockArea->dockManager())
{
d->DockContainer->addDockArea(DockArea);
#ifdef Q_OS_LINUX
d->TitleBar->enableCloseButton(isClosable());
#endif
auto TopLevelDockWidget = topLevelDockWidget();
if (TopLevelDockWidget)
{
TopLevelDockWidget->emitTopLevelChanged(true);
}
d->DockManager->notifyWidgetOrAreaRelocation(DockArea);
}
//============================================================================
@@ -644,14 +686,13 @@ CFloatingDockContainer::CFloatingDockContainer(CDockWidget *DockWidget) :
CFloatingDockContainer(DockWidget->dockManager())
{
d->DockContainer->addDockWidget(CenterDockWidgetArea, DockWidget);
#ifdef Q_OS_LINUX
d->TitleBar->enableCloseButton(isClosable());
#endif
auto TopLevelDockWidget = topLevelDockWidget();
if (TopLevelDockWidget)
{
TopLevelDockWidget->emitTopLevelChanged(true);
}
d->DockManager->notifyWidgetOrAreaRelocation(DockWidget);
}
//============================================================================
@@ -674,12 +715,19 @@ CDockContainerWidget* CFloatingDockContainer::dockContainer() const
//============================================================================
void CFloatingDockContainer::changeEvent(QEvent *event)
{
QWidget::changeEvent(event);
Super::changeEvent(event);
if ((event->type() == QEvent::ActivationChange) && isActiveWindow())
{
ADS_PRINT("FloatingWidget::changeEvent QEvent::ActivationChange ");
d->zOrderIndex = ++zOrderCounter;
return;
#ifdef Q_OS_LINUX
if (d->DraggingState == DraggingFloatingWidget)
{
d->titleMouseReleaseEvent();
d->DraggingState = DraggingInactive;
}
#endif
}
}
@@ -800,10 +848,17 @@ void CFloatingDockContainer::hideEvent(QHideEvent *event)
d->Hiding = false;
}
//============================================================================
void CFloatingDockContainer::showEvent(QShowEvent *event)
{
Super::showEvent(event);
#ifdef Q_OS_LINUX
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
{
this->window()->activateWindow();
}
#endif
}
@@ -811,25 +866,35 @@ void CFloatingDockContainer::showEvent(QShowEvent *event)
void CFloatingDockContainer::startFloating(const QPoint &DragStartMousePos,
const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)
{
#ifndef Q_OS_LINUX
Q_UNUSED(MouseEventHandler)
#endif
resize(Size);
d->setState(DragState);
d->DragStartMousePosition = DragStartMousePos;
#ifdef Q_OS_LINUX
if (!isMaximized())
{
resize(Size);
d->DragStartMousePosition = DragStartMousePos;
}
d->setState(DragState);
if (DraggingFloatingWidget == DragState)
{
setAttribute(Qt::WA_X11NetWmWindowTypeDock, true);
d->MouseEventHandler = MouseEventHandler;
if (d->MouseEventHandler)
{
d->MouseEventHandler->grabMouse();
}
}
#endif
if (!isMaximized())
{
moveFloating();
}
show();
#else
Q_UNUSED(MouseEventHandler)
resize(Size);
d->DragStartMousePosition = DragStartMousePos;
d->setState(DragState);
moveFloating();
show();
#endif
}
//============================================================================
@@ -839,7 +904,6 @@ void CFloatingDockContainer::moveFloating()
const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition
- QPoint(BorderSize, 0);
move(moveToPos);
switch (d->DraggingState)
{
case DraggingMousePressed:
@@ -938,11 +1002,17 @@ bool CFloatingDockContainer::restoreState(CDockingStateReader &Stream,
{
return false;
}
onDockAreasAddedOrRemoved();
#ifdef Q_OS_LINUX
if(d->TitleBar)
{
d->TitleBar->setMaximizedIcon(windowState() == Qt::WindowMaximized);
}
#endif
return true;
}
//============================================================================
bool CFloatingDockContainer::hasTopLevelDockWidget() const
{
@@ -966,18 +1036,210 @@ void CFloatingDockContainer::finishDragging()
{
ADS_PRINT("CFloatingDockContainer::finishDragging");
#ifdef Q_OS_LINUX
setAttribute(Qt::WA_X11NetWmWindowTypeDock, false);
setWindowOpacity(1);
activateWindow();
if (d->MouseEventHandler)
{
d->MouseEventHandler->releaseMouse();
d->MouseEventHandler = nullptr;
}
setWindowOpacity(1);
activateWindow();
if (d->MouseEventHandler)
{
d->MouseEventHandler->releaseMouse();
d->MouseEventHandler = nullptr;
}
#endif
d->titleMouseReleaseEvent();
d->titleMouseReleaseEvent();
}
#ifdef Q_OS_MACOS
//============================================================================
bool CFloatingDockContainer::event(QEvent *e)
{
switch (d->DraggingState)
{
case DraggingInactive:
{
// Normally we would check here, if the left mouse button is pressed.
// But from QT version 5.12.2 on the mouse events from
// QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
// The event always returns Qt::RightButton even if the left button
// is clicked.
// It is really great to work around the whole NonClientMouseArea
// bugs
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
if (e->type() == QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
#else
if (e->type() == QEvent::NonClientAreaMouseButtonPress && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
#endif
{
ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
d->DragStartPos = pos();
d->setState(DraggingMousePressed);
}
}
break;
case DraggingMousePressed:
switch (e->type())
{
case QEvent::NonClientAreaMouseButtonDblClick:
ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick");
d->setState(DraggingInactive);
break;
case QEvent::Resize:
// If the first event after the mouse press is a resize event, then
// the user resizes the window instead of dragging it around.
// But there is one exception. If the window is maximized,
// then dragging the window via title bar will cause the widget to
// leave the maximized state. This in turn will trigger a resize event.
// To know, if the resize event was triggered by user via moving a
// corner of the window frame or if it was caused by a windows state
// change, we check, if we are not in maximized state.
if (!isMaximized())
{
d->setState(DraggingInactive);
}
break;
default:
break;
}
break;
case DraggingFloatingWidget:
if (e->type() == QEvent::NonClientAreaMouseButtonRelease)
{
ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease");
d->titleMouseReleaseEvent();
}
break;
default:
break;
}
#if (ADS_DEBUG_LEVEL > 0)
qDebug() << QTime::currentTime() << "CFloatingDockContainer::event " << e->type();
#endif
return QWidget::event(e);
}
//============================================================================
void CFloatingDockContainer::moveEvent(QMoveEvent *event)
{
QWidget::moveEvent(event);
switch (d->DraggingState)
{
case DraggingMousePressed:
d->setState(DraggingFloatingWidget);
d->updateDropOverlays(QCursor::pos());
break;
case DraggingFloatingWidget:
d->updateDropOverlays(QCursor::pos());
// In OSX when hiding the DockAreaOverlay the application would set
// the main window as the active window for some reason. This fixes
// that by resetting the active window to the floating widget after
// updating the overlays.
QApplication::setActiveWindow(this);
break;
default:
break;
}
}
#endif
#ifdef Q_OS_LINUX
//============================================================================
void CFloatingDockContainer::onMaximizeRequest()
{
if (windowState() == Qt::WindowMaximized)
{
showNormal();
}
else
{
showMaximized();
}
}
//============================================================================
void CFloatingDockContainer::showNormal(bool fixGeometry)
{
if (windowState() == Qt::WindowMaximized)
{
QRect oldNormal = normalGeometry();
Super::showNormal();
if(fixGeometry)
{
setGeometry(oldNormal);
}
}
if(d->TitleBar)
{
d->TitleBar->setMaximizedIcon(false);
}
}
//============================================================================
void CFloatingDockContainer::showMaximized()
{
Super::showMaximized();
if (d->TitleBar)
{
d->TitleBar->setMaximizedIcon(true);
}
}
//============================================================================
bool CFloatingDockContainer::isMaximized() const
{
return windowState() == Qt::WindowMaximized;
}
//============================================================================
void CFloatingDockContainer::show()
{
// Prevent this window from showing in the taskbar and pager (alt+tab)
internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_TASKBAR");
internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_PAGER");
Super::show();
}
//============================================================================
void CFloatingDockContainer::resizeEvent(QResizeEvent *event)
{
d->IsResizing = true;
Super::resizeEvent(event);
}
//============================================================================
void CFloatingDockContainer::moveEvent(QMoveEvent *event)
{
Super::moveEvent(event);
if (!d->IsResizing && event->spontaneous())
{
d->DraggingState = DraggingFloatingWidget;
d->updateDropOverlays(QCursor::pos());
}
d->IsResizing = false;
}
//============================================================================
bool CFloatingDockContainer::hasNativeTitleBar()
{
return d->TitleBar == nullptr;
}
#endif
} // namespace ads
//---------------------------------------------------------------------------

View File

@@ -172,8 +172,7 @@ protected:
/**
* Call this function to update the window title
*/
void updateWindowTitle();
void updateWindowTitle();
protected: // reimplements QWidget
virtual void changeEvent(QEvent *event) override;
@@ -181,6 +180,16 @@ protected: // reimplements QWidget
virtual void hideEvent(QHideEvent *event) override;
virtual void showEvent(QShowEvent *event) override;
#ifdef Q_OS_MACOS
virtual bool event(QEvent *e) override;
virtual void moveEvent(QMoveEvent *event) override;
#endif
#ifdef Q_OS_LINUX
virtual void moveEvent(QMoveEvent *event) override;
virtual void resizeEvent(QResizeEvent *event) override;
#endif
#ifdef Q_OS_WIN
/**
* Native event filter for handling WM_MOVING messages on Windows
@@ -190,7 +199,7 @@ protected: // reimplements QWidget
public:
using Super = QWidget;
using Super = tFloatingWidgetBase;
/**
* Create empty floating widget - required for restore state
@@ -244,6 +253,44 @@ public:
* function of the internal container widget.
*/
QList<CDockWidget*> dockWidgets() const;
#ifdef Q_OS_LINUX
/**
* This is a function that responds to FloatingWidgetTitleBar::maximizeRequest()
* Maximize or normalize the container size.
*/
void onMaximizeRequest();
/**
* Normalize (Unmaximize) the window.
* fixGeometry parameter fixes a "bug" in QT where immediately after calling showNormal
* geometry is not set properly.
* Set this true when moving the window immediately after normalizing.
*/
void showNormal(bool fixGeometry=false);
/**
* Maximizes the window.
*/
void showMaximized();
/**
* Returns if the window is currently maximized or not.
*/
bool isMaximized() const;
/**
* Patched show to prevent the window from appearing in the taskbar.
*/
void show();
/**
* Returns true if the floating widget has a native titlebar or false if
* the floating widget has a QWidget based title bar
*/
bool hasNativeTitleBar();
#endif
}; // class FloatingDockContainer
}
// namespace ads

View File

@@ -112,7 +112,7 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
{
ContainerOverlay->hideOverlay();
DockAreaOverlay->hideOverlay();
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewIsDynamic))
if (CDockManager::testConfigFlag(CDockManager::DragPreviewIsDynamic))
{
setHidden(false);
}
@@ -151,7 +151,7 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
// If there is only one single visible dock area in a container, then
// it does not make sense to show a dock overlay because the dock area
// would be removed and inserted at the same position
if (VisibleDockAreas <= 1)
if (VisibleDockAreas == 1)
{
ContainerOverlay->hideOverlay();
}
@@ -167,7 +167,7 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
}
}
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewIsDynamic))
if (CDockManager::testConfigFlag(CDockManager::DragPreviewIsDynamic))
{
setHidden(DockDropArea != InvalidDockWidgetArea || ContainerDropArea != InvalidDockWidgetArea);
}
@@ -203,7 +203,7 @@ void FloatingDragPreviewPrivate::createFloatingWidget()
{
FloatingWidget->setGeometry(_this->geometry());
FloatingWidget->show();
if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
if (!CDockManager::testConfigFlag(CDockManager::DragPreviewHasWindowFrame))
{
QApplication::processEvents();
int FrameHeight = FloatingWidget->frameGeometry().height() - FloatingWidget->geometry().height();
@@ -222,7 +222,7 @@ CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) :
{
d->Content = Content;
setAttribute(Qt::WA_DeleteOnClose);
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
if (CDockManager::testConfigFlag(CDockManager::DragPreviewHasWindowFrame))
{
setWindowFlags(
Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
@@ -245,7 +245,7 @@ CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) :
// Create a static image of the widget that should get undocked
// This is like some kind preview image like it is uses in drag and drop
// operations
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewShowsContentPixmap))
if (CDockManager::testConfigFlag(CDockManager::DragPreviewShowsContentPixmap))
{
d->ContentPreviewPixmap = QPixmap(Content->size());
Content->render(&d->ContentPreviewPixmap);
@@ -363,14 +363,14 @@ void CFloatingDragPreview::paintEvent(QPaintEvent* event)
}
QPainter painter(this);
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewShowsContentPixmap))
if (CDockManager::testConfigFlag(CDockManager::DragPreviewShowsContentPixmap))
{
painter.drawPixmap(QPoint(0, 0), d->ContentPreviewPixmap);
}
// If we do not have a window frame then we paint a QRubberBand like
// frameless window
if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
if (!CDockManager::testConfigFlag(CDockManager::DragPreviewHasWindowFrame))
{
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
QPen Pen = painter.pen();

View File

@@ -4,5 +4,15 @@
<file>images/close-button.svg</file>
<file>images/close-button-disabled.svg</file>
<file>stylesheets/default_linux.css</file>
<file>images/close-button-focused.svg</file>
<file>stylesheets/focus_highlighting.css</file>
<file>stylesheets/focus_highlighting_linux.css</file>
<file>images/tabs-menu-button.svg</file>
<file>images/detach-button.svg</file>
<file>images/detach-button-disabled.svg</file>
<file>images/maximize-button.svg</file>
<file>images/maximize-button-focused.svg</file>
<file>images/restore-button.svg</file>
<file>images/restore-button-focused.svg</file>
</qresource>
</RCC>

View File

@@ -31,18 +31,262 @@
#include <QVariant>
#include <QPainter>
#include <QAbstractButton>
#include <QStyle>
#include "DockSplitter.h"
#include "DockManager.h"
#include "IconProvider.h"
#include "ads_globals.h"
#ifdef Q_OS_LINUX
#include <QX11Info>
#include <QSettings>
#include <QFile>
#endif
#include <QApplication>
namespace ads
{
namespace internal
{
#ifdef Q_OS_LINUX
static QString _window_manager;
static QHash<QString, xcb_atom_t> _xcb_atom_cache;
//============================================================================
xcb_atom_t xcb_get_atom(const char *name)
{
if (!QX11Info::isPlatformX11())
{
return XCB_ATOM_NONE;
}
auto key = QString(name);
if(_xcb_atom_cache.contains(key))
{
return _xcb_atom_cache[key];
}
xcb_connection_t *connection = QX11Info::connection();
xcb_intern_atom_cookie_t request = xcb_intern_atom(connection, 1, strlen(name), name);
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, request, NULL);
if (!reply)
{
return XCB_ATOM_NONE;
}
xcb_atom_t atom = reply->atom;
if(atom == XCB_ATOM_NONE)
{
ADS_PRINT("Unknown Atom response from XServer: " << name);
}
else
{
_xcb_atom_cache.insert(key, atom);
}
free(reply);
return atom;
}
//============================================================================
void xcb_update_prop(bool set, WId window, const char *type, const char *prop, const char *prop2)
{
auto connection = QX11Info::connection();
xcb_atom_t type_atom = xcb_get_atom(type);
xcb_atom_t prop_atom = xcb_get_atom(prop);
xcb_client_message_event_t event;
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.sequence = 0;
event.window = window;
event.type = type_atom;
event.data.data32[0] = set ? 1 : 0;
event.data.data32[1] = prop_atom;
event.data.data32[2] = prop2 ? xcb_get_atom(prop2) : 0;
event.data.data32[3] = 0;
event.data.data32[4] = 0;
xcb_send_event(connection, 0, window,
XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_PROPERTY_CHANGE,
(const char *)&event);
xcb_flush(connection);
}
//============================================================================
xcb_get_property_reply_t* _xcb_get_props(WId window, const char *type, unsigned int atom_type)
{
if (!QX11Info::isPlatformX11())
{
return nullptr;
}
xcb_connection_t *connection = QX11Info::connection();
xcb_atom_t type_atom = xcb_get_atom(type);
if (type_atom == XCB_ATOM_NONE)
{
return nullptr;
}
xcb_get_property_cookie_t request = xcb_get_property_unchecked(connection, 0, window, type_atom, atom_type, 0, 1024);
xcb_get_property_reply_t *reply = xcb_get_property_reply(connection, request, nullptr);
if(reply && reply->type != atom_type)
{
ADS_PRINT("ATOM TYPE MISMATCH (" << type <<"). Expected: " << atom_type << " but got " << reply->type);
free(reply);
return nullptr;
}
return reply;
}
//============================================================================
template <typename T>
void xcb_get_prop_list(WId window, const char *type, QVector<T> &ret, unsigned int atom_type)
{
xcb_get_property_reply_t *reply = _xcb_get_props(window, type, atom_type);
if (reply && reply->format == 32 && reply->type == atom_type && reply->value_len > 0)
{
const xcb_atom_t *data = static_cast<const T *>(xcb_get_property_value(reply));
ret.resize(reply->value_len);
memcpy((void *)&ret.first(), (void *)data, reply->value_len * sizeof(T));
}
free(reply);
}
//============================================================================
QString xcb_get_prop_string(WId window, const char *type)
{
QString ret;
// try utf8 first
xcb_atom_t utf_atom = xcb_get_atom("UTF8_STRING");
if(utf_atom != XCB_ATOM_NONE)
{
xcb_get_property_reply_t *reply = _xcb_get_props(window, type, utf_atom);
if (reply && reply->format == 8 && reply->type == utf_atom)
{
const char *value = reinterpret_cast<const char *>(xcb_get_property_value(reply));
ret = QString::fromUtf8(value, xcb_get_property_value_length(reply));
free(reply);
return ret;
}
free(reply);
}
// Fall back to XCB_ATOM_STRING
xcb_get_property_reply_t *reply = _xcb_get_props(window, type, XCB_ATOM_STRING);
if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING)
{
const char *value = reinterpret_cast<const char *>(xcb_get_property_value(reply));
ret = QString::fromLatin1(value, xcb_get_property_value_length(reply));
}
free(reply);
return ret;
}
//============================================================================
bool xcb_dump_props(WId window, const char *type)
{
QVector<xcb_atom_t> atoms;
xcb_get_prop_list(window, type, atoms, XCB_ATOM_ATOM);
qDebug() << "\n\n!!!" << type << " - " << atoms.length();
xcb_connection_t *connection = QX11Info::connection();
for (auto atom : atoms)
{
auto foo = xcb_get_atom_name(connection, atom);
auto bar = xcb_get_atom_name_reply(connection, foo, nullptr);
qDebug() << "\t" << xcb_get_atom_name_name(bar);
free(bar);
}
return true;
}
//============================================================================
void xcb_add_prop(bool state, WId window, const char *type, const char *prop)
{
if (!QX11Info::isPlatformX11())
{
return;
}
xcb_atom_t prop_atom = xcb_get_atom(prop);
xcb_atom_t type_atom = xcb_get_atom(type);
if (prop_atom == XCB_ATOM_NONE || type_atom == XCB_ATOM_NONE)
{
return;
}
QVector<xcb_atom_t> atoms;
xcb_get_prop_list(window, type, atoms, XCB_ATOM_ATOM);
int index = atoms.indexOf(prop_atom);
if (state && index == -1)
{
atoms.push_back(prop_atom);
}
else if (!state && index >= 0)
{
atoms.remove(index);
}
xcb_connection_t *connection = QX11Info::connection();
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, type_atom, XCB_ATOM_ATOM, 32, atoms.count(), atoms.constData());
xcb_flush(connection);
}
//============================================================================
QString detectWindowManagerX11()
{
// Tries to detect the windowmanager via X11.
// See: https://specifications.freedesktop.org/wm-spec/1.3/ar01s03.html#idm46018259946000
if (!QX11Info::isPlatformX11())
{
return "UNKNOWN";
}
xcb_connection_t *connection = QX11Info::connection();
xcb_screen_t *first_screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
if(!first_screen)
{
ADS_PRINT("No screen found via XCB.");
return "UNKNOWN";
}
// Get supporting window ()
xcb_window_t root = first_screen->root;
xcb_window_t support_win = 0;
QVector<xcb_window_t> sup_windows;
xcb_get_prop_list(root, "_NET_SUPPORTING_WM_CHECK", sup_windows, XCB_ATOM_WINDOW);
if(sup_windows.length() == 0)
{
// This doesn't seem to be in use anymore, but wmctrl does the same so lets play safe.
// Both XCB_ATOM_CARDINAL and XCB_ATOM_WINDOW break down to a uint32_t, so reusing sup_windows should be fine.
xcb_get_prop_list(root, "_WIN_SUPPORTING_WM_CHECK", sup_windows, XCB_ATOM_CARDINAL);
}
if(sup_windows.length() == 0)
{
ADS_PRINT("Failed to get the supporting window on non EWMH comform WM.");
return "UNKNOWN";
}
support_win = sup_windows[0];
QString ret = xcb_get_prop_string(support_win, "_NET_WM_NAME");
if(ret.length() == 0)
{
ADS_PRINT("Empty WM name occured.");
return "UNKNOWN";
}
return ret;
}
//============================================================================
QString windowManager()
{
if(_window_manager.length() == 0)
{
_window_manager = detectWindowManagerX11();
}
return _window_manager;
}
#endif
//============================================================================
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To)
{
@@ -118,6 +362,31 @@ void setButtonIcon(QAbstractButton* Button, QStyle::StandardPixmap StandarPixmap
#endif
}
//============================================================================
void repolishStyle(QWidget* w, eRepolishChildOptions Options)
{
if (!w)
{
return;
}
w->style()->unpolish(w);
w->style()->polish(w);
if (RepolishIgnoreChildren == Options)
{
return;
}
QList<QWidget*> Children = w->findChildren<QWidget*>(QString(),
(RepolishDirectChildren == Options) ? Qt::FindDirectChildrenOnly: Qt::FindChildrenRecursively);
for (auto Widget : Children)
{
Widget->style()->unpolish(Widget);
Widget->style()->polish(Widget);
}
}
} // namespace internal
} // namespace ads

View File

@@ -37,6 +37,10 @@
#include <QDebug>
#include <QStyle>
#ifdef Q_OS_LINUX
#include <xcb/xcb.h>
#endif
QT_FORWARD_DECLARE_CLASS(QAbstractButton)
#ifndef ADS_STATIC
@@ -64,13 +68,6 @@ QT_FORWARD_DECLARE_CLASS(QSplitter)
namespace ads
{
enum eStateFileVersion
{
InitialVersion = 0,
Version1 = 1,
CurrentVersion = Version1
};
class CDockSplitter;
enum DockWidgetArea
@@ -129,6 +126,7 @@ enum eBitwiseOperator
BitwiseOr
};
namespace internal
{
static const bool RestoreTesting = true;
@@ -136,6 +134,33 @@ static const bool Restore = false;
static const char* const ClosedProperty = "close";
static const char* const DirtyProperty = "dirty";
#ifdef Q_OS_LINUX
// Utils to directly communicate with the X server
/**
* Get atom from cache or request it from the XServer.
*/
xcb_atom_t xcb_get_atom(const char *name);
/**
* Add a property to a window. Only works on "hidden" windows.
*/
void xcb_add_prop(bool state, WId window, const char *type, const char *prop);
/**
* Updates up to two window properties. Can be set on a visible window.
*/
void xcb_update_prop(bool set, WId window, const char *type, const char *prop, const char *prop2 = nullptr);
/**
* Only for debugging purposes.
*/
bool xcb_dump_props(WId window, const char *type);
/**
* Gets the active window manager from the X11 Server.
* Requires a EWMH conform window manager (Allmost all common used ones are).
* Returns "UNKNOWN" otherwise.
*/
QString windowManager();
#endif
/**
* Replace the from widget in the given splitter with the To widget
*/
@@ -251,6 +276,21 @@ void setToolTip(QObjectPtr obj, const QString &tip)
void setButtonIcon(QAbstractButton* Button, QStyle::StandardPixmap StandarPixmap,
ads::eIcon CustomIconId);
enum eRepolishChildOptions
{
RepolishIgnoreChildren,
RepolishDirectChildren,
RepolishChildrenRecursively
};
/**
* Calls unpolish() / polish for the style of the given widget to update
* stylesheet if a property changes
*/
void repolishStyle(QWidget* w, eRepolishChildOptions Options = RepolishIgnoreChildren);
} // namespace internal
} // namespace ads

View File

@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@@ -9,114 +7,133 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="512"
height="512"
viewBox="0 0 512 512"
xml:space="preserve"
sodipodi:docname="close-button-disabled.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata897"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs895" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview893"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.85862966"
inkscape:cx="345.29142"
inkscape:cy="32.731258"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g860"
transform="matrix(0.71708683,0,0,0.71708683,128,128)"
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081">
<g
id="close"
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081">
<polygon
points="357,321.3 214.2,178.5 357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 "
id="polygon857"
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081" />
</g>
</g>
<g
id="g862"
transform="translate(0,155)">
</g>
<g
id="g864"
transform="translate(0,155)">
</g>
<g
id="g866"
transform="translate(0,155)">
</g>
<g
id="g868"
transform="translate(0,155)">
</g>
<g
id="g870"
transform="translate(0,155)">
</g>
<g
id="g872"
transform="translate(0,155)">
</g>
<g
id="g874"
transform="translate(0,155)">
</g>
<g
id="g876"
transform="translate(0,155)">
</g>
<g
id="g878"
transform="translate(0,155)">
</g>
<g
id="g880"
transform="translate(0,155)">
</g>
<g
id="g882"
transform="translate(0,155)">
</g>
<g
id="g884"
transform="translate(0,155)">
</g>
<g
id="g886"
transform="translate(0,155)">
</g>
<g
id="g888"
transform="translate(0,155)">
</g>
<g
id="g890"
transform="translate(0,155)">
</g>
</svg>
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
version="1.1"
id="svg2"
viewBox="0 0 16 16"
height="16px"
width="16px">
<style
id="style2"></style>
<defs
id="defs4">
<pattern
id="EMFhbasepattern"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-4"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-3"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-8"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
</defs>
<sodipodi:namedview
inkscape:guide-bbox="true"
showguides="true"
inkscape:document-rotation="0"
inkscape:snap-global="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:bbox-nodes="true"
inkscape:bbox-paths="true"
inkscape:snap-bbox="true"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="1912"
inkscape:window-height="1017"
inkscape:window-width="1920"
units="px"
showgrid="true"
inkscape:current-layer="g5228"
inkscape:document-units="px"
inkscape:cy="13.17691"
inkscape:cx="6.2316889"
inkscape:zoom="22.627417"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base">
<inkscape:grid
id="grid3336"
type="xygrid" />
<sodipodi:guide
id="guide883"
orientation="1,0"
position="4,10" />
<sodipodi:guide
id="guide885"
orientation="0,-1"
position="10,12" />
<sodipodi:guide
id="guide887"
orientation="1,0"
position="12,2" />
<sodipodi:guide
id="guide889"
orientation="0,-1"
position="14,4" />
</sodipodi:namedview>
<g
transform="translate(0,-1036.3622)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
id="g5228"
transform="translate(628,-140.49998)">
<path
id="path846"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#a0a0a0;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1;opacity:1"
d="M 4.4765625 4.0019531 A 0.5 0.5 0 0 0 4.1464844 4.1464844 A 0.5 0.5 0 0 0 4.1464844 4.8535156 L 7.2929688 8 L 4.1464844 11.146484 A 0.5 0.5 0 0 0 4.1464844 11.853516 A 0.5 0.5 0 0 0 4.8535156 11.853516 L 8 8.7070312 L 11.146484 11.853516 A 0.5 0.5 0 0 0 11.853516 11.853516 A 0.5 0.5 0 0 0 11.853516 11.146484 L 8.7070312 8 L 11.853516 4.8535156 A 0.5 0.5 0 0 0 11.853516 4.1464844 A 0.5 0.5 0 0 0 11.476562 4.0019531 A 0.5 0.5 0 0 0 11.146484 4.1464844 L 8 7.2929688 L 4.8535156 4.1464844 A 0.5 0.5 0 0 0 4.4765625 4.0019531 z "
transform="translate(-628,1176.8622)" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
dc:language="en"
dc:format="image/svg+xml"
dc:date="2016-12-14"
dc:publisher="Iconscout"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
about="https://iconscout.com/legal#licenses">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="close-button-focused.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
version="1.1"
id="svg2"
viewBox="0 0 16 16"
height="16px"
width="16px">
<style
id="style2"></style>
<defs
id="defs4">
<pattern
id="EMFhbasepattern"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-4"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-3"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-8"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
</defs>
<sodipodi:namedview
inkscape:guide-bbox="true"
showguides="true"
inkscape:document-rotation="0"
inkscape:snap-global="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:bbox-nodes="true"
inkscape:bbox-paths="true"
inkscape:snap-bbox="true"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="-8"
inkscape:window-height="1017"
inkscape:window-width="1920"
units="px"
showgrid="true"
inkscape:current-layer="g5228"
inkscape:document-units="px"
inkscape:cy="13.17691"
inkscape:cx="6.2316889"
inkscape:zoom="22.627417"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base">
<inkscape:grid
id="grid3336"
type="xygrid" />
<sodipodi:guide
id="guide883"
orientation="1,0"
position="4,10" />
<sodipodi:guide
id="guide885"
orientation="0,-1"
position="10,12" />
<sodipodi:guide
id="guide887"
orientation="1,0"
position="12,2" />
<sodipodi:guide
id="guide889"
orientation="0,-1"
position="14,4" />
</sodipodi:namedview>
<g
transform="translate(0,-1036.3622)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
id="g5228"
transform="translate(628,-140.49998)">
<path
id="path846"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1;opacity:1"
d="M 4.4765625 4.0019531 A 0.5 0.5 0 0 0 4.1464844 4.1464844 A 0.5 0.5 0 0 0 4.1464844 4.8535156 L 7.2929688 8 L 4.1464844 11.146484 A 0.5 0.5 0 0 0 4.1464844 11.853516 A 0.5 0.5 0 0 0 4.8535156 11.853516 L 8 8.7070312 L 11.146484 11.853516 A 0.5 0.5 0 0 0 11.853516 11.853516 A 0.5 0.5 0 0 0 11.853516 11.146484 L 8.7070312 8 L 11.853516 4.8535156 A 0.5 0.5 0 0 0 11.853516 4.1464844 A 0.5 0.5 0 0 0 11.476562 4.0019531 A 0.5 0.5 0 0 0 11.146484 4.1464844 L 8 7.2929688 L 4.8535156 4.1464844 A 0.5 0.5 0 0 0 4.4765625 4.0019531 z "
transform="translate(-628,1176.8622)" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
dc:language="en"
dc:format="image/svg+xml"
dc:date="2016-12-14"
dc:publisher="Iconscout"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
about="https://iconscout.com/legal#licenses">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@@ -9,111 +7,133 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="512"
height="512"
viewBox="0 0 512 512"
xml:space="preserve"
sodipodi:docname="close-button.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata897"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs895" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview893"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.85862966"
inkscape:cx="345.29142"
inkscape:cy="32.731258"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g860"
transform="matrix(0.71708683,0,0,0.71708683,128,128)">
<g
id="close">
<polygon
points="357,321.3 214.2,178.5 357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 "
id="polygon857" />
</g>
</g>
<g
id="g862"
transform="translate(0,155)">
</g>
<g
id="g864"
transform="translate(0,155)">
</g>
<g
id="g866"
transform="translate(0,155)">
</g>
<g
id="g868"
transform="translate(0,155)">
</g>
<g
id="g870"
transform="translate(0,155)">
</g>
<g
id="g872"
transform="translate(0,155)">
</g>
<g
id="g874"
transform="translate(0,155)">
</g>
<g
id="g876"
transform="translate(0,155)">
</g>
<g
id="g878"
transform="translate(0,155)">
</g>
<g
id="g880"
transform="translate(0,155)">
</g>
<g
id="g882"
transform="translate(0,155)">
</g>
<g
id="g884"
transform="translate(0,155)">
</g>
<g
id="g886"
transform="translate(0,155)">
</g>
<g
id="g888"
transform="translate(0,155)">
</g>
<g
id="g890"
transform="translate(0,155)">
</g>
</svg>
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="close-button2.svg">
<style
id="style2"></style>
<defs
id="defs4">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="6.2316889"
inkscape:cy="13.17691"
inkscape:document-units="px"
inkscape:current-layer="g5228"
showgrid="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-global="true"
inkscape:document-rotation="0"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3336" />
<sodipodi:guide
position="4,10"
orientation="1,0"
id="guide883" />
<sodipodi:guide
position="10,12"
orientation="0,-1"
id="guide885" />
<sodipodi:guide
position="12,2"
orientation="1,0"
id="guide887" />
<sodipodi:guide
position="14,4"
orientation="0,-1"
id="guide889" />
</sodipodi:namedview>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
transform="translate(628,-140.49998)"
id="g5228">
<path
transform="translate(-628,1176.8622)"
d="M 4.4765625 4.0019531 A 0.5 0.5 0 0 0 4.1464844 4.1464844 A 0.5 0.5 0 0 0 4.1464844 4.8535156 L 7.2929688 8 L 4.1464844 11.146484 A 0.5 0.5 0 0 0 4.1464844 11.853516 A 0.5 0.5 0 0 0 4.8535156 11.853516 L 8 8.7070312 L 11.146484 11.853516 A 0.5 0.5 0 0 0 11.853516 11.853516 A 0.5 0.5 0 0 0 11.853516 11.146484 L 8.7070312 8 L 11.853516 4.8535156 A 0.5 0.5 0 0 0 11.853516 4.1464844 A 0.5 0.5 0 0 0 11.476562 4.0019531 A 0.5 0.5 0 0 0 11.146484 4.1464844 L 8 7.2929688 L 4.8535156 4.1464844 A 0.5 0.5 0 0 0 4.4765625 4.0019531 z "
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1;opacity:1"
id="path846" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
about="https://iconscout.com/legal#licenses"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:publisher="Iconscout"
dc:date="2016-12-14"
dc:format="image/svg+xml"
dc:language="en">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="detach-button-disabled.svg">
<style
id="style2"></style>
<defs
id="defs4">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-2" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-9" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4-8" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3-7" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8-0" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-41" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4-5" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3-0" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8-2" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="6.2316889"
inkscape:cy="12.734968"
inkscape:document-units="px"
inkscape:current-layer="g5228"
showgrid="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-global="true"
inkscape:document-rotation="0"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3336" />
<sodipodi:guide
position="4,10"
orientation="1,0"
id="guide883" />
<sodipodi:guide
position="10,12"
orientation="0,-1"
id="guide885" />
<sodipodi:guide
position="12,2"
orientation="1,0"
id="guide887" />
<sodipodi:guide
position="14,4"
orientation="0,-1"
id="guide889" />
</sodipodi:namedview>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
transform="translate(628,-140.49998)"
id="g5228">
<path
id="path893"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#a0a0a0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:9.2;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
d="m -622,1179.8622 v 0.5 1.5 1 h -2 v 0.5 1.5 4 h 6 v -3 h 2 v -4 -2 z m 1,2 h 4 v 3 h -1 v -2 h -3 z m -2,3 h 4 v 3 h -4 z" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
about="https://iconscout.com/legal#licenses"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:publisher="Iconscout"
dc:date="2016-12-14"
dc:format="image/svg+xml"
dc:language="en">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<style
id="style2-3" />
<style
id="style2-1" />
</svg>

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="detach-button.svg">
<style
id="style2"></style>
<defs
id="defs4">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-2" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-9" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4-8" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3-7" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8-0" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="6.2316889"
inkscape:cy="12.734968"
inkscape:document-units="px"
inkscape:current-layer="g5228"
showgrid="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-global="true"
inkscape:document-rotation="0"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3336" />
<sodipodi:guide
position="4,10"
orientation="1,0"
id="guide883" />
<sodipodi:guide
position="10,12"
orientation="0,-1"
id="guide885" />
<sodipodi:guide
position="12,2"
orientation="1,0"
id="guide887" />
<sodipodi:guide
position="14,4"
orientation="0,-1"
id="guide889" />
</sodipodi:namedview>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
transform="translate(628,-140.49998)"
id="g5228">
<path
id="path893"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:9.2;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
d="m -622,1179.8622 v 0.5 1.5 1 h -2 v 0.5 1.5 4 h 6 v -3 h 2 v -4 -2 z m 1,2 h 4 v 3 h -1 v -2 h -3 z m -2,3 h 4 v 3 h -4 z" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
about="https://iconscout.com/legal#licenses"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:publisher="Iconscout"
dc:date="2016-12-14"
dc:format="image/svg+xml"
dc:language="en">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<style
id="style2-3" />
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="maximize-button-focused.svg">
<style
id="style2" />
<defs
id="defs4">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="-7.4143106"
inkscape:cy="6.591104"
inkscape:document-units="px"
inkscape:current-layer="g5228"
showgrid="true"
units="px"
inkscape:window-width="1848"
inkscape:window-height="920"
inkscape:window-x="72"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-global="true"
inkscape:document-rotation="0"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3336" />
<sodipodi:guide
position="4,10"
orientation="1,0"
id="guide883"
inkscape:locked="false" />
<sodipodi:guide
position="10,12"
orientation="0,-1"
id="guide885"
inkscape:locked="false" />
<sodipodi:guide
position="12,2"
orientation="1,0"
id="guide887"
inkscape:locked="false" />
<sodipodi:guide
position="14,4"
orientation="0,-1"
id="guide889"
inkscape:locked="false" />
</sodipodi:namedview>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
transform="translate(628,-140.49998)"
id="g5228">
<rect
id="rect4094"
width="7"
height="7"
x="-623.5"
y="1181.3622"
style="fill:none;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
about="https://iconscout.com/legal#licenses"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:publisher="Iconscout"
dc:date="2016-12-14"
dc:format="image/svg+xml"
dc:language="en">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="maximize-button.svg">
<style
id="style2" />
<defs
id="defs4">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="-1.8674356"
inkscape:cy="6.591104"
inkscape:document-units="px"
inkscape:current-layer="g5228"
showgrid="true"
units="px"
inkscape:window-width="1848"
inkscape:window-height="920"
inkscape:window-x="72"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-global="true"
inkscape:document-rotation="0"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3336" />
<sodipodi:guide
position="4,10"
orientation="1,0"
id="guide883"
inkscape:locked="false" />
<sodipodi:guide
position="10,12"
orientation="0,-1"
id="guide885"
inkscape:locked="false" />
<sodipodi:guide
position="12,2"
orientation="1,0"
id="guide887"
inkscape:locked="false" />
<sodipodi:guide
position="14,4"
orientation="0,-1"
id="guide889"
inkscape:locked="false" />
</sodipodi:namedview>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
transform="translate(628,-140.49998)"
id="g5228">
<rect
id="rect4094"
width="7"
height="7"
x="-623.5"
y="1181.3622"
style="fill:none;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
about="https://iconscout.com/legal#licenses"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:publisher="Iconscout"
dc:date="2016-12-14"
dc:format="image/svg+xml"
dc:language="en">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="restore-button-focused.svg">
<style
id="style2" />
<defs
id="defs4">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="3.6794394"
inkscape:cy="7.841104"
inkscape:document-units="px"
inkscape:current-layer="g5228"
showgrid="true"
units="px"
inkscape:window-width="1848"
inkscape:window-height="920"
inkscape:window-x="72"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-global="true"
inkscape:document-rotation="0"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3336" />
<sodipodi:guide
position="4,10"
orientation="1,0"
id="guide883"
inkscape:locked="false" />
<sodipodi:guide
position="10,12"
orientation="0,-1"
id="guide885"
inkscape:locked="false" />
<sodipodi:guide
position="12,2"
orientation="1,0"
id="guide887"
inkscape:locked="false" />
<sodipodi:guide
position="14,4"
orientation="0,-1"
id="guide889"
inkscape:locked="false" />
</sodipodi:namedview>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
transform="translate(628,-140.49998)"
id="g5228">
<rect
id="rect4094"
width="5.055603"
height="5.0555329"
x="-623.5556"
y="1183.3622"
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
<path
style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -621.98958,1181.3414 h 5.51042 v 5.4999"
id="path6127"
inkscape:connector-curvature="0" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
about="https://iconscout.com/legal#licenses"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:publisher="Iconscout"
dc:date="2016-12-14"
dc:format="image/svg+xml"
dc:language="en">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="svg2"
version="1.1"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="restore-button.svg">
<style
id="style2" />
<defs
id="defs4">
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-4" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-3" />
<pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern-8" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="32"
inkscape:cx="3.6794394"
inkscape:cy="7.841104"
inkscape:document-units="px"
inkscape:current-layer="g5228"
showgrid="true"
units="px"
inkscape:window-width="1848"
inkscape:window-height="920"
inkscape:window-x="72"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-global="true"
inkscape:document-rotation="0"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid3336" />
<sodipodi:guide
position="4,10"
orientation="1,0"
id="guide883"
inkscape:locked="false" />
<sodipodi:guide
position="10,12"
orientation="0,-1"
id="guide885"
inkscape:locked="false" />
<sodipodi:guide
position="12,2"
orientation="1,0"
id="guide887"
inkscape:locked="false" />
<sodipodi:guide
position="14,4"
orientation="0,-1"
id="guide889"
inkscape:locked="false" />
</sodipodi:namedview>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
transform="translate(628,-140.49998)"
id="g5228">
<rect
id="rect4094"
width="5.055603"
height="5.0555329"
x="-623.5556"
y="1183.3622"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -621.98958,1181.3414 h 5.51042 v 5.4999"
id="path6127"
inkscape:connector-curvature="0" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
about="https://iconscout.com/legal#licenses"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:publisher="Iconscout"
dc:date="2016-12-14"
dc:format="image/svg+xml"
dc:language="en">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="tabs-menu-button.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
version="1.1"
id="svg2"
viewBox="0 0 16 16"
height="16px"
width="16px">
<style
id="style2"></style>
<defs
id="defs4">
<pattern
id="EMFhbasepattern"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-4"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-3"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
<pattern
id="EMFhbasepattern-8"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
</defs>
<sodipodi:namedview
inkscape:guide-bbox="true"
showguides="true"
inkscape:document-rotation="0"
inkscape:snap-global="true"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:bbox-nodes="true"
inkscape:bbox-paths="true"
inkscape:snap-bbox="true"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="-8"
inkscape:window-height="1017"
inkscape:window-width="1920"
units="px"
showgrid="true"
inkscape:current-layer="g5228"
inkscape:document-units="px"
inkscape:cy="13.17691"
inkscape:cx="6.2316889"
inkscape:zoom="22.627417"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base">
<inkscape:grid
id="grid3336"
type="xygrid" />
<sodipodi:guide
id="guide883"
orientation="1,0"
position="4,10" />
<sodipodi:guide
id="guide885"
orientation="0,-1"
position="10,12" />
<sodipodi:guide
id="guide887"
orientation="1,0"
position="12,2" />
<sodipodi:guide
id="guide889"
orientation="0,-1"
position="14,4" />
</sodipodi:namedview>
<g
transform="translate(0,-1036.3622)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
id="g5228"
transform="translate(628,-140.49998)">
<path
id="path842"
d="m -624,1182.8622 4,4 4,-4 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
<metadata
id="metadata12">
<rdf:RDF>
<rdf:Description
dc:language="en"
dc:format="image/svg+xml"
dc:date="2016-12-14"
dc:publisher="Iconscout"
dc:description="Menu, Bar, Lines, Option, List, Hamburger, Web"
dc:title="Menu, Bar, Lines, Option, List, Hamburger, Web"
about="https://iconscout.com/legal#licenses">
<dc:creator>
<rdf:Bag>
<rdf:li>Jemis Mali</rdf:li>
</rdf:Bag>
</dc:creator>
</rdf:Description>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -45,7 +45,8 @@ namespace ads
{
using tTabLabel = CElidingLabel;
using tCloseButton = QPushButton;
using tCloseButton = QToolButton;
using tMaximizeButton = QToolButton;
/**
* @brief Private data class of public interface CFloatingWidgetTitleBar
@@ -56,8 +57,12 @@ struct FloatingWidgetTitleBarPrivate
QLabel *IconLabel = nullptr;
tTabLabel *TitleLabel;
tCloseButton *CloseButton = nullptr;
tMaximizeButton* MaximizeButton = nullptr;
CFloatingDockContainer *FloatingWidget = nullptr;
eDragState DragState = DraggingInactive;
QIcon MaximizeIcon;
QIcon NormalIcon;
bool Maximized = false;
FloatingWidgetTitleBarPrivate(CFloatingWidgetTitleBar *_public) :
_this(_public)
@@ -81,7 +86,11 @@ void FloatingWidgetTitleBarPrivate::createLayout()
CloseButton = new tCloseButton();
CloseButton->setObjectName("floatingTitleCloseButton");
CloseButton->setFlat(true);
CloseButton->setAutoRaise(true);
MaximizeButton = new tMaximizeButton();
MaximizeButton->setObjectName("floatingTitleMaximizeButton");
MaximizeButton->setAutoRaise(true);
// The standard icons do does not look good on high DPI screens
QIcon CloseIcon;
@@ -97,6 +106,12 @@ void FloatingWidgetTitleBarPrivate::createLayout()
CloseButton->setFocusPolicy(Qt::NoFocus);
_this->connect(CloseButton, SIGNAL(clicked()), SIGNAL(closeRequested()));
_this->setMaximizedIcon(false);
MaximizeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
MaximizeButton->setVisible(true);
MaximizeButton->setFocusPolicy(Qt::NoFocus);
_this->connect(MaximizeButton, &QPushButton::clicked, _this, &CFloatingWidgetTitleBar::maximizeRequested);
QFontMetrics fm(TitleLabel->font());
int Spacing = qRound(fm.height() / 4.0);
@@ -107,6 +122,7 @@ void FloatingWidgetTitleBarPrivate::createLayout()
_this->setLayout(Layout);
Layout->addWidget(TitleLabel, 1);
Layout->addSpacing(Spacing);
Layout->addWidget(MaximizeButton);
Layout->addWidget(CloseButton);
Layout->setAlignment(Qt::AlignCenter);
@@ -115,11 +131,20 @@ void FloatingWidgetTitleBarPrivate::createLayout()
//============================================================================
CFloatingWidgetTitleBar::CFloatingWidgetTitleBar(CFloatingDockContainer *parent) :
QWidget(parent),
QFrame(parent),
d(new FloatingWidgetTitleBarPrivate(this))
{
d->FloatingWidget = parent;
d->createLayout();
auto normalPixmap = this->style()->standardPixmap(QStyle::SP_TitleBarNormalButton, 0, d->MaximizeButton);
d->NormalIcon.addPixmap(normalPixmap, QIcon::Normal);
d->NormalIcon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25), QIcon::Disabled);
auto maxPixmap = this->style()->standardPixmap(QStyle::SP_TitleBarMaxButton, 0, d->MaximizeButton);
d->MaximizeIcon.addPixmap(maxPixmap, QIcon::Normal);
d->MaximizeIcon.addPixmap(internal::createTransparentPixmap(maxPixmap, 0.25), QIcon::Disabled);
setMaximizedIcon(d->Maximized);
}
//============================================================================
@@ -141,17 +166,19 @@ void CFloatingWidgetTitleBar::mousePressEvent(QMouseEvent *ev)
Super::mousePressEvent(ev);
}
//============================================================================
void CFloatingWidgetTitleBar::mouseReleaseEvent(QMouseEvent *ev)
{
d->DragState = DraggingInactive;
if (d->FloatingWidget)
{
d->FloatingWidget->finishDragging();
d->FloatingWidget->finishDragging();
}
Super::mouseReleaseEvent(ev);
}
//============================================================================
void CFloatingWidgetTitleBar::mouseMoveEvent(QMouseEvent *ev)
{
@@ -165,6 +192,10 @@ void CFloatingWidgetTitleBar::mouseMoveEvent(QMouseEvent *ev)
// move floating window
if (DraggingFloatingWidget == d->DragState)
{
if(d->FloatingWidget->isMaximized())
{
d->FloatingWidget->showNormal(true);
}
d->FloatingWidget->moveFloating();
Super::mouseMoveEvent(ev);
return;
@@ -172,16 +203,91 @@ void CFloatingWidgetTitleBar::mouseMoveEvent(QMouseEvent *ev)
Super::mouseMoveEvent(ev);
}
//============================================================================
void CFloatingWidgetTitleBar::enableCloseButton(bool Enable)
{
d->CloseButton->setEnabled(Enable);
}
//============================================================================
void CFloatingWidgetTitleBar::setTitle(const QString &Text)
{
d->TitleLabel->setText(Text);
}
//============================================================================
void CFloatingWidgetTitleBar::updateStyle()
{
internal::repolishStyle(this, internal::RepolishDirectChildren);
}
//============================================================================
void CFloatingWidgetTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
{
emit maximizeRequested();
event->accept();
}
else
{
QWidget::mouseDoubleClickEvent(event);
}
}
//============================================================================
void CFloatingWidgetTitleBar::setMaximizedIcon(bool maximized)
{
d->Maximized = maximized;
if (maximized)
{
d->MaximizeButton->setIcon(d->NormalIcon);
}
else
{
d->MaximizeButton->setIcon(d->MaximizeIcon);
}
}
//============================================================================
void CFloatingWidgetTitleBar::setMaximizeIcon(const QIcon& Icon)
{
d->MaximizeIcon = Icon;
if (d->Maximized)
{
setMaximizedIcon(d->Maximized);
}
}
//============================================================================
void CFloatingWidgetTitleBar::setNormalIcon(const QIcon& Icon)
{
d->NormalIcon = Icon;
if (!d->Maximized)
{
setMaximizedIcon(d->Maximized);
}
}
//============================================================================
QIcon CFloatingWidgetTitleBar::maximizeIcon() const
{
return d->MaximizeIcon;
}
//============================================================================
QIcon CFloatingWidgetTitleBar::normalIcon() const
{
return d->NormalIcon;
}
} // namespace ads

View File

@@ -29,7 +29,8 @@
//============================================================================
// INCLUDES
//============================================================================
#include <QWidget>
#include <QFrame>
#include <QIcon>
namespace ads
{
@@ -45,9 +46,11 @@ struct FloatingWidgetTitleBarPrivate;
* for the docking system to work properly, we use our own titlebar here to
* capture the required mouse events.
*/
class CFloatingWidgetTitleBar : public QWidget
class CFloatingWidgetTitleBar : public QFrame
{
Q_OBJECT
Q_PROPERTY(QIcon maximizeIcon READ maximizeIcon WRITE setMaximizeIcon)
Q_PROPERTY(QIcon normalIcon READ normalIcon WRITE setNormalIcon)
private:
FloatingWidgetTitleBarPrivate *d; ///< private data (pimpl)
@@ -55,6 +58,12 @@ protected:
virtual void mousePressEvent(QMouseEvent *ev) override;
virtual void mouseReleaseEvent(QMouseEvent *ev) override;
virtual void mouseMoveEvent(QMouseEvent *ev) override;
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
void setMaximizeIcon(const QIcon& Icon);
QIcon maximizeIcon() const;
void setNormalIcon(const QIcon& Icon);
QIcon normalIcon() const;
public:
using Super = QWidget;
@@ -75,11 +84,26 @@ public:
*/
void setTitle(const QString &Text);
/**
* Update stylesheet style if a property changes
*/
void updateStyle();
/**
* Change the maximize button icon according to current windows state
*/
void setMaximizedIcon(bool maximized);
signals:
/**
* This signal is emitted, if the close button is clicked.
*/
void closeRequested();
/**
* This signal is emitted, if the maximize button is clicked.
*/
void maximizeRequested();
};
} // namespace ads
#endif // FLOATINGWIDGETTITLEBAR_H

View File

@@ -45,7 +45,8 @@ HEADERS += \
DockAreaTitleBar.h \
ElidingLabel.h \
IconProvider.h \
DockComponentsFactory.h
DockComponentsFactory.h \
DockFocusController.h
SOURCES += \
@@ -64,12 +65,14 @@ SOURCES += \
DockAreaTitleBar.cpp \
ElidingLabel.cpp \
IconProvider.cpp \
DockComponentsFactory.cpp
DockComponentsFactory.cpp \
DockFocusController.cpp
unix {
HEADERS += linux/FloatingWidgetTitleBar.h
SOURCES += linux/FloatingWidgetTitleBar.cpp
QT += x11extras
}
isEmpty(PREFIX){

View File

@@ -1,94 +1,93 @@
/*
* Default style sheet on Windows Platforms
* Note: Always use CSS-classes with and without "ads--" namespace to support Qt4 & Qt5
*/
ads--CDockContainerWidget
{
background: palette(dark);
ads--CDockContainerWidget {
background: palette(dark);
}
ads--CDockContainerWidget QSplitter::handle
{
background: palette(dark);
ads--CDockContainerWidget QSplitter::handle {
background: palette(dark);
}
ads--CDockAreaWidget
{
background: palette(window);
border: 1px solid white;
ads--CDockAreaWidget {
background: palette(window);
border: 1px solid white;
}
ads--CDockAreaWidget #tabsMenuButton::menu-indicator
{
image: none;
ads--CDockWidgetTab {
background: palette(window);
border-color: palette(light);
border-style: solid;
border-width: 0 1px 0 0;
padding: 0 0px;
}
ads--CDockWidgetTab
{
background: palette(window);
border-color: palette(light);
border-style: solid;
border-width: 0 1px 0 0;
padding: 0 0px;
ads--CDockWidgetTab[activeTab="true"] {
background: qlineargradient(spread : pad, x1 : 0, y1 : 0, x2 : 0, y2 : 0.5, stop : 0
palette(window), stop:1 palette(light));
/*background: palette(highlight);*/
}
ads--CDockWidgetTab[activeTab="true"]
{
background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:0.5, stop:0 palette(window), stop:1 palette(light));
/*background: palette(highlight);*/
ads--CDockWidgetTab QLabel {
color: palette(dark);
}
ads--CDockWidgetTab QLabel
{
color: palette(dark);
ads--CDockWidgetTab[activeTab="true"] QLabel {
color: palette(foreground);
}
ads--CDockWidgetTab[activeTab="true"] QLabel
{
color: palette(foreground);
ads--CDockWidget {
background: palette(light);
border-color: palette(light);
border-style: solid;
border-width: 1px 0 0 0;
}
ads--CDockWidget
{
background: palette(light);
border-color: palette(light);
border-style: solid;
border-width: 1px 0 0 0;
}
ads--CTitleBarButton
{
ads--CTitleBarButton {
padding: 0px 0px;
}
QScrollArea#dockWidgetScrollArea
{
QScrollArea#dockWidgetScrollArea {
padding: 0px;
border: none;
}
#tabCloseButton
{
#tabCloseButton {
margin-top: 2px;
background: none;
border: none;
padding: 0px -2px;
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#tabCloseButton:hover
{
#tabCloseButton:hover {
border: 1px solid rgba(0, 0, 0, 32);
background: rgba(0, 0, 0, 16);
}
#tabCloseButton:pressed
{
#tabCloseButton:pressed {
background: rgba(0, 0, 0, 32);
}
#tabsMenuButton::menu-indicator {
image: none;
}
#tabsMenuButton {
qproperty-icon: url(:/ads/images/tabs-menu-button.svg);
qproperty-iconSize: 16px;
}
#dockAreaCloseButton {
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#detachGroupButton {
qproperty-icon: url(:/ads/images/detach-button.svg),
url(:/ads/images/detach-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}

View File

@@ -1,96 +1,121 @@
/*
* Default style sheet on Windows Platforms
* Note: Always use CSS-classes with and without "ads--" namespace to support Qt4 & Qt5
* Default style sheet on Linux Platforms
*/
ads--CDockContainerWidget
{
background: palette(dark);
ads--CDockContainerWidget {
background: palette(dark);
}
ads--CDockContainerWidget QSplitter::handle
{
background: palette(dark);
ads--CDockContainerWidget QSplitter::handle {
background: palette(dark);
}
ads--CDockAreaWidget
{
background: palette(window);
border: 1px solid white;
ads--CDockAreaWidget {
background: palette(window);
border: 1px solid white;
}
ads--CDockAreaWidget #tabsMenuButton::menu-indicator
{
image: none;
ads--CDockAreaWidget #tabsMenuButton::menu-indicator {
image: none;
}
ads--CDockWidgetTab
{
background: palette(window);
border-color: palette(light);
border-style: solid;
border-width: 0 1px 0 0;
padding: 0 0px;
ads--CDockWidgetTab {
background: palette(window);
border-color: palette(light);
border-style: solid;
border-width: 0 1px 0 0;
padding: 0 0px;
}
ads--CDockWidgetTab[activeTab="true"]
{
background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:0.5, stop:0 palette(window), stop:1 palette(light));
/*background: palette(highlight);*/
ads--CDockWidgetTab[activeTab="true"] {
background: qlineargradient(spread : pad, x1 : 0, y1 : 0, x2 : 0, y2 : 0.5, stop : 0
palette(window), stop:1 palette(light));
/*background: palette(highlight);*/
}
ads--CDockWidgetTab QLabel
{
color: palette(dark);
ads--CDockWidgetTab QLabel {
color: palette(dark);
}
ads--CDockWidgetTab[activeTab="true"] QLabel
{
color: palette(foreground);
ads--CDockWidgetTab[activeTab="true"] QLabel {
color: palette(foreground);
}
ads--CDockWidget
{
background: palette(light);
border-color: palette(light);
border-style: solid;
border-width: 1px 0 0 0;
ads--CDockWidget {
background: palette(light);
border-color: palette(light);
border-style: solid;
border-width: 1px 0 0 0;
}
ads--CTitleBarButton
{
ads--CTitleBarButton {
padding: 0px 0px;
}
QScrollArea#dockWidgetScrollArea
{
QScrollArea#dockWidgetScrollArea {
padding: 0px;
border: none;
}
#tabCloseButton
{
margin-top: 2px;
background: none;
border: none;
padding: 0px -2px;
#tabCloseButton {
margin-top: 2px;
background: none;
border: none;
padding: 0px -2px;
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#tabCloseButton:hover
{
border: 1px solid rgba(0, 0, 0, 32);
background: rgba(0, 0, 0, 16);
#tabCloseButton:hover {
border: 1px solid rgba(0, 0, 0, 32);
background: rgba(0, 0, 0, 16);
}
#tabCloseButton:pressed
{
background: rgba(0, 0, 0, 32);
#tabCloseButton:pressed {
background: rgba(0, 0, 0, 32);
}
#tabsMenuButton {
qproperty-icon: url(:/ads/images/tabs-menu-button.svg);
qproperty-iconSize: 16px;
}
#dockAreaCloseButton {
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#detachGroupButton {
qproperty-icon: url(:/ads/images/detach-button.svg),
url(:/ads/images/detach-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
ads--CFloatingWidgetTitleBar {
background: palette(midlight);
qproperty-maximizeIcon: url(:/ads/images/maximize-button.svg);
qproperty-normalIcon: url(:/ads/images/restore-button.svg);
}
#floatingTitleCloseButton, #floatingTitleMaximizeButton {
qproperty-iconSize: 16px;
border: none;
margin: 3px;
}
#floatingTitleCloseButton {
qproperty-icon: url(:/ads/images/close-button.svg);
}
#floatingTitleCloseButton:hover {
background: rgba(0, 0, 0, 24);
border: none;
}
#floatingTitleCloseButton:pressed {
background: rgba(0, 0, 0, 48);
}

View File

@@ -0,0 +1,125 @@
/*
* Default style sheet on Windows Platforms with focus highlighting flag enabled
*/
ads--CDockContainerWidget {
background: palette(dark);
}
ads--CDockAreaWidget {
background: palette(window);
border: 1px solid white;
}
ads--CDockWidgetTab {
background: palette(window);
border-color: palette(light);
border-style: solid;
border-width: 0 1px 0 0;
padding: 0 0px;
}
ads--CDockWidgetTab[activeTab="true"] {
background: qlineargradient(spread : pad, x1 : 0, y1 : 0, x2 : 0, y2 : 0.5, stop : 0
palette(window), stop:1 palette(light));
/*background: palette(highlight);*/
}
ads--CDockWidgetTab QLabel {
color: palette(dark);
}
ads--CDockWidgetTab[activeTab="true"] QLabel {
color: palette(foreground);
}
ads--CDockWidget {
background: palette(light);
border-color: palette(light);
border-style: solid;
border-width: 1px 0 0 0;
}
ads--CTitleBarButton {
padding: 0px 0px;
}
QScrollArea#dockWidgetScrollArea {
padding: 0px;
border: none;
}
#tabsMenuButton::menu-indicator {
image: none;
}
#tabCloseButton {
margin-top: 2px;
background: none;
border: none;
padding: 0px -2px;
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#tabCloseButton:hover {
/*border: 1px solid rgba(0, 0, 0, 32);*/
background: rgba(0, 0, 0, 24);
}
#tabCloseButton:pressed {
background: rgba(0, 0, 0, 48);
}
#dockAreaCloseButton {
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#detachGroupButton {
qproperty-icon: url(:/ads/images/detach-button.svg),
url(:/ads/images/detach-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
ads--CDockSplitter::handle {
background-color: palette(dark);
/* uncomment the following line if you would like to change the size of
the splitter handles */
/* height: 1px; */
}
/* Focus related styling */
ads--CDockWidgetTab[focused="true"] {
background: palette(highlight);
border-color: palette(highlight);
}
ads--CDockWidgetTab[focused="true"]>#tabCloseButton {
qproperty-icon: url(:/ads/images/close-button-focused.svg)
}
ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover {
background: rgba(255, 255, 255, 48);
}
ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed {
background: rgba(255, 255, 255, 92);
}
ads--CDockWidgetTab[focused="true"] QLabel {
color: palette(light);
}
ads--CDockAreaTitleBar {
background: transparent;
border-bottom: 2px solid palette(light);
padding-bottom: 0px;
}
ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar {
background: transparent;
border-bottom: 2px solid palette(highlight);
padding-bottom: 0px;
}

View File

@@ -0,0 +1,194 @@
/*
* Default style sheet on Linux Platforms with focus highlighting flag enabled
*/
ads--CDockContainerWidget {
background: palette(dark);
}
ads--CDockContainerWidget QSplitter::handle {
background: palette(dark);
}
ads--CDockAreaWidget {
background: palette(window);
border: 1px solid white;
}
ads--CDockAreaWidget #tabsMenuButton::menu-indicator {
image: none;
}
ads--CDockWidgetTab {
background: palette(window);
border-color: palette(light);
border-style: solid;
border-width: 0 1px 0 0;
padding: 0 0px;
}
ads--CDockWidgetTab[activeTab="true"] {
background: qlineargradient(spread : pad, x1 : 0, y1 : 0, x2 : 0, y2 : 0.5, stop : 0
palette(window), stop:1 palette(light));
/*background: palette(highlight);*/
}
ads--CDockWidgetTab QLabel {
color: palette(dark);
}
ads--CDockWidgetTab[activeTab="true"] QLabel {
color: palette(foreground);
}
ads--CDockWidget {
background: palette(light);
border-color: palette(light);
border-style: solid;
border-width: 1px 0 0 0;
}
ads--CTitleBarButton {
padding: 0px 0px;
}
QScrollArea#dockWidgetScrollArea {
padding: 0px;
border: none;
}
#dockAreaCloseButton {
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#detachGroupButton {
qproperty-icon: url(:/ads/images/detach-button.svg),
url(:/ads/images/detach-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#tabCloseButton {
margin-top: 2px;
background: none;
border: none;
padding: 0px -2px;
qproperty-icon: url(:/ads/images/close-button.svg),
url(:/ads/images/close-button-disabled.svg) disabled;
qproperty-iconSize: 16px;
}
#tabCloseButton:hover {
/*border: 1px solid rgba(0, 0, 0, 32);*/
background: rgba(0, 0, 0, 24);
}
#tabCloseButton:pressed {
background: rgba(0, 0, 0, 48);
}
#tabsMenuButton {
qproperty-icon: url(:/ads/images/tabs-menu-button.svg);
qproperty-iconSize: 16px;
}
/* Focus related styling */
ads--CDockWidgetTab[focused="true"] {
background: palette(highlight);
border-color: palette(highlight);
}
ads--CDockWidgetTab[focused="true"]>#tabCloseButton {
qproperty-icon: url(:/ads/images/close-button-focused.svg)
}
ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover {
background: rgba(255, 255, 255, 48);
}
ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed {
background: rgba(255, 255, 255, 92);
}
ads--CDockWidgetTab[focused="true"] QLabel {
color: palette(light);
}
ads--CDockAreaTitleBar {
background: transparent;
border-bottom: 2px solid palette(light);
padding-bottom: 0px;
}
ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar {
background: transparent;
border-bottom: 2px solid palette(highlight);
padding-bottom: 0px;
}
ads--CFloatingWidgetTitleBar {
qproperty-maximizeIcon: url(:/ads/images/maximize-button.svg);
qproperty-normalIcon: url(:/ads/images/restore-button.svg);
}
/* does not properly work on KDE
ads--CFloatingDockContainer[isActiveWindow="true"] ads--CFloatingWidgetTitleBar {
background: palette(highlight);
qproperty-maximizeIcon: url(:/ads/images/maximize-button-focused.svg);
qproperty-normalIcon: url(:/ads/images/restore-button-focused.svg);
}
ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleLabel {
color: palette(light);
}
*/
#floatingTitleCloseButton, #floatingTitleMaximizeButton {
qproperty-iconSize: 16px;
border: none;
margin: 6px 3px 6px 3px;
}
#floatingTitleCloseButton {
qproperty-icon: url(:/ads/images/close-button.svg);
}
#floatingTitleCloseButton:hover, #floatingTitleMaximizeButton:hover {
background: rgba(0, 0, 0, 24);
border: none;
}
#floatingTitleCloseButton:pressed, #floatingTitleMaximizeButton:pressed {
background: rgba(0, 0, 0, 48);
}
ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleMaximizeButton {
qproperty-iconSize: 16px;
}
/* does not properly work on KDE
ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleCloseButton {
qproperty-icon: url(:/ads/images/close-button-focused.svg);
qproperty-iconSize: 16px;
}
ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleCloseButton:hover,
ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleMaximizeButton:hover {
background: rgba(255, 255, 255, 48);
}
ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleCloseButton:pressed,
ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleMaximizeButton:pressed {
background: rgba(255, 255, 255, 92);
}
*/