Compare commits

...

308 Commits

Author SHA1 Message Date
Allen Winter
cbedc06e97 various - prep for 1.1.1 release 2020-12-11 16:56:04 -05:00
Sergio Martins
b5c2757874 Updated Changelog with v1.1.1 2020-12-11 16:36:37 +00:00
Sergio Martins
fb6e2afd7b Windows: Don't start a drag when it's a resize
There were a few pixels where you could click where, very near the
border where it would start a drag while it shouldn't.

The drag state machine then was in an invalid state which could lead to
a crash.

Fixes issue #110
2020-12-10 21:16:42 +00:00
Sergio Martins
80bf6032f3 Fix FloatingWindow's title when shown in the taskbar
The window title isn't only important when using native title bar,
it's also important for showing the correct title in the taskbar
or alt-tab.

For example, if using "minimize support", they'll show in the task bar

Fixes issue #101
2020-11-23 15:52:50 +00:00
Allen Winter
ece7b22bec apidox - fix doc for enum KDDockWidgets::Config::Flag
doxygen likes "///<"  (not "///>")

Issue#106
2020-11-22 12:17:38 -05:00
Sergio Martins
72605292b7 Don't show dock/undock icon when dockwidget is not dockable
Fixes issue #99
2020-11-13 15:51:26 +00:00
Sergio Martins
7318675e84 Clarify comment about fractionaly scalling factors
The problem can happen on Windows too.

Fixes issue #94

Nothing more we can do here, it's fixed for Qt 5.15.2.
2020-11-02 11:36:24 +00:00
Allen Winter
8a51c31663 OBS - update for 1.1.0 release 2020-10-26 12:14:46 -04:00
Sergio Martins
a586a7894b cmake: Qt5::GuiPrivate is only needed on Windows 2020-10-26 16:14:07 +00:00
Sergio Martins
31fcbebaff ChangeLog: Add the date of 1.1 release 2020-10-26 15:29:47 +00:00
Sergio Martins
392dac5691 Use Qt::WA_PendingMoveEvent instead of Qt::WA_Moved
We check if the user provided position before putting a floating
window in a default position. Qt::WA_Moved however has the problem
that it's not cleared, so second time you show a window, it will
have it, even if user didn't set geometry.

Use Qt::WA_PendingMoveEvent instead, which was made for tracking
moves made before the first show.
2020-10-23 17:07:14 +01:00
Sergio Martins
29744c01c6 ChangeLog: Added Config::setTabbingAllowedFunc 2020-10-23 10:33:37 +01:00
Sergio Martins
49e488df24 remove roadmap from 1.1 ChangeLog
We only have it for master
2020-10-23 10:29:57 +01:00
Sergio Martins
1a3f00eac8 ChangeLog: Added HDPI improvements 2020-10-23 10:29:00 +01:00
Sérgio Martins
c6ea8d5525 ChangeLog: Remove mention to 1.0.1 release
We're releasing 1.1 asap
2020-10-23 10:23:52 +01:00
Sergio Martins
8f62004f5b cmake: Remove QTQUICK option for 1.1
Leave it in master only.
2020-10-19 21:23:44 +01:00
Sergio Martins
f698b56dad relax test
Seems to happen with 5.15 static. It's benign anyway
2020-10-16 22:02:45 +01:00
Sergio Martins
4ed18fdf1d Introduce Config::setTabbingAllowedFunc(<lambda>)
This gives a lot of power to the user to disallow tabbing two dock
widgets, while still allowing them to be docked side by side. As
this can't be achieved with affinities.

Instead of adding API which might not be enough soon, just allow
the user to pass a lambda and implement his very custom requirement.

Fixes #91
2020-10-16 21:56:33 +01:00
Sergio Martins
6e05f13c77 Added FloatingWindow::dockWidgets() 2020-10-16 21:48:47 +01:00
Sergio Martins
a146cd81b2 Fix mac tests build 2020-10-16 20:52:22 +01:00
Sergio Martins
ac6d845c8d Skip tests on macOS+offscreen if Qt <= 5.15.0
There's a bug in Qt qpa only fixed in 5.15.1
2020-10-16 20:35:04 +01:00
Allen Winter
77f259a435 README.md - contact info 2020-10-15 16:06:26 -04:00
Allen Winter
7ebc3f3533 src/DockWidgetBase.h - fix compile after merge from master 2020-10-15 12:43:29 -04:00
Renato Araujo Oliveira Filho
0ee94b425e Fixed python bindings generation 2020-10-15 12:38:32 -04:00
Allen Winter
e57b46979d buildsystem - fix installation path for Python bindings 2020-10-14 16:27:18 -04:00
Allen Winter
683b67abb0 buildsystem - install libs with symlinks for the major vers 2020-10-14 15:59:53 -04:00
Allen Winter
697c140883 set version to 1.1.0 2020-10-14 10:07:48 -04:00
Sergio Martins
819725351a Fix -Wweak-vtables warnings 2020-10-14 14:55:28 +01:00
Allen Winter
07db9f9a7a cmake/Python/FindShiboken2.cmake - clean 2020-10-13 13:23:39 -04:00
Allen Winter
77d7cd7d58 buildsystem - namespace CMake options
OPTION_DEVELOPER_MODE => KDDockWidgets_DEVELOPER_MODE
OPTION_BUILD_PYTHON_BINDINGS => KDDockWidgets_PYTHON_BINDINGS
PYTHON_BINDINGS_INSTALL_PREFIX =>
  KDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX
OPTION_QTQUICK => KDDockWidgets_QTQUICK
2020-10-13 12:28:49 -04:00
Allen Winter
e5cb42c4fe CMakeLists.txt - improve installing to non-KDAB location 2020-10-13 11:32:12 -04:00
Allen Winter
1fe1d619a9 footer.html - update tag line 2020-10-13 11:30:14 -04:00
Sergio Martins
b00d1d80b0 Merge branch '1.0' into 1.1 2020-10-12 18:09:54 +01:00
Sergio Martins
67bb42c5b4 Fix infinite loop when updating title bar visibility
Not exactly infinite, just exponential growth or worse
Fixes #92
2020-10-12 18:09:32 +01:00
Allen Winter
f5099167b6 misspelling-- 2020-10-10 05:29:08 -04:00
Sergio Martins
17df7b5b4e Install DragController_p.h
Still private. It's for advanced used only.
2020-10-09 16:56:43 +01:00
Sergio Martins
15dc64d550 quick: Fix positioning windows when floating them
- Resizing the FloatingWindow wasn't resizing the QQuickView
- QQuickItems were being created as visible, while QWidgets are
created invisible. Fixed this difference in behaviour
2020-10-07 19:43:40 +01:00
Sergio Martins
03b575d16e quick: Fix MultiSplitter()::mainWindow()
Works now for QtQuick
2020-10-06 21:04:25 +01:00
Sergio Martins
4cacee45e8 Export MultiSplitter
Has powerful private api which could be useful
2020-10-06 11:03:52 +01:00
Sergio Martins
873b860203 ItemContainer: Make some getters public
They're decent private api for some very custom use cases
2020-10-06 10:53:15 +01:00
Sergio Martins
128ae2d889 Fix separators not being deleted
Bug found with QtQuick but also reproducible with QtWidgets.
Added unit-test for both stacks.
2020-10-05 18:25:33 +01:00
Sergio Martins
b0ec0e22e4 quick: Remove unused Separator.qml
We have one in multisplitter/ already
2020-10-05 17:34:27 +01:00
Sergio Martins
6aa4e979dc Added DockWidgetBase::hasPreviousDockedLocation() 2020-10-05 13:52:36 +01:00
Sergio Martins
36f225b859 Fix build with MinGW, no pragma link
Instead use cmake to link, which is cleaner anyway.

As a drive-by, remove the QtWidget check from the headers includes,
as QtQuick also needs Dwm lib
2020-10-05 03:15:36 -07:00
Sergio Martins
48a75b2450 Fix namespaced build 2020-10-05 10:21:20 +01:00
Sergio Martins
2af4f939dd tests|quick: Fix leak 2020-10-04 20:37:00 +01:00
Sergio Martins
b592d21064 quick: Also run tst_resizeWindow2 for QtQuick 2020-10-04 20:22:43 +01:00
Sergio Martins
3cdd5afe7a quick: Fix ownership of the floating view
Not nice to delete it in two places.
2020-10-04 20:16:30 +01:00
Sergio Martins
0ef56c1302 quick: Fix the overlay from minimizing windows being dragged 2020-10-04 19:41:26 +01:00
Sergio Martins
96f7f38a0e tests|quick: Set a source in the view, so we have a root item 2020-10-04 19:39:13 +01:00
Sergio Martins
689ba7da8f quick: Make dealing with window flags more stable
There's only one place where we need to set the flags, it's when
creating the FloatingWindowQuick. So no need to complex machinery
which is bug propne
2020-10-04 11:12:35 +01:00
Sergio Martins
951aeece6e quick: Make DockWidgetBase::setWidget() virtual
The QtQuick counter-part needs to do some specific things, like
settings anchors.parent: fill on it, and parenting it
2020-10-04 00:01:32 +01:00
Sergio Martins
2ea0d54e6c quick: Fix floating windows not having the correct window flags
Add a unit-test too.
2020-10-03 23:30:13 +01:00
Sergio Martins
1c98fe04ca Fix build 2020-10-03 23:11:40 +01:00
Sergio Martins
59a9ab6642 tests: Remove org.kde.desktop from warning blacklist
It's now solved by not using the kde QQC2 style. So no need to polute
the warning list
2020-10-03 23:07:49 +01:00
Sergio Martins
7ee5949ae2 tests|quick: Fix memory leaks 2020-10-03 23:07:04 +01:00
Sergio Martins
721f08e29b tests: Show the QQuickView and cleanit up
Also commit main.qml I forgot
2020-10-03 22:49:27 +01:00
Sergio Martins
df07133c9d tests: Silence some QML warnings from KDE theme plugin Kirigami
We don't want tests to abort because of that
2020-10-03 22:48:28 +01:00
Sergio Martins
b9e3024720 tst_common now passes for QtQuick
Needed a view
2020-10-03 22:10:38 +01:00
Sergio Martins
d848d3e39a MainWindow: Receive either QWidget or QQuickItem as parent
No need to receive the more complex adapters
2020-10-03 22:09:56 +01:00
Sergio Martins
3f26f4c8f2 Remove unused variable 2020-10-03 22:09:26 +01:00
Sergio Martins
dc9d709dd7 quick: Use proper icons for close and float
No more red rectangles
2020-10-03 18:55:33 +01:00
Sergio Martins
543f734650 Added DragController::enableFallbackMouseGrabber()
So it's easier to test the fallback mouse grabber
2020-10-03 18:37:26 +01:00
Sergio Martins
3fb723a82f quick: Fix QtQuick build 2020-10-03 18:27:22 +01:00
Sergio Martins
71c2f34ed4 quick: Add needed pure virtual FrameQuick::renameTab()
Not needed to have much of an impl, it's just to fix the build.
For QtQuick the tab's titles are updated via bindings
2020-10-03 18:15:56 +01:00
Sergio Martins
d4b3bf9de6 quick: Added support for showMinimized() 2020-10-03 18:11:33 +01:00
Sergio Martins
2b234f313c quick: Remove some QWidget specific code from MainWindowBase 2020-10-03 18:10:23 +01:00
Sergio Martins
d1b2d17f7d Allow the normal/restore icon to be different than float/dock
Allow we use the same icon, the user might now want to, so allow
them to use a different icon
2020-10-03 14:58:07 +01:00
Sergio Martins
f062ab7a64 TitleBar: Move button construction into the FrameWorkWidgetFactory
So it can be more easily overridden by the user.
A virtual in TitleBarWidget is not good enough as we can't call virtuals
when in the ctor
2020-10-03 14:52:44 +01:00
Sergio Martins
f009f57581 Move TitleBarButtonType next to all other enums 2020-10-03 14:29:36 +01:00
Sergio Martins
f86a818e69 TitleBar: Add an enum to describe each button type 2020-10-03 14:24:40 +01:00
Sergio Martins
bb80c2158d Fix outter_bottom_active.png
Was missing an outline for some reason
2020-10-03 13:57:32 +01:00
Sergio Martins
86fa6258f6 Comment++ 2020-10-03 13:56:51 +01:00
Sergio Martins
545536fab5 Support high-res icons when on 1.5x scaling and Qt >= 5.15.2
Icons look nice now on linux with 1.5x. Windows and macOS don't use
fractional scaling, so not affected

Fixes #11

Will open a separate bug report to get high-res docking indicators.
2020-10-03 13:21:06 +01:00
Sergio Martins
ef23553b66 Fix high-res unauto-hide icon
We had it but we were still using the old one in C++
2020-10-03 12:04:39 +01:00
Sergio Martins
fcf56664cc Add high-res icons for minimize and maximize 2020-10-03 11:50:33 +01:00
Sergio Martins
d932166bcd Add high-res icons for dock/float 2020-10-03 11:43:15 +01:00
Sergio Martins
0c5783774d Added high-res close icon 2020-10-03 11:38:26 +01:00
Sergio Martins
aa42ea15f7 Add high-res versions for auto-hide and unauto-hide png
1.5x is disabled for now, as Qt < 5.15.2 has a rounding bug
rendering them
2020-10-03 11:28:21 +01:00
Sergio Martins
9dd778d55d Pass the correct icon size when rendering a button
Needed when rendering with different scaling
2020-10-03 10:57:54 +01:00
Sergio Martins
ac35a919f4 Don't show center/tab docking indicator when there's no affinity
If the dock widget can't dock there as tabbed, don't show the
indicator
2020-10-02 17:35:15 +01:00
Sergio Martins
a32c5017e6 Minor: Remove unneeded variable 2020-10-02 17:24:50 +01:00
Sergio Martins
7995a6d13b Windows: Fix dragging sometimes not showing indicators
DragController thought there was a resize going on.
The hardcoded margins in FloatingWindow::isInDragArea() arent
needed anymore.

iPlease enter the commit message for your changes. Lines starting
2020-10-02 17:05:16 +01:00
Sergio Martins
d4ec2eec88 Windows: Added support for drop shadow for floating windows 2020-10-01 18:31:46 +01:00
Sergio Martins
12ad3b3484 Fix floating window's border, was appearing black
QPen was unused
2020-10-01 18:22:07 +01:00
Sergio Martins
9a53c36c14 Also honour affinities when dropping into a dock widget as tabbed
Fixes #89
2020-10-01 17:55:19 +01:00
Sergio Martins
8fb3802343 tests: Add an xfail for an affinities bug
This is for #89. They shouldn't be allowed to tab
together since they have different affinities

Minor refactoring in drop area so we can call DropArea::drop()
directly without having to move the mouse, as that's not relevant
for this test.
2020-10-01 17:45:53 +01:00
Sergio Martins
c035df7e85 Improve the heuristics for auto-hide prefered side bar
Now it counts the number of borders it's touching to decide.
Then checks aspect ratio too.

Can still be improved, but it's a start. Will gather feedback
before changing it further.
2020-10-01 17:16:41 +01:00
Sergio Martins
92f81e28ca Merge branch '1.0' into master 2020-10-01 11:08:39 +01:00
Sergio Martins
7a87db608b README: Updated build instructions
use cmake to call the generator, this way it's generic and
works with any generator
2020-10-01 11:07:11 +01:00
Sergio Martins
d42fb81790 Windows: Fix artifacts when dragging window to another screen
Qt does its best to honour our custom WM_NCCALCSIZE processing,
except when the window moves to another screen. So help Qt a bit
and trigger a WM_NCCALCSIZE message, which Qt intercepts and takes
notes of the custom margins.

Fixes #46
2020-09-30 22:12:40 +01:00
Sergio Martins
73934e2f90 Always call FloatingWindow::create() in the CTOR
0x051000 was a typo, as it's Qt 5.16, not 5.10.
Since it's been running fine for 5.15 for so long, let's remove
special cases and have the same path for all Qt versions.
2020-09-30 22:07:07 +01:00
Allen Winter
1c8642298b src/private/multisplitter/Item.cpp - fix compile with msvc2013
might be choking on the QStringLiteral being a lambda
used into a [] ??
2020-09-30 12:51:02 -04:00
Allen Winter
bfc45bb0e9 tst_multisplitter.cpp - add braces to make msvc2013 happy
Change-Id: I562a8b14c9c6713fc15116397b5c215138a0c9cb
2020-09-30 12:50:03 -04:00
Allen Winter
58af9e2516 tst_multisplitter.cpp - add braces to make msvc2013 happy
Change-Id: I562a8b14c9c6713fc15116397b5c215138a0c9cb
2020-09-30 09:25:01 -04:00
Sergio Martins
4228c044ea Fix false-positive caught by Coverity
It's benign
2020-09-30 10:58:36 +01:00
Sergio Martins
ccc0aec968 Remove some dead code which is no longer used 2020-09-30 10:39:04 +01:00
Sergio Martins
3718d3fe79 Silence false-positive pointed out by Coverity 2020-09-30 10:33:58 +01:00
Sergio Martins
26ed9b722b Don't allow to turn off native dragging on Windows
Native dragging is much better as Windows deals with crossing screen
boundaries, there's no reason not to want that.

Client-side moving is buggy within Qt, depending on the HDPI setting.

Fixes #86
Fixes #78
2020-09-30 09:01:09 +01:00
Sergio Martins
6751669249 Fix flaky test on 5.14, it's benign 2020-09-29 23:21:36 +01:00
Sergio Martins
c7955dce1e Update ChangeLog and README
1.1 is due out soon, won't have QtQuick yetx
2020-09-29 21:10:47 +01:00
Sergio Martins
2e432f402f Also update floating action when removing from a FloatingWindow
Fixes #79
2020-09-29 21:05:45 +01:00
Sergio Martins
07791cd901 Fix another case where floating actions weren't updated
Relates to issue #79
2020-09-29 20:50:02 +01:00
Sergio Martins
1458da92d9 minimal example: Use fusion too
Looks better in general
2020-09-29 18:10:12 +01:00
Sergio Martins
c56f998292 Use Qt::MitterJoin when drawing rectangle
As it's not the default. Otherwise there's artifacts with hdpi scaling
2020-09-29 13:38:44 +01:00
Sergio Martins
991075d69e Windows: Start a native drag as soon as possible
Native drag works much better with HDPI crossing screens.
Relates to issue #78
2020-09-29 12:39:10 +01:00
Sergio Martins
234ca75728 tests: minor: Use QCOMPARE instead of QVERIFY 2020-09-28 22:10:00 +01:00
Allen Winter
e34d62d3e5 src/private/multisplitter/Item.cpp - fix compile with msvc2013
might be choking on the QStringLiteral being a lambda
used into a [] ??
2020-09-28 16:49:59 -04:00
Allen Winter
423be28afd various - misspelling-- 2020-09-28 16:40:27 -04:00
Sergio Martins
eb7bed9601 Fix build with -Werror 2020-09-28 19:00:40 +01:00
Sergio Martins
fa09521012 Adjust unit-test, according to the latest change 2020-09-28 18:55:55 +01:00
Sergio Martins
bb30f322a3 Fix size when docking a floating window
The docked widget would have the size of the window's contents,
we should use the size of the floating window instead.

The difference is just the title bar. When docked, the title bar
belongs do Frame, while when Floating it belongs to FloatingWindow.
When doing the docking calculation the frame's title bar is still hidden

Fixes issue #84
2020-09-28 18:47:46 +01:00
Sergio Martins
0e35c93ae5 Update ChangeLog 2020-09-27 18:02:56 +01:00
Sergio Martins
603224e553 FrameWidget: Fix painting the border on HDPI
Work in floating point instead of int.
2020-09-27 18:00:15 +01:00
Sergio Martins
9b82063d52 Fix drawing the FloatingWindowWidget border on HDPI
left and top margins were smaller than bottom and right.
2020-09-27 17:49:29 +01:00
Sergio Martins
c210a523e3 Focus the newly dropped dock widget
When we drag a dock widget into a another widget, we should focus it

Fixes issue #77
2020-09-26 17:44:30 +01:00
Sergio Martins
e33151d482 Add a failing test for issue #77 2020-09-26 17:15:46 +01:00
Sergio Martins
835f67a106 Mark DropArea::drop() as private
It's an implementation detail
2020-09-26 17:08:23 +01:00
Sergio Martins
a50f6ec602 Added DockWidgetBase::isFocused Q_PROPERTY
For GammaRay convenience. For QML too.
The getter and signal already existed.

For issue #73
2020-09-25 19:35:28 +01:00
Sergio Martins
4a49dbc6b4 Add a DockWidget::isFloatingChanged() signal
For issue #73
2020-09-25 19:25:58 +01:00
Sergio Martins
05c843397b Add one more test
tabbed dock widget aren't floating either
2020-09-25 18:32:06 +01:00
Sergio Martins
e4871eb340 Fix floating action not being triggered in some cases
When docking a dock widget into a floating widget, then both
are not "floating" anymore, as there's two of them in the layout

Fixes #79
2020-09-25 18:28:32 +01:00
Sergio Martins
0e696ff2dd FloatingWindow: Also use margin when using aero-snap
It's always good to have contents margin. Initially the idea was
that we were adding margin just to make the client resize handler
work better. But no reason to have different visual aspect depending
on if you have aero-snap or not

Fixes applications needing to look the same on all platforms.
2020-09-25 11:23:03 +01:00
Sergio Martins
9f15773a9b Fix dragging by tabbar if there's a line edit in the tab bar
User was able to drag and line edit wouldn't get focus.
This is a hot fix, not the most elegant way to do it.
2020-09-25 11:02:35 +01:00
Sergio Martins
a00984f95a Fix potential crash at shutdown
QWidget DTOR can trigger a focus change, which triggers
DockRegistry::onFocusObjectChanged(), which would dereference the
dockwidget
2020-09-24 16:05:38 +01:00
Allen Winter
c7e9632f18 src/MainWindow.cpp - minor header order 2020-09-22 11:22:40 -04:00
Sergio Martins
7080712501 Rename the tab's title if its dock widget changes 2020-09-21 16:19:35 +01:00
Sergio Martins
03b574434c Fix non-developer build
Fixes #76
2020-09-21 10:07:04 +01:00
Sergio Martins
6a46744073 Make Flag_AutoHideSupport public
Ready to be tested by the public
2020-09-21 00:19:20 +01:00
Sergio Martins
7e52c510b3 Fix rendering vertical sidebars on scaled monitors 2020-09-21 00:14:09 +01:00
Sergio Martins
9bf060af9a SideBar: Support sending to West/East too
Algorithm can be made smarter, but this is good for now
2020-09-20 23:53:26 +01:00
Sergio Martins
b5973fcf8c Fix sidebar test
We're not hidding them, they just occupy 0 it seems
2020-09-20 23:50:46 +01:00
Sergio Martins
ac7d06d4fe When closing overlay, remove it from side bar too
Added test.
2020-09-20 23:46:37 +01:00
Sergio Martins
75e9137e3a Increase a bit the side of the overlays 2020-09-20 23:18:46 +01:00
Sergio Martins
5168940422 When enabling auto-hide, don't overlay it immediately
Instead, hide it. Will be overlayed when the user toggles it.
2020-09-20 23:16:40 +01:00
Sergio Martins
cfd2dafa53 Remove bogus debug 2020-09-20 23:15:01 +01:00
Sergio Martins
188b0a0edd Don't style side-bar buttons of overlayed widgets
As mouse-over is already using the same color. Would be nice
to have some different style for the currently overlayed window.
2020-09-20 23:09:33 +01:00
Sergio Martins
206c418ebc Make TitleBarWidget::buttonAreaWidth() generic
Nowadays we have much more buttons
2020-09-20 22:59:25 +01:00
Sergio Martins
b0acf8d1ae Disable floating button when using auto-hide
TitleBar is a bit crowded otherwise. User can still pass
& ~Flag_TitleBarNoFloatButton if he really wants both buttons.
2020-09-20 22:54:51 +01:00
Sergio Martins
f279ea41e6 Add tooltips to title bar buttons 2020-09-20 22:43:10 +01:00
Sergio Martins
d2a929f35d Minor whitespace fix 2020-09-20 22:26:51 +01:00
Sergio Martins
6f5258b5dd Add auto-hide iconsz 2020-09-20 22:25:56 +01:00
Sergio Martins
4f223a9439 Change color of active/hovered SideBarButton 2020-09-20 20:59:54 +01:00
Sergio Martins
ea98eb3d44 Restyle the StyleBarButtons a bit 2020-09-20 20:30:40 +01:00
Sergio Martins
cdb8f85620 Fix overlay positions when on left/right
Was off by a few pixels, looks good now
2020-09-20 19:37:53 +01:00
Sergio Martins
f459dcb8b3 length of overlayed dockwidgets now accounts for open sidebars
For example, if we're showing a bottom overlay, but the left
sidebar is visible, then the bottom overlay can't be so wide
2020-09-20 19:20:35 +01:00
Sergio Martins
967a539e71 Simplify SideBarButton::sizeHint() 2020-09-20 19:08:52 +01:00
Sergio Martins
db615da0ee Override from QToolButton to have our own SideBarButton
Has proper size when vertical.
Text isn't vertical yet though.
2020-09-20 19:06:47 +01:00
Sergio Martins
c4b420bd31 Add a fwd-header for SideBarWidget too 2020-09-20 18:09:54 +01:00
Sergio Martins
a6c4730c44 SideBar is now constructed by the framework widget factory
Means it can be overridden by the user
2020-09-20 18:08:23 +01:00
Sergio Martins
eb1f4c5a14 Auto-hide overlays when clicking elsewhere
That's what auto-hide is all about
2020-09-20 17:25:40 +01:00
Sergio Martins
b303af738c Improve position for north/south overlays 2020-09-20 16:56:57 +01:00
Sergio Martins
af5e11a265 Update the overlay's geometry when we resize the main window 2020-09-20 16:38:03 +01:00
Sergio Martins
8d7627069c Factor out some code into updateOverlayGeometry()
So it's reusable
2020-09-20 16:30:43 +01:00
Sergio Martins
9e94c0d67d The auto-hide button now works as expected
1st click it show the overlay and adds to sidebar
2nd click it hides the overlay, removes from sidebar and restores the dockwidget
2020-09-20 14:13:39 +01:00
Sergio Martins
55ddacf978 Partially revert previous commit
toggling overlay visibility won't remove it from the sidebar afterall.
User will need to explicitly press the auto-hide button
2020-09-20 13:56:52 +01:00
Sergio Martins
005e0552b6 Delete SideBarButton when dock widget is removed from sidebar 2020-09-20 13:53:49 +01:00
Sergio Martins
54b28c42e2 Added DockWidgetBase::isOverlayed() 2020-09-20 13:48:17 +01:00
Sergio Martins
2659ddb76b refactor: Decouple moveToSideBar from overlaying
overlaying just shows/hides the overlay, and not requires
the dock widget was added to the sidebar before
2020-09-20 13:44:04 +01:00
Sergio Martins
c85873c6ce Added MainWindowBase::sideBarForDockWidget(dw)
Just a getter.
2020-09-20 13:24:18 +01:00
Sergio Martins
6e32f3f915 Added SideBar::mainWindow()
It's just a getter.
2020-09-20 13:18:34 +01:00
Sergio Martins
b8891a5727 Start implementing overlaying on top of main window 2020-09-20 12:56:31 +01:00
Sergio Martins
fcb6f5a6af Use the top sidebar too 2020-09-19 12:16:51 +01:00
Sergio Martins
0365f3194d Added Item::adjacentLayoutBorders() 2020-09-19 11:50:00 +01:00
Sergio Martins
76e2ec6429 Add East, West and North sidebars too
Instead of just south.
Only south is used for now though.
2020-09-19 11:00:42 +01:00
Sergio Martins
a5d0a202a5 Add enum with sidebar location 2020-09-19 10:35:36 +01:00
Sergio Martins
def752632f tests: fix flaky test on macOS 2020-09-19 00:08:47 +01:00
Sergio Martins
f296048063 tests: Stabilize two tests on XCB
Spacings/margins are different. Anyway, that QVERIFY isn't
very important, mostly useless.
2020-09-18 23:44:34 +01:00
Sergio Martins
1c1b816292 Fix tst_maximumSizePolicy with qpa xcb 2020-09-18 23:28:14 +01:00
Sergio Martins
fbd463e18b tests: debug++ 2020-09-18 19:42:26 +01:00
Sergio Martins
9e01363648 tests: debug++ 2020-09-18 19:40:37 +01:00
Sergio Martins
67bf7e9775 tst_raise: raise the window before starting
needed on macOS
2020-09-18 19:34:09 +01:00
Sergio Martins
d8c2100b24 tests: Set object name for debugging 2020-09-18 19:30:28 +01:00
Sergio Martins
d1a3e39f17 tests: Improve debug message 2020-09-18 19:27:17 +01:00
Sergio Martins
3d5c081333 tests: Debugging a macOS failure 2020-09-18 19:24:49 +01:00
Sergio Martins
e1085fb770 Add experimental support for minimization to side-bar
Auto-hide not working yet. Just minimization.
Internal for now. Will be public once finished.
2020-09-18 18:35:41 +01:00
Sergio Martins
c294c19be7 Fix Frame having a null DropArea
Fixes inMainWindow() signal not being emitted sometimes
2020-09-18 18:34:49 +01:00
Sergio Martins
87726fb0a7 Minor style: Reduce nesting level in Frame::setDropArea() 2020-09-18 18:34:28 +01:00
Sergio Martins
d28e61f412 Minor tidying 2020-09-18 17:48:31 +01:00
Sergio Martins
890e750c23 Trying to fix Windows/MinGW build 2020-09-18 17:48:04 +01:00
Sergio Martins
1fe5cfd121 Added Frame::mainWindow() 2020-09-18 17:40:38 +01:00
Sergio Martins
c8eaf88cf1 Added DockWidgetBase::mainWindow() 2020-09-18 17:20:41 +01:00
Sergio Martins
f3f812205d Pass the new title to DockWidget::titleChanged() signal 2020-09-18 17:12:38 +01:00
Sergio Martins
7b2ec52831 Fix build on 5.9/mingw 2020-09-18 16:59:01 +01:00
Sergio Martins
72785cf869 Updated ChangeLog and README with new features and bugfixes 2020-09-17 21:54:36 +01:00
Sergio Martins
e92ef472b3 Floating windows now support a minimize button
Introduced Flag_TitleBarHasMinimizeButton for it.
It implies Flag_DontUseUtilityFloatingWindows too, since Qt::Tool
don't appear in the task bar.

example: kddockwidgets_example -k
2020-09-17 21:46:28 +01:00
Sergio Martins
deec6ffa31 Windows: Fix windows have 0 min-size
Also tested on HDPI configurations and added the device pixel ratio
into account, as Windows works in native pixels
2020-09-17 18:37:13 +01:00
Sergio Martins
47779c8d0a Fix non-native move screwing up the size when moving across screens
The drag to the 2nd monitor was native, as we detected HTCAPTION,
but the drag back to 1st monitor was non-native. Non native is not
recommended, not great with HDPI in Qt.

The bug we were mixing native pos from win32 with Qt's logical
positions.

Fixes #72
2020-09-17 09:43:38 +01:00
Allen Winter
3e9e802b6c buildsystem - do not build docs by default 2020-09-16 16:04:18 -04:00
Allen Winter
8bd429db4c buildsystem - do not build docs by default 2020-09-16 16:03:31 -04:00
Sergio Martins
d76b27863f Don't center floating window if user moved it
Fixes #75
2020-09-16 16:51:05 +01:00
Sergio Martins
576627eb17 Always outter indicators if the center is obscured with something else
If there's some other floating window over our drop zone, then it's
very difficult to drop if there's no outter indicators.

Now we'll show the outter indicators if we suspect there's some other
window obscuring
2020-09-16 12:54:09 +01:00
Sergio Martins
74adb5f021 Fix floating window's title bar not being correct
FloatingWindow::hasSingleFrame() was true, but FloatingWindow::frames()
returned 2 of them, since frames() is based on child count and it hadn't
been reparented yet

Not commiting to 1.0 since it touches the layouting engine.
All tests pass and testing showed no side effects though, so should be fine for
1.0 too

Fixes #74
2020-09-15 19:52:48 +01:00
Allen Winter
dcdcef1fb2 Merge branch '1.0' 2020-09-15 08:45:20 -04:00
Allen Winter
cf7311682e images - add svg version of logo. update other png's 2020-09-15 08:44:37 -04:00
Sergio Martins
beb2128804 example: Added --no-aero-snap for debugging purposes 2020-09-14 22:28:15 +01:00
Sergio Martins
85cb289bc4 Also focus when clicking on the current tab
Fixes issue #71
2020-09-14 21:08:48 +01:00
Sergio Martins
5293943a50 Add TabBar::frame()
Returns the Frame this TabBar is in.
2020-09-14 21:07:51 +01:00
Sergio Martins
ee4d720c51 Added test for issue #71 2020-09-14 20:54:35 +01:00
Allen Winter
f8b698e669 Merge branch '1.0' 2020-09-13 09:41:53 -04:00
Allen Winter
0e3fcc7749 update home page URL 2020-09-13 09:29:36 -04:00
Allen Winter
5755e5ff65 Doxygen - add product logo to page header and footer 2020-09-13 09:16:23 -04:00
Allen Winter
d9db3d0b29 images - add logo and banner images 2020-09-13 09:14:04 -04:00
Sergio Martins
87ba2e0ee7 example: Add option to test combinations of Qt::Tool and parent
for internal testing
2020-09-13 13:30:55 +01:00
Sergio Martins
eaeed567f3 Don't have a parent window when using Qt::Window
Otherwise Qt::Window behaves like Qt::Tool, on Windows
2020-09-13 13:22:48 +01:00
Sergio Martins
a2054359a2 Minor code move, so next diff is short 2020-09-13 12:48:25 +01:00
Sergio Martins
85b533d4c4 Minor code move 2020-09-13 12:47:04 +01:00
Sergio Martins
2d2c8524ee Introduce Config::Flag_DontUseUtilityWindowsForFloating
Controls whether windows get Qt::Tool or not
2020-09-13 12:24:26 +01:00
Sergio Martins
62271b11a7 Update .gitignore 2020-09-13 12:12:13 +01:00
Sergio Martins
869cacc568 Use mouse events for tst_titleBarFocusedWhenTabsChange
So we can test clicking on a current tab too.
Also since changing tabs programatically shouldn't change focus,
which I'll fix soon
2020-09-12 00:39:10 +01:00
Sergio Martins
0155790b02 tests: add Test::clickOn() 2020-09-12 00:33:34 +01:00
Sergio Martins
2cb25fefe4 Minor: Add the tab widget as a member 2020-09-11 23:40:41 +01:00
Sergio Martins
98225ac9a3 Fix DockWidget::isInMainWindow()
FloatingWindows are parented to the main window, so we need to stop
the loop once isWindow().

The tests didn't catch this because the floating window in the test
was created before the main window, so it truly didn't have a parent

Fixes #69
2020-09-11 22:33:25 +01:00
Sergio Martins
4bdfc35c8c Changing tabs should also activate our focus scope
Fixes #70
2020-09-09 21:03:00 +01:00
Sergio Martins
f090a51485 example: Make title bar focusable when debugging focus 2020-09-07 20:26:09 +01:00
Sergio Martins
b510c2fd5f Added DockWidget::isInMainWindow()
For task #69.
A signal would be nice too, though.
2020-09-07 15:27:54 +01:00
Sergio Martins
03e58c7443 update change log regarding issue #68 2020-09-04 17:17:23 +01:00
Sergio Martins
676086ba90 Update .gitignore 2020-09-04 17:17:23 +01:00
Sergio Martins
4f6b9e3dff update change log regarding issue #68 2020-09-04 17:16:00 +01:00
Allen Winter
c8a5bd3f15 .../quick/qml/ClassicIndicator.qml - license+copyright header 2020-09-04 12:15:31 -04:00
Sergio Martins
5e83ddf7bd Update .gitignore 2020-09-04 17:13:58 +01:00
Sergio Martins
6b28a804f8 example: Allow to demo the focus scope
set KDDW_DEBUG_FOCUS
2020-09-04 17:06:32 +01:00
Allen Winter
7c5e159677 Merge branch '1.0' 2020-09-03 18:55:08 -04:00
Allen Winter
63f8468f48 cmake/Python - don't require pkg-config, only use if available.
Issue#68
2020-09-03 18:14:14 -04:00
Allen Winter
933a535494 Merge branch '1.0' 2020-09-03 08:08:55 -04:00
Allen Winter
518a7cb398 Changelog - fix typo 2020-09-03 08:08:14 -04:00
Allen Winter
eac2cff09c Merge branch '1.0' 2020-09-03 08:07:47 -04:00
Allen Winter
9a601a5172 CMakeLists.txt, Changelog - bump to 1.0.1 2020-09-03 08:06:12 -04:00
Allen Winter
cf8f25988c Merge branch '1.0' 2020-09-03 07:58:52 -04:00
Allen Winter
a613e401e2 ready for 1.0.0 release 2020-09-02 12:29:58 -04:00
Sergio Martins
23e27ee953 Add 1.0 release date to the ChangeLog 2020-09-02 17:27:51 +01:00
Allen Winter
633dc06e6f Merge branch '1.0' 2020-09-02 11:54:06 -04:00
Allen Winter
5ddf0ada76 Changelog - reorder versions 2020-09-02 11:50:53 -04:00
Allen Winter
c8664c4d44 cmake/Python/* - sync with the KDAB toolbox 2020-09-02 11:11:29 -04:00
Allen Winter
d6d28b3f7b src/DockWidgetBase.h - minor spelling fixes 2020-09-02 11:11:06 -04:00
Allen Winter
eddcfef5d8 Merge branch '1.0' 2020-08-31 18:19:44 -04:00
Allen Winter
737d63eede CMakeLists.txt - document PYTHON_BINDINGS_INSTALL_PREFIX 2020-08-31 18:19:20 -04:00
Allen Winter
ba3890acfa Merge branch '1.0' 2020-08-31 13:22:24 -04:00
Allen Winter
9e8353f50f cmake/Python/PySide2ModuleBuild.cmake - another fix for Mac 2020-08-31 12:11:33 -04:00
Renato Araujo Oliveira Filho
2db4398637 Python/PySide2ModuleBuild.cmake - fix for Windows build 2020-08-31 11:19:04 -04:00
Allen Winter
1348434b50 docs/api/Doxyfile.cmake - remove CLANG options
to quiet the doxygen warnings:
"belongs to an option that was not enabled at compile time."
2020-08-31 11:15:47 -04:00
Sergio Martins
6cf527403e Merge branch '1.0' into master 2020-08-30 17:53:04 +01:00
Sergio Martins
92843b4972 Merge branch '1.0' into master 2020-08-30 14:46:28 +01:00
Allen Winter
b2df16dcb0 Merge branch '1.0' 2020-08-27 12:23:38 -04:00
Sergio Martins
8bb15f5447 Updated ChangeLog 2020-08-27 15:30:17 +01:00
Sergio Martins
2977f0b8c6 Introduce Config::Flag_AlwaysTitleBarWhenFloating
Allows to improve on Flag_HideTitleBarWhenTabsVisible.

Flag_HideTitleBarWhenTabsVisible will hide title bar regardless
if the window is floating or docked. By enabling Flag_AlwaysTitleBarWhenFloating
the title bar will only be hidden if docked.

Demo: ./bin/kddockwidgets_example -qt

Fixes #64
2020-08-27 15:14:55 +01:00
Sergio Martins
251423116f Merge branch '1.0' into master 2020-08-27 14:54:18 +01:00
Sergio Martins
04e2a71b66 Merge branch '1.0' into master 2020-08-25 22:00:25 +01:00
Sergio Martins
a06fec51c8 Merge branch '1.0' into master 2020-08-25 21:54:32 +01:00
Sergio Martins
83eda81263 Minor code simplification 2020-08-24 17:58:42 +01:00
Sergio Martins
1bb476ca95 Merge branch '1.0' into master 2020-08-24 14:38:06 +01:00
Sergio Martins
f0ac455ec1 Allow the window being dragged to be transparent 2020-08-23 17:44:57 +01:00
Sergio Martins
44b2fc6944 indicators: Improve style for segmented indicators 2020-08-23 17:23:37 +01:00
Sergio Martins
113e6453ea example: Show usage of segmented indicators 2020-08-23 16:57:48 +01:00
Sergio Martins
283d814dc6 indicators: Also install the headers
So that the example app can show how to switch style type
2020-08-23 16:43:54 +01:00
Sergio Martins
034dc25483 indicators: Remove type()
There's no point in using it
2020-08-23 16:22:21 +01:00
Sergio Martins
b1333b2c4c ChangeLog: Update the changelog for 1.1 2020-08-23 13:52:16 +01:00
Sergio Martins
ff58ff72f9 Merge branch '1.0' into master 2020-08-23 13:47:52 +01:00
Sergio Martins
00b4dbc821 Add a Segmented Indicator
Just a POC of a new indicator style
2020-08-23 13:24:27 +01:00
Sergio Martins
35076bbdb6 indicators: Update the indicator's visibility in the base class
So derived classes don't have to.
Doesn't affect ClassicIndicators, since it uses a separate
window for them. But useful for new indicator types.
2020-08-22 19:58:45 +01:00
Sergio Martins
2dc98804f4 qml|indicators: Use frame geometry instead of frame rect
The rect is always at 0,0, not very useful.
2020-08-22 19:53:20 +01:00
Sergio Martins
961600fe74 qtquick: fix build
MainWindow.h is specific to QtWidgets
2020-08-22 19:19:59 +01:00
Sergio Martins
7fdca76a4c indicators: Use enum class for the type 2020-08-22 19:16:24 +01:00
Sergio Martins
32592f6ad1 classic indicators: Remove unneeded hidding in ctor
Already done in base class
2020-08-22 19:13:26 +01:00
Sergio Martins
1545e98e6d Merge branch '1.0' into master 2020-08-22 18:58:42 +01:00
Allen Winter
85b3feb10b Merge branch '1.0' 2020-08-15 10:15:26 -04:00
Sergio Martins
d9fdd20caa Add DockWidgetBase::isFocusedChanged
Fixes: #60
2020-08-15 00:46:41 +01:00
Sergio Martins
9e2d001ac5 Add DockWidget::isFocused() for issue #60
Needs a signal now
2020-08-14 23:51:35 +01:00
Sergio Martins
750f9b6142 tests: Add strong-focus to the widget 2020-08-14 23:00:14 +01:00
Sergio Martins
1c3cf8cf2d Merge branch '1.0' into master 2020-08-14 18:47:42 +01:00
Sergio Martins
db19cb40d7 Merge branch '1.0' into master 2020-08-14 18:30:00 +01:00
Sergio Martins
037fa76fff Fix building user apps out of repo
Our example was being built as part of KDDW, so that worked fine.
Now it can also be built with an installed KDDW.

Problem was the folder hiearchy in the installed include dir
didn't match the folder hiearchy in the source repo

Fixes #62
2020-08-14 17:49:24 +01:00
Sergio Martins
caa2ece751 qml: Move the 1st test from tst_docks to tst_common 2020-08-13 00:46:55 +01:00
Sergio Martins
22f2975f3c tests: createMainWindow() works for qml now too 2020-08-13 00:46:55 +01:00
Sergio Martins
d3323d824a tests: Make createMainWindow return MainWindowBase
Instead of QMainWindow, so it works with qml too
2020-08-13 00:46:55 +01:00
Allen Winter
41d1ea8f61 various fixes for the OBS config 2020-08-12 18:07:40 -04:00
Sergio Martins
1e85b1e7fb tests: Share EnsureTopLevelsDeleted with qml too
So we can start to copy tests to tst_common without hacking them
2020-08-12 22:45:59 +01:00
Sergio Martins
75464708af Remove unneeded debug 2020-08-12 22:00:23 +01:00
Sergio Martins
f007451442 Fix case where floatAction() wouldn't trigger
Fixes #58
2020-08-12 21:21:04 +01:00
Allen Winter
f591270d46 CMakeLists.txt - increase numbers. this will be v1.1 some day 2020-08-12 13:00:35 -04:00
Allen Winter
390423d0c1 Merge branch '1.0' 2020-08-12 12:59:09 -04:00
Sergio Martins
1aed8c7429 Merge branch '1.0' into master 2020-08-12 11:09:06 +01:00
Sergio Martins
0aee56114b qml: Dropping a dragged window now works 2020-08-11 23:40:07 +01:00
Sergio Martins
b3ec7423e8 qml: The inner indicators are now centered 2020-08-11 22:19:51 +01:00
Sergio Martins
179cd4cf45 qml: Add properties for outter/inner indicators visibility 2020-08-11 22:19:51 +01:00
Sergio Martins
75d26c3cce qml: Draw the inner indicators too 2020-08-11 22:19:51 +01:00
Allen Winter
9071664ef2 .../ClassicIndicatorsOverlay.qml - copyright+license header 2020-08-11 08:14:00 -04:00
Sergio Martins
1980f9c42c qml: Fix namespaced build 2020-08-11 09:59:25 +01:00
Sergio Martins
2c917dcd7c qml: Show 4 proper indicators when dragging in a floating window
They don't do much yet, but at least appear.
2020-08-11 01:35:28 +01:00
Allen Winter
5ccf15b9ed Merge branch '1.0' 2020-08-10 17:07:05 -04:00
Sergio Martins
7eaac87640 qml: Add a ClassicIndicatorsOverlay.qml file
Doesn't do much yet
2020-08-10 19:05:59 +01:00
Sergio Martins
5b9f08c754 Remove mapTo/From global from Layouting::Widget
Use the ones from QWidgetAdapter instead
2020-08-10 19:05:02 +01:00
Sergio Martins
02c165163a DragController: Use the geometry of the QWindow
While this works fine for QtWidgets, where the geometry of the
top-level QWidget is the same as the QWindow, it doesn't work
for QtQuick, where the geometry of the root item starts at 0,0
2020-08-10 19:03:15 +01:00
Sergio Martins
4bbc0f1d4f qml: Create drop indicator overlay too
The actual impl isn't done yet though
2020-08-09 22:45:15 +01:00
Sergio Martins
cf692797b6 qml: ClassicIndicators are now abstracted and built
The QtQuick counterpart just needs to be implemented
2020-08-09 20:27:05 +01:00
Sergio Martins
0e4ec055b2 Remove unused function 2020-08-09 20:05:38 +01:00
Sergio Martins
cf7c25cd88 Remove old cruft "rubberBandIsTopLevel" which we don't use 2020-08-09 19:23:52 +01:00
Sergio Martins
60b5eb00a3 Move IndicatorWindow to its own file
As it's the part that will be different with QtQuick.
ClassicIndicators can be shared.
2020-08-09 19:19:31 +01:00
Sergio Martins
0705b4da72 qml: Make Indicator class a implementation detail of QtWidgets
No longer accessed by ClassicIndicators
2020-08-09 18:57:23 +01:00
Sergio Martins
09b3e685a9 IndicatorWindow: Make some members private 2020-08-09 18:53:30 +01:00
Sergio Martins
64791eec82 qml: decouple ClassicIndicator from QRubberBand
the rubber band is now returned from the factory, meaning it can
be a QQuickItem when QtQuick is being used

Still need to remove the QtWidget'isms from IndicatorWindow
though
2020-08-09 18:39:56 +01:00
Sergio Martins
dc3aa354ec Minor code styling: Remove unneeded indentation 2020-08-09 18:13:23 +01:00
Sergio Martins
890784ba5a Finish FocusScope support
When clicking on a TitleBar the focus will be redirected to either:
- Last widget that had focus inside the scope
- To the DockWidget. Implies the user setting a guest widget that
accepts focus

Fixes: #56
2020-08-08 17:34:06 +01:00
Sergio Martins
c9468bef8a example: Add some helper code to debug focus 2020-08-08 17:34:06 +01:00
Sergio Martins
0b4c017f22 qml: Add subs regarding focus 2020-08-08 17:34:06 +01:00
Sergio Martins
6de558773f Merge branch '1.0' into master 2020-08-08 17:33:53 +01:00
Sergio Martins
94258abf43 Decouple title bar icon from tab bar icon
You can now use different icons, or even just set an icon for the
title bar but not tab bar

Fixes #57
2020-08-08 14:05:42 +01:00
Sergio Martins
10026ba191 Add FocusScope behaviour to TitleBar
Github issue #56 is not a KDDW bug, it's how Qt works. QtWidgets don't
have focus scope. But let's workaround and handroll our own FocusScope.

Now the title bar can be colored differently if the dock widget it controls
contains any focused children.

This just implements half of the story. You have to focus a child
for the title bar to change color. Clicking the title bar directly
isn't done yet. Needs to be figured out. What do we focus when clicking it?
TitleBars usually don't care about keyboard focus. Probably we
just use the user's widget as a focus proxy.
2020-08-08 12:33:23 +01:00
157 changed files with 6171 additions and 935 deletions

12
.gitignore vendored
View File

@@ -6,7 +6,6 @@ Makefile
CMakeFiles
CMakeCache.txt
/examples/example
libdocks.so
tst_docks
CMakeLists.txt.user*
/build
@@ -34,7 +33,8 @@ cmake_install.cmake
latex
html
custom_titlebar
libkddockwidgets.so
libkddockwidgets.so*
libkddockwidgets_multisplitter.so*
*.depends
kddockwidgets_basic_quick
/src/KDDockWidgetsConfig.cmake
@@ -51,3 +51,11 @@ mylayout.json
*.pri
/docks-w
kddockwidgets_minimal_example
/docs/api/Doxyfile
/docs/api/qch/kddockwidgets-api.qch
/doxygen.log
/kddockwidgets.tag
/CMakeDoxyfile.in
/CMakeDoxygenDefaults.cmake
/Testing
/layout_tst*

View File

@@ -4,7 +4,7 @@
"qevent": "cpp"
},
"cmake.configureSettings": {
"OPTION_DEVELOPER_MODE" : "ON",
"OPTION_QTQUICK" : true
"KDDockWidgets_DEVELOPER_MODE" : "ON",
"KDDockWidgets_QTQUICK" : true
}
}

View File

@@ -25,18 +25,22 @@
#
# -DKDDockWidgets_DOCS=[true|false]
# Build the API documentation.
# Default=true
# Default=false
#
# -DOPTION_DEVELOPER_MODE=[true|false]
# -DKDDockWidgets_DEVELOPER_MODE=[true|false]
# Configure the build for a developer setup.
# Enables some features that are not geared towards end-users.
# Forces the test harness to be built.
# Default=false
#
# -DOPTION_BUILD_PYTHON_BINDINGS=[true|false]
# -DKDDockWidgets_PYTHON_BINDINGS=[true|false]
# Build/Generate python bindings. Always false for Debug builds
# Default=false
#
# -DKDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX=[path]
# alternative install path for python bindings
# Default=CMAKE_INSTALL_PREFIX
#
cmake_minimum_required(VERSION 3.7)
if(POLICY CMP0020)
@@ -46,10 +50,12 @@ if(POLICY CMP0042)
cmake_policy(SET CMP0042 NEW)
endif()
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
set(USE_DEFAULT_INSTALL_LOCATION True)
else()
set(USE_DEFAULT_INSTALL_LOCATION False)
set(KDAB_INSTALL True)
if((NOT DEFINED ${USE_DEFAULT_INSTALL_LOCATION}) OR (NOT ${USE_DEFAULT_INSTALL_LOCATION}))
if(NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "")
set(KDAB_INSTALL False)
endif()
set(USE_DEFAULT_INSTALL_LOCATION ${KDAB_INSTALL} CACHE INTERNAL "Install to default KDAB Location" FORCE)
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
@@ -61,25 +67,25 @@ else()
LANGUAGES CXX)
endif()
set(${PROJECT_NAME}_VERSION_MAJOR 0)
set(${PROJECT_NAME}_VERSION_MINOR 9)
set(${PROJECT_NAME}_VERSION_PATCH 99)
set(${PROJECT_NAME}_VERSION_MAJOR 1)
set(${PROJECT_NAME}_VERSION_MINOR 1)
set(${PROJECT_NAME}_VERSION_PATCH 1)
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
set(${PROJECT_NAME}_SOVERSION "1.0")
set(${PROJECT_NAME}_SOVERSION "1.1")
include(FeatureSummary)
option(OPTION_DEVELOPER_MODE "Developer Mode" OFF)
option(OPTION_BUILD_PYTHON_BINDINGS "Build python bindings" OFF)
if(OPTION_BUILD_PYTHON_BINDINGS AND (CMAKE_BUILD_TYPE MATCHES "^[Dd]eb" OR ${PROJECT_NAME}_STATIC))
option(${PROJECT_NAME}_DEVELOPER_MODE "Developer Mode" OFF)
option(${PROJECT_NAME}_PYTHON_BINDINGS "Build python bindings" OFF)
if(${PROJECT_NAME}_PYTHON_BINDINGS AND (CMAKE_BUILD_TYPE MATCHES "^[Dd]eb" OR ${PROJECT_NAME}_STATIC))
message(FATAL_ERROR "** Python Bindings are disabled in debug or static builds.")
endif()
option(${PROJECT_NAME}_TESTS "Build the tests" OFF)
option(${PROJECT_NAME}_EXAMPLES "Build the examples" ON)
option(${PROJECT_NAME}_DOCS "Build the API documentation" ON)
option(${PROJECT_NAME}_DOCS "Build the API documentation" OFF)
#Always build the test harness in developer-mode
if(OPTION_DEVELOPER_MODE)
if(${PROJECT_NAME}_DEVELOPER_MODE)
set(${PROJECT_NAME}_TESTS ON)
endif()
@@ -97,21 +103,18 @@ include(InstallLocation)
include(QtInstallPaths) #to set QT_INSTALL_FOO variables
macro(set_compiler_flags targetName)
if(OPTION_DEVELOPER_MODE)
if(${PROJECT_NAME}_DEVELOPER_MODE)
target_compile_definitions(${targetName} PRIVATE DOCKS_DEVELOPER_MODE QT_FORCE_ASSERTS)
if(NOT MSVC)
target_compile_options(${targetName} PRIVATE -Wall -Wextra -Werror -Wno-error=deprecated-declarations)
if (APPLE)
target_compile_options(${targetName} PRIVATE -Wweak-vtables)
endif()
endif()
endif()
endmacro()
if(OPTION_QTQUICK)
find_package(Qt5Quick)
find_package(Qt5QuickControls2)
add_definitions(-DKDDOCKWIDGETS_QTQUICK)
else()
add_definitions(-DKDDOCKWIDGETS_QTWIDGETS)
endif()
add_definitions(-DKDDOCKWIDGETS_QTWIDGETS)
if(${PROJECT_NAME}_STATIC)
set(${PROJECT_NAME}_LIBRARY_MODE "STATIC")
@@ -140,12 +143,12 @@ install(FILES LICENSE.txt README.md DESTINATION ${INSTALL_DOC_DIR})
install(DIRECTORY LICENSES DESTINATION ${INSTALL_DOC_DIR})
add_subdirectory(src)
if(OPTION_BUILD_PYTHON_BINDINGS)
if(${PROJECT_NAME}_PYTHON_BINDINGS)
add_subdirectory(python)
endif()
if(${PROJECT_NAME}_EXAMPLES)
if (OPTION_QTQUICK)
if (${PROJECT_NAME}_QTQUICK)
add_subdirectory(examples/qtquick)
set_compiler_flags(kddockwidgets_example_quick)
else()
@@ -156,13 +159,13 @@ if(${PROJECT_NAME}_EXAMPLES)
endif()
endif()
if(OPTION_DEVELOPER_MODE)
if(${PROJECT_NAME}_DEVELOPER_MODE)
include(ECMEnableSanitizers)
if(${PROJECT_NAME}_TESTS)
enable_testing()
add_subdirectory(tests)
if (NOT OPTION_QTQUICK)
if (NOT ${PROJECT_NAME}_QTQUICK)
#Require Qt5.15.1 or higher to run the tests_launcher tests on Mac
if(NOT APPLE OR Qt5Widgets_VERSION VERSION_GREATER 5.15.0)
# tst_docks.exe is pretty big (140 tests), so split it in 6 runs so we can use threads.

View File

@@ -1,28 +1,54 @@
* v0.1 (November 4th, 2019)
- Initial Release and blog
* v1.1.1 (11 December 2020)
- Windows: Fixed a crash when clicking on the close button for floating windows in some situations (#110)
- Don't show dock/undock icon when dockwidget is not dockable (#99)
* v1.0.0 (, 2020)
- PySide2 bindings
- Rewrote the layouting engine, resulting in a huge stability gain and makes it easy to add new features
- Honour min/max sizes and some QSizePolicy heuristics
- Lazy resize (resize only when dropping the separator)
- Native Windows dragging (supporting Aero-snap)
- Allow to hide TitleBar and just show tabs. Allow dragging via the tab bar.
- Reordering tabs with mouse
- Partial layout save/restore (affecting only a subset)
- Double-click on title bar to maximize
- Maximize button on the title bar
- HDPI: Relative layouting restore
- Allow to make a dock widget non-closable and non-dockable
- Show close button on tabs
- Multiple Main Window support
- Allowing to dock on different parents
- Support for affinities, making some dock widgets only dockable on certain main windows
- 200 unit-tests
- Fuzzer which found plenty of crashes in the old layouting engine
- ASAN fixes
- Double click on separator to distribute equally
- Hovering over an indicator returns the true size that the dropped widget will get
- Static build support
- Namespaced Qt support
- Dozens of crash fixes, bugs and much more...
* v1.1.0 (26 October 2020)
- New drop indicator style type: Segmented Indicators
- Windows: Drop Shadow for floating windows
- Added AutoHide / SideBar support
- Added FocusScope support
- Added DockWidget::isFocused() and DockWidgetBase::isFocusedChanged()
- Added Config::Flag_AlwaysTitleBarWhenFloating, which complements Flag_HideTitleBarWhenTabsVisible
- Added Config::Flag_DontUseUtilityWindowsForFloating
- Added Config::Flag_TitleBarHasMinimizeButton
- Added Config::Flag_TitleBarNoFloatButton
- Added Config::Flag_AutoHideSupport
- Added Config::setTabbingAllowedFunc(TabbingAllowedFunc func)
- HDPI improvements, new high-res icons
- Bugfixes:
- Windows: Fixed windows not having proper minimum size.
- Windows: Fixed moving windows across screens with different DPI (#72)
- Don't center floating windows if the user set a custom position (#75)
- Fixed floating window's title not being correct (#74)
- Fixed focus scope not reacting when clicking on current tab (#71)
- Fixed floating window borders not being rendered correctly on HDPI due to rounding errors.
- cmake/Python - don't require pkg-config, only use if available (#68)
* v1.0.0 (2 September 2020)
- PySide2 bindings
- Rewrote the layouting engine, resulting in a huge stability gain and makes it easy to add new features
- Honour min/max sizes and some QSizePolicy heuristics
- Lazy resize (resize only when dropping the separator)
- Native Windows dragging (supporting Aero-snap)
- Allow to hide TitleBar and just show tabs. Allow dragging via the tab bar.
- Reordering tabs with mouse
- Partial layout save/restore (affecting only a subset)
- Double-click on title bar to maximize
- Maximize button on the title bar
- HDPI: Relative layouting restore
- Allow to make a dock widget non-closable and non-dockable
- Show close button on tabs
- Multiple Main Window support
- Allowing to dock on different parents
- Support for affinities, making some dock widgets only dockable on certain main windows
- 200 unit-tests
- Fuzzer which found plenty of crashes in the old layouting engine
- ASAN fixes
- Double click on separator to distribute equally
- Hovering over an indicator returns the true size that the dropped widget will get
- Static build support
- Namespaced Qt support
- Dozens of crash fixes, bugs and much more...
* v0.1 (4 November 2019)
- Initial Release and blog

View File

@@ -1,5 +1,5 @@
KDDockWidgets
==============
=============
`KDDockWidgets` is a Qt dock widget library written by KDAB, suitable for replacing
`QDockWidget` and implementing advanced functionalities missing in Qt.
@@ -20,7 +20,7 @@ creative with their requests, so it was clear we needed a better docking framewo
You will find more information in these places:
* [our official home page](https://www.kdab.com/kddockwidgets)
* [our official home page](https://www.kdab.com/development-resources/qt-tools/kddockwidgets)
* [online detailed browsable API reference](https://docs.kdab.com/kddockwidgets)
* [our example programs](examples/)
@@ -56,15 +56,15 @@ Features
- Double click on separator to distribute equally
- Show close button on tabs
- Allow to make a dock widget non-closable and/or non-dockable
- Optional maximize button on the title bar
- Optional minimize and maximize button on the title bar
- FloatingWindows can be utility windows or full native
![Screen capture](./screencap.gif?raw=true "The docking system in action")
Roadmap
========
- QtQuick support for v1.1
- "Minimization bar" for v1.2
- QtQuick support
Trying out the examples
=======================
@@ -81,15 +81,15 @@ Build and install the KDDockWidgets framework:
```
$ cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/path/where/to/install ../path/to/kddockwidgets
$ make
$ make install
$ cmake --build .
$ cmake --build . --target install
```
Now build and run the example:
```
$ cd path/to/kddockwidgets/examples/dockwidgets/
$ cmake -DCMAKE_PREFIX_PATH=/path/where/to/install
$ make
$ cmake -G Ninja -DCMAKE_PREFIX_PATH=/path/where/to/install
$ cmake --build .
$ ./kddockwidgets_example
```
@@ -114,13 +114,13 @@ For more info visit https://doc.qt.io/qtforpython/shiboken2/gettingstarted.html
Once QtForPython is installed you are ready to generate the PySide bindings
for KDDockwWidgets.
Next pass `-DOPTION_BUILD_PYTHON_BINDINGS=ON` to CMake, followed by the
Next pass `-DKDDockWidgets_PYTHON_BINDINGS=ON` to CMake, followed by the
make command.
The bindings will be installed to the passed `-DCMAKE_INSTALL_PREFIX`, which
might require setting the `PYTHONPATH` env variable to point to that path when
running applications. Alternatively, configure the bindings install location
by passing `-DPYTHON_BINDINGS_INSTALL_PREFIX=/usr/lib/python3.8/site-packages`
by passing `-DKDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX=/usr/lib/python3.8/site-packages`
to CMake (adjust to the python path on your system).
To run the KDDW python example
@@ -170,3 +170,8 @@ to the Qt Project. We can give advanced or standard trainings anywhere
around the globe on Qt as well as C++, OpenGL, 3D and more.
Please visit https://www.kdab.com to meet the people who write code like this.
Stay up-to-date with KDAB product announcements:
* [KDAB Newsletter](https://news.kdab.com)
* [KDAB Blogs](https://www.kdab.com/category/blogs)

View File

@@ -1,6 +1,4 @@
#
# This file is part of KDDockWidgets.
#
# SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
#
@@ -15,9 +13,12 @@
# PYSIDE_TYPESYSTEMS - Type system files that should be used by other bindings extending PySide2
#
# You can install PySide2 from Qt repository with
# pip3 install --index-url=https://download.qt.io/snapshots/ci/pyside/<Qt-Version>/latest/ pyside2 --trusted-host download.qt.io
find_package(PkgConfig REQUIRED)
pkg_check_modules(PYSIDE2_PRIV pyside2 QUIET)
# pip3 install --index-url=https://download.qt.io/official_releases/QtForPython --trusted-host download.qt.io pyside2
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PYSIDE2_PRIV QUIET pyside2)
endif()
set(PYSIDE2_FOUND FALSE)

View File

@@ -1,6 +1,4 @@
#
# This file is part of KDDockWidgets.
#
# SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
#
@@ -15,9 +13,12 @@
# SHIBOKEN_BUILD_TYPE - Tells if Shiboken was compiled in Release or Debug mode.
# You can install Shiboken from Qt repository with
# pip3 install --index-url=https://download.qt.io/snapshots/ci/pyside/<Qt-Version>/latest/ shiboken2-generator --trusted-host download.qt.io
find_package(PkgConfig REQUIRED)
pkg_check_modules(SHIBOKEN2_PRIV shiboken2 QUIET)
# pip3 install --index-url=https://download.qt.io/official_releases/QtForPython --trusted-host download.qt.io shiboken2-generator
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(SHIBOKEN2_PRIV QUIET shiboken2)
endif()
set(SHIBOKEN_FOUND FALSE)
@@ -114,7 +115,6 @@ else()
set(SHIBOKEN_SEARCH_PATHS ${SHIBOKEN_CUSTOM_PATH})
list(APPEND SHIBOKEN_SEARCH_PATHS ${SHIBOKEN_BASEDIR})
list(APPEND SHIBOKEN_SEARCH_PATHS ${SHIBOKEN_GENERATOR_BASEDIR})
message(STATUS "BOO: ${SHIBOKEN_SEARCH_PATHS}")
find_file(SHIBOKEN_LIBRARY
${SHIBOKEN_LIBRARY_BASENAMES}
PATHS ${SHIBOKEN_SEARCH_PATHS}

View File

@@ -1,6 +1,4 @@
#
# This file is part of KDDockWidgets.
#
# SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
#
@@ -9,11 +7,11 @@
# Contact KDAB at <info@kdab.com> for commercial licensing options.
#
if (NOT PYTHON_BINDINGS_INSTALL_PREFIX)
SET(PYTHON_BINDINGS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE FILEPATH "Custom path to install python bindings.")
if (NOT ${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX)
SET(${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE FILEPATH "Custom path to install python bindings.")
endif()
message(STATUS "PYTHON INSTALL PREFIX ${PYTHON_BINDINGS_INSTALL_PREFIX}")
message(STATUS "PYTHON INSTALL PREFIX ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}")
if (WIN32)
set(PATH_SEP "\;")
@@ -28,9 +26,9 @@ endif()
get_target_property(QtCore_is_framework Qt5::Core FRAMEWORK)
if (QtCore_is_framework)
# Get the path to the framework dir.
list(GET Qt5Core_INCLUDE_DIRS 0 QT_INCLUDE_DIR)
get_filename_component(QT_FRAMEWORK_INCLUDE_DIR "${QT_INCLUDE_DIR}/../" ABSOLUTE)
list(GET Qt5Core_INCLUDE_DIRS 0 QT_INCLUDE_DIR)
# QT_INCLUDE_DIR points to the QtCore.framework directory, so we need to adjust this to point
# to the actual include directory, which has include files for non-framework parts of Qt.
get_filename_component(QT_INCLUDE_DIR "${QT_INCLUDE_DIR}/../../include" ABSOLUTE)
@@ -54,6 +52,15 @@ set(GENERATOR_EXTRA_FLAGS --generator-set=shiboken
--enable-return-value-heuristic
--use-isnull-as-nb_nonzero
-std=c++${CMAKE_CXX_STANDARD})
# 2017-04-24 The protected hack can unfortunately not be disabled, because
# Clang does produce linker errors when we disable the hack.
# But the ugly workaround in Python is replaced by a shiboken change.
if(WIN32 OR DEFINED AVOID_PROTECTED_HACK)
set(GENERATOR_EXTRA_FLAGS ${GENERATOR_EXTRA_FLAGS} --avoid-protected-hack)
add_definitions(-DAVOID_PROTECTED_HACK)
endif()
macro(make_path varname)
# accepts any number of path variables
string(REPLACE ";" "${PATH_SEP}" ${varname} "${ARGN}")
@@ -146,5 +153,5 @@ macro(CREATE_PYTHON_BINDINGS
LINK_FLAGS "-undefined dynamic_lookup")
endif()
install(TARGETS ${TARGET_NAME}
LIBRARY DESTINATION ${PYTHON_BINDINGS_INSTALL_PREFIX}/${TARGET_NAME})
LIBRARY DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/${TARGET_NAME})
endmacro()

View File

@@ -11,7 +11,7 @@ from conans import ConanFile, CMake, tools
class KDDockWidgetsConan(ConanFile):
name = "kddockwidgets"
version = "0.99.9"
version = "1.1.1"
default_user = "kdab"
default_channel = "stable"
license = ("https://raw.githubusercontent.com/KDAB/KDDockWidgets/master/LICENSES/GPL-2.0-only.txt",
@@ -51,7 +51,7 @@ class KDDockWidgetsConan(ConanFile):
self.cmake.definitions["KDDockWidgets_STATIC"] = self.options.build_static
self.cmake.definitions["KDDockWidgets_EXAMPLES"] = self.options.build_examples
self.cmake.definitions["KDDockWidgets_TESTS"] = self.options.build_tests
self.cmake.definitions["OPTION_BUILD_PYTHON_BINDINGS"] = self.options.build_python_bindings
self.cmake.definitions["KDDockWidgets_PYTHON_BINDINGS"] = self.options.build_python_bindings
self.cmake.configure()
self.cmake.build()

View File

@@ -1,3 +1,21 @@
kddockwidgets (1.1.1) release candidate; urgency=high
* 1.1.1 final
-- Allen Winter <allen.winter@kdab.com> Fri, 11 Dec 2020 12:00:00 -0500
kddockwidgets (1.1.0) release candidate; urgency=high
* 1.1.0 final
-- Allen Winter <allen.winter@kdab.com> Mon, 26 Oct 2020 12:00:00 -0500
kddockwidgets (1.0.0) release candidate; urgency=high
* 1.0.0 final
-- Allen Winter <allen.winter@kdab.com> Wed, 2 Sep 2020 12:00:00 -0500
kddockwidgets (0.99.9) release candidate; urgency=high
* 1.0.0 release candidate

View File

@@ -25,7 +25,7 @@ find_package(Doxygen)
set_package_properties(Doxygen PROPERTIES
TYPE OPTIONAL
DESCRIPTION "API Documentation system"
URL "http://www.doxygen.org"
URL "https://www.doxygen.org"
PURPOSE "Needed to build the API documentation."
)
if(DOXYGEN_DOT_EXECUTABLE)

View File

@@ -51,7 +51,7 @@ PROJECT_BRIEF =
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
PROJECT_LOGO = "@CMAKE_SOURCE_DIR@/images/KDDockWidgets-64x64.png"
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -1083,35 +1083,6 @@ USE_HTAGS = NO
VERBATIM_HEADERS = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
# were built. This is equivalent to specifying the "-p" option to a clang tool,
# such as clang-check. These options will then be passed to the parser.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
#TOO NEW CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
@@ -1225,7 +1196,8 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES = "@CMAKE_CURRENT_SOURCE_DIR@/kdab-logo-16x16.png"
HTML_EXTRA_FILES = "@CMAKE_CURRENT_SOURCE_DIR@/kdab-logo-16x16.png" \
"@CMAKE_CURRENT_SOURCE_DIR@/kdab-kddockwidgets-logo-16x16.png"
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to

View File

@@ -3,16 +3,16 @@
<img src="kdab-logo-16x16.png">
<font style="font-weight: bold;">Klar&auml;lvdalens Datakonsult AB (KDAB)</font>
<br>
"The Qt Experts"<br>
"The Qt, C++ and OpenGL Experts"<br>
<a href="https://www.kdab.com/">https://www.kdab.com/</a>
</div>
<div style="text-align: right;">
<!-- <img src="kddockwidgets-logo-16x16.png" /><br> -->
<img src="kdab-kddockwidgets-logo-16x16.png" />
<font style="font-weight: bold;">KDDockWidgets</font>
<br>
Advanced Dock Widget Framework for Qt<br>
<a href="https://www.kdab.com/development-resources/qt-tools/kd-dockwidgets/">https://www.kdab.com/development-resources/qt-tools/kd-dockwidgets/</a>
<a href="https://www.kdab.com/development-resources/qt-tools/kddockwidgets/">https://www.kdab.com/development-resources/qt-tools/kddockwidgets/</a>
</div>
</body>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -32,6 +32,8 @@ public:
init();
}
~MyTitleBar() override;
void init()
{
setFixedHeight(60);
@@ -41,7 +43,9 @@ public:
{
QPainter p(this);
QPen pen(Qt::black);
QBrush brush(Qt::yellow);
const QColor focusedBackgroundColor = Qt::yellow;
const QColor backgroundColor = focusedBackgroundColor.darker(115);
QBrush brush(isFocused() ? focusedBackgroundColor : backgroundColor);
pen.setWidth(4);
p.setPen(pen);
p.setBrush(brush);
@@ -54,6 +58,8 @@ public:
}
};
MyTitleBar::~MyTitleBar() = default;
// Inheriting from SeparatorWidget instead of Separator as it handles moving and mouse cursor changing
class MySeparator : public Layouting::SeparatorWidget
{
@@ -63,6 +69,8 @@ public:
{
}
~MySeparator() override;
void paintEvent(QPaintEvent *) override
{
QPainter p(this);
@@ -70,6 +78,8 @@ public:
}
};
MySeparator::~MySeparator() = default;
KDDockWidgets::TitleBar * CustomWidgetFactory::createTitleBar(KDDockWidgets::Frame *frame) const
{
return new MyTitleBar(frame);

View File

@@ -14,6 +14,7 @@
#include <QPainter>
#include <QDebug>
#include <QFile>
#include <QLineEdit>
static QHash<QString, QImage> s_images; /// clazy:exclude=non-pod-global-static
@@ -33,6 +34,15 @@ MyWidget::MyWidget(const QString &backgroundFile, const QString &logoFile, QWidg
it = s_images.insert(logoFile, QImage(logoFile));
m_logo = it.value();
}
setFocusPolicy(Qt::StrongFocus);
if (qEnvironmentVariableIsSet("KDDW_DEBUG_FOCUS")) {
// Uncomment to show focus propagation working
new QLineEdit(this);
auto l2 = new QLineEdit(this);
l2->move(0, 100);
setFocusProxy(l2);
}
}
MyWidget::~MyWidget()

View File

@@ -37,6 +37,7 @@ int main(int argc, char **argv)
parser.setApplicationDescription("KDDockWidgets example application");
parser.addHelpOption();
// Fusion looks better in general, but feel free to change
qApp->setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
QCommandLineOption customStyle("p", QCoreApplication::translate("main", "Shows how to style framework internals via FrameworkWidgetFactory"));
@@ -48,6 +49,9 @@ int main(int argc, char **argv)
QCommandLineOption noTitleBars("t", QCoreApplication::translate("main", "Hide titlebars when tabs are visible"));
parser.addOption(noTitleBars);
QCommandLineOption alwaysTitleBarWhenFloating("q", QCoreApplication::translate("main", "Don't hide title bars if floating, even if Flag_HideTitleBarWhenTabsVisible is specified."));
parser.addOption(alwaysTitleBarWhenFloating);
QCommandLineOption alwaysTabs("z", QCoreApplication::translate("main", "Show tabs even if there's only one"));
parser.addOption(alwaysTabs);
@@ -75,8 +79,17 @@ int main(int argc, char **argv)
QCommandLineOption nonDockable("d", QCoreApplication::translate("main", "DockWidget #9 will be non-dockable"));
parser.addOption(nonDockable);
QCommandLineOption maximizeButton("b", QCoreApplication::translate("main", "DockWidgets have maximize/restore buttons instead of float/dock button"));
parser.addOption(maximizeButton);
QCommandLineOption maximizeButtonOption("b", QCoreApplication::translate("main", "Floating dockWidgets have maximize/restore buttons instead of float/dock button"));
parser.addOption(maximizeButtonOption);
QCommandLineOption minimizeButtonOption("k", QCoreApplication::translate("main", "Floating dockWidgets have a minimize button. Implies not being an utility window (~Qt::Tool)"));
parser.addOption(minimizeButtonOption);
QCommandLineOption segmentedIndicators("y", QCoreApplication::translate("main", "Use segmented indicators instead of classical"));
parser.addOption(segmentedIndicators);
QCommandLineOption noUtilityWindows("u", QCoreApplication::translate("main", "FloatingWindows will be normal windows instead of utility windows"));
parser.addOption(noUtilityWindows);
parser.addPositionalArgument("savedlayout", QCoreApplication::translate("main", "loads the specified json file at startup"));
@@ -89,8 +102,22 @@ int main(int argc, char **argv)
parser.addOption(maxSizeOption);
QCommandLineOption centralFrame("f", QCoreApplication::translate("main", "Persistent central frame"));
QCommandLineOption autoHideSupport("w", QCoreApplication::translate("main", "Enables auto-hide/minimization to side-bar support"));
parser.addOption(autoHideSupport);
#if defined(DOCKS_DEVELOPER_MODE)
parser.addOption(centralFrame);
QCommandLineOption noQtTool("no-qttool", QCoreApplication::translate("main", "(internal) Don't use Qt::Tool"));
QCommandLineOption noParentForFloating("no-parent-for-floating", QCoreApplication::translate("main", "(internal) FloatingWindows won't have a parent"));
parser.addOption(noQtTool);
parser.addOption(noParentForFloating);
# if defined(Q_OS_WIN)
QCommandLineOption noAeroSnap("no-aero-snap", QCoreApplication::translate("main", "(internal) Disable AeroSnap"));
parser.addOption(noAeroSnap);
# endif
#else
Q_UNUSED(centralFrame)
#endif
@@ -104,25 +131,60 @@ int main(int argc, char **argv)
Config::self().setSeparatorThickness(10);
}
if (parser.isSet(segmentedIndicators))
KDDockWidgets::DefaultWidgetFactory::s_dropIndicatorType = KDDockWidgets::DropIndicatorType::Segmented;
MainWindowOptions options = MainWindowOption_None;
auto flags = KDDockWidgets::Config::self().flags();
#if defined(DOCKS_DEVELOPER_MODE)
options = parser.isSet(centralFrame) ? MainWindowOption_HasCentralFrame
: MainWindowOption_None;
if (parser.isSet(noQtTool))
flags |= KDDockWidgets::Config::Flag_internal_DontUseQtToolWindowsForFloatingWindows;
if (parser.isSet(noParentForFloating))
flags |= KDDockWidgets::Config::Flag_internal_DontUseParentForFloatingWindows;
# if defined(Q_OS_WIN)
if (parser.isSet(noAeroSnap))
flags &= ~KDDockWidgets::Config::Flag_AeroSnapWithClientDecos;
# endif
#endif
auto flags = KDDockWidgets::Config::self().flags();
if (parser.isSet(autoHideSupport))
flags |= Config::Flag_AutoHideSupport;
if (parser.isSet(noTitleBars))
flags |= KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible;
if (parser.isSet(noUtilityWindows))
flags |= KDDockWidgets::Config::Flag_DontUseUtilityFloatingWindows;
if (parser.isSet(alwaysTabs))
flags |= KDDockWidgets::Config::Flag_AlwaysShowTabs;
if (parser.isSet(alwaysTitleBarWhenFloating)) {
flags |= KDDockWidgets::Config::Flag_AlwaysTitleBarWhenFloating;
if (!(flags & KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible)) {
qWarning() << "Flag_AlwaysTitleBarWhenFloating is unneeded if Flag_HideTitleBarWhenTabsVisible isn't used."
<< "As floating windows already have title bars by default.";
}
}
if (parser.isSet(customStyle) || qEnvironmentVariableIsSet("KDDW_DEBUG_FOCUS"))
flags |= KDDockWidgets::Config::Flag_TitleBarIsFocusable; // also showing title bar focus with -p, just to not introduce another switch
if (parser.isSet(reorderTabsOption))
flags |= KDDockWidgets::Config::Flag_AllowReorderTabs;
if (parser.isSet(maximizeButton))
if (parser.isSet(maximizeButtonOption))
flags |= KDDockWidgets::Config::Flag_TitleBarHasMaximizeButton;
if (parser.isSet(minimizeButtonOption))
flags |= KDDockWidgets::Config::Flag_TitleBarHasMinimizeButton;
if (parser.isSet(lazyResizeOption))
flags |= KDDockWidgets::Config::Flag_LazyResize;

View File

@@ -24,6 +24,7 @@ class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget() = default;
explicit MyWidget(const QString &backgroundFile, const QString &logoFile, QWidget *parent = nullptr);
~MyWidget();
protected:

View File

@@ -14,6 +14,8 @@
#include <kddockwidgets/DockWidget.h>
#include <kddockwidgets/MainWindow.h>
#include <QStyleFactory>
// clazy:excludeall=qstring-allocations
using namespace KDDockWidgets;
@@ -27,6 +29,9 @@ int main(int argc, char **argv)
app.setOrganizationName(QStringLiteral("KDAB"));
app.setApplicationName(QStringLiteral("Test app"));
// Fusion looks better in general, but feel free to change
qApp->setStyle(QStyleFactory::create(QStringLiteral("Fusion")));
// # 1. Create our main window
KDDockWidgets::MainWindow mainWindow(QStringLiteral("MyMainWindow"));
@@ -34,10 +39,9 @@ int main(int argc, char **argv)
mainWindow.resize(1200, 1200);
mainWindow.show();
// # 2. Create four dock widgets. Each needs an unique name.
// # 2. Create a dock widget, it needs a unique name
auto dock1 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock1"));
auto widget1 = new MyWidget(QStringLiteral(":/assets/base.png"),
QStringLiteral(":/assets/KDAB_bubble_fulcolor.png"));
auto widget1 = new MyWidget();
dock1->setWidget(widget1);
auto dock2 = new KDDockWidgets::DockWidget(QStringLiteral("MyDock2"));

View File

@@ -0,0 +1,34 @@
#
# This file is part of KDDockWidgets.
#
# SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# Author: Sergio Martins <sergio.martins@kdab.com>
#
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
#
# Contact KDAB at <info@kdab.com> for commercial licensing options.
#
cmake_minimum_required(VERSION 3.7)
project(kddockwidgets_example_quick)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIRS ON)
if(NOT TARGET kddockwidgets)
# This will look for Qt, do find_package yourself manually before
# if you want to look for a specific Qt version for instance.
find_package(KDDockWidgets REQUIRED)
endif()
qt5_add_resources(RESOURCES_EXAMPLE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/resources_example.qrc)
add_executable(kddockwidgets_example_quick
main.cpp
${RESOURCES_EXAMPLE_SRC}
)
target_link_libraries(kddockwidgets_example_quick
PRIVATE
KDAB::kddockwidgets
)

View File

@@ -0,0 +1,20 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sergio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
import QtQuick 2.9
Rectangle {
color: "blue"
anchors.fill: parent
Text {
text: "Guest Widget!"
}
}

View File

@@ -0,0 +1,20 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sergio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
import QtQuick 2.9
Rectangle {
color: "lightblue"
anchors.fill: parent
Text {
text: "Guest Widget #1 !"
}
}

View File

@@ -0,0 +1,20 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sergio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
import QtQuick 2.9
Rectangle {
color: "pink"
anchors.fill: parent
Text {
text: "Guest Widget #2!"
}
}

View File

@@ -0,0 +1,20 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sergio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
import QtQuick 2.9
Rectangle {
color: "gray"
anchors.fill: parent
Text {
text: "Guest Widget #3!"
}
}

54
examples/qtquick/main.cpp Normal file
View File

@@ -0,0 +1,54 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sergio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "private/DockRegistry_p.h"
#include "private/quick/DockWidgetQuick.h"
#include "Config.h"
#include <QQuickView>
#include <QGuiApplication>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
view.setObjectName("MainWindow QQuickView");
KDDockWidgets::Config::self().setQmlEngine(view.engine());
view.resize(1000, 800);
view.show();
view.setResizeMode(QQuickView::SizeRootObjectToView);
auto dw1 = new KDDockWidgets::DockWidgetQuick("Dock #1");
view.setSource(QUrl("qrc:/main.qml"));
dw1->setWidget(QStringLiteral("qrc:/Guest1.qml"));
dw1->resize(QSize(800, 800));
dw1->show();
auto dw2 = new KDDockWidgets::DockWidgetQuick("Dock #2");
dw2->setWidget(QStringLiteral("qrc:/Guest2.qml"));
dw2->resize(QSize(800, 800));
dw2->show();
auto dw3 = new KDDockWidgets::DockWidgetQuick("Dock #3");
dw3->setWidget(QStringLiteral("qrc:/Guest3.qml"));
dw3->resize(QSize(800, 800));
dw3->show();
dw1->addDockWidgetToContainingWindow(dw3, KDDockWidgets::Location_OnRight);
KDDockWidgets::MainWindowBase *mainWindow = KDDockWidgets::DockRegistry::self()->mainwindows().constFirst();
mainWindow->addDockWidget(dw2, KDDockWidgets::Location_OnTop);
return app.exec();
}

23
examples/qtquick/main.qml Normal file
View File

@@ -0,0 +1,23 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sergio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
import QtQuick 2.6
import com.kdab.dockwidgets 1.0 as KDDW
KDDW.MainWindow {
id: root
Component.onCompleted: {
root.init("MyWindowName-1");
}
}

View File

@@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>Guest1.qml</file>
<file>Guest2.qml</file>
<file>Guest3.qml</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -0,0 +1,320 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 33.866665 33.866667"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="128x128.svg"
inkscape:export-filename="/home/pinheiro/media/server/kdab/2017/templates/Marketing/Branding/products/kddockwidgets/icons/256x256.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4182"
id="linearGradient2204"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.51735502,0,0,0.51741082,-2340.918,-1199.7217)"
x1="4533.3271"
y1="2365.7585"
x2="4573.1943"
y2="2342.7412" />
<linearGradient
inkscape:collect="always"
id="linearGradient4182">
<stop
style="stop-color:#04a5e7;stop-opacity:1;"
offset="0"
id="stop4184" />
<stop
style="stop-color:#2982c4;stop-opacity:1"
offset="1"
id="stop4186" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2202"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,0.61581147,-0.61574507,0,3061.0284,-1011.6512)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
id="linearGradient4733"
inkscape:collect="always">
<stop
id="stop4735"
offset="0"
style="stop-color:#1abafb;stop-opacity:1" />
<stop
style="stop-color:#19aff2;stop-opacity:1;"
offset="0.6658641696"
id="stop4739" />
<stop
id="stop4737"
offset="1"
style="stop-color:#187fcb;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2200"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-0.61581147,-0.61574507,0,3061.0284,1048.8936)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2198"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.22796197,0,0,0.22798656,-1029.3611,-516.35749)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
id="linearGradient2009">
<stop
style="stop-color:#f5f5f5;stop-opacity:1;"
offset="0"
id="stop2005" />
<stop
style="stop-color:#f5f5f5;stop-opacity:0;"
offset="1"
id="stop2007" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2196"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,0.22945621,-0.22945621,0,1158.704,-373.75425)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2194"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-0.097279,0.09727896,0,-449.73978,167.5063)"
x1="1632.0477"
y1="4981.3447"
x2="1693.9222"
y2="4946.9316" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2192"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.22945621,0,0,0.22945621,-1030.9526,-524.92857)"
x1="4620.3696"
y1="2304.967"
x2="4539.2959"
y2="2351.7751" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2190"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.23947392,0,0,0.23947399,-1071.1667,-551.60122)"
x1="4620.3696"
y1="2304.967"
x2="4539.2959"
y2="2351.7751" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2188"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,0.22798656,-0.22796197,0,541.76567,-1033.9073)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2186"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-0.22798656,-0.22796197,0,541.76567,1071.2141)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2184"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-0.22798656,0.22796197,0,-511.86527,1071.2141)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="107.45186"
inkscape:cy="35.577827"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="true"
units="px"
inkscape:showpageshadow="false"
inkscape:snap-global="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="false"
inkscape:snap-bbox-midpoints="false"
inkscape:snap-nodes="true"
inkscape:snap-others="false"
inkscape:snap-page="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid319"
originx="-6.9805273e-15"
originy="-6.980528e-15" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="opacity:0.04470928;fill:#050505;stroke:none;stroke-width:0.192438;stroke-linecap:square;paint-order:stroke fill markers;fill-opacity:0.03451458"
id="rect339"
width="33.866665"
height="33.866665"
x="3.4902638e-15"
y="3.4902638e-15" />
<path
id="path2172"
style="opacity:1;fill:url(#linearGradient2194);fill-opacity:1;stroke:#ffffff;stroke-width:0.189129;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="M 29.460396,6.7875213 V 2.72324 l 4.064309,4.0642813 z"
sodipodi:nodetypes="cccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<g
id="g1175"
transform="matrix(1.0177349,0,0,1.0177349,-0.15056408,-0.31430128)"
style="stroke-width:0.982574">
<path
id="path2170"
style="opacity:1;fill:url(#linearGradient2196);fill-opacity:1;stroke:#ffffff;stroke-width:0.185833;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="M 28.393217,5.3400577 V 14.926735 L 18.806543,5.3400577 Z"
sodipodi:nodetypes="cccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2192);stroke-width:0.12682;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 28.393217,5.3400577 23.61143,10.122934"
id="path2174"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</g>
<path
style="fill:none;stroke:url(#linearGradient2190);stroke-width:0.129069;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 31.506974,4.7404732 29.460396,6.7875213"
id="path2176"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<g
id="g1171"
transform="matrix(1.00156,0,0,1.0014514,0.06599202,-0.11494774)"
style="stroke-width:0.9985">
<path
id="path2162"
style="opacity:1;fill:url(#linearGradient2204);fill-opacity:1;stroke:#ffffff;stroke-width:0.187626;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="M 2.1413076,5.7567952 H 18.336441 l 9.506012,9.5070378 V 31.46073 H 2.1413076 Z"
sodipodi:nodetypes="cccccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
id="path2164"
style="opacity:0.404507;fill:url(#linearGradient2202);fill-opacity:1;stroke:none;stroke-width:0.213405;stroke-linecap:square;stroke-linejoin:round;paint-order:stroke fill markers"
d="M 27.842495,15.26388 V 31.485416 L 2.1166666,5.7568177 H 18.33646 Z"
sodipodi:nodetypes="ccccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
id="path2166"
style="opacity:0.404507;fill:url(#linearGradient2200);fill-opacity:1;stroke:none;stroke-width:0.213405;stroke-linecap:square;stroke-linejoin:round;paint-order:stroke fill markers"
d="M 27.842495,31.485416 V 15.26388 L 23.059402,10.539405 2.1166666,31.485416 Z"
sodipodi:nodetypes="ccccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2198);stroke-width:0.128043;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.086067,10.514784 -8.135893,8.138618"
id="path2168"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2188);stroke-width:0.128043;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 14.950174,18.653402 6.8124322,10.516629"
id="path2178"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2186);stroke-width:0.128043;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 14.950174,18.653402 6.8124322,26.790173"
id="path2180"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2184);stroke-width:0.128043;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 14.950174,18.653402 8.137738,8.136771"
id="path2182"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1,862 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="301.11804mm"
height="104.09705mm"
viewBox="0 0 1066.9537 368.84777"
id="svg2"
version="1.1"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="kddw.svg"
inkscape:export-filename="/home/pinheiro/media/server/kdab/2017/templates/Marketing/Branding/products/kddockwidgets/kddw.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient2009">
<stop
style="stop-color:#f5f5f5;stop-opacity:1;"
offset="0"
id="stop2005" />
<stop
style="stop-color:#f5f5f5;stop-opacity:0;"
offset="1"
id="stop2007" />
</linearGradient>
<inkscape:path-effect
pattern-nodetypes="cscscsscssc"
fuse_tolerance="0"
vertical_pattern="true"
prop_units="true"
tang_offset="0"
normal_offset="0"
spacing="0"
scale_y_rel="false"
prop_scale="0.88207218"
copytype="single_stretched"
pattern="m 4206.4067,1373.8314 c 1.1289,-1.7427 2.2338,-2.9184 2.9093,-4.8116 0.4125,-1.156 -0.031,-16.8273 0.6649,-16.8273 0.6422,0 0.2359,15.574 0.6242,16.7092 0.6713,1.9621 1.7981,3.1516 2.95,4.9297 11.1033,14.807 11.2215,45.5151 0,60.2344 -0.7017,0.9204 -1.6243,2.6721 -2.3634,4.5072 -0.7184,1.7837 -1.2634,-18.8714 -1.2634,-17.6169 0,-1.3447 -0.5565,19.2474 -1.2655,17.457 -0.7387,-1.8651 -1.6429,-3.5838 -2.2561,-4.3473 -11.7524,-14.6327 -11.1808,-45.7893 0,-60.2344 z"
is_visible="true"
id="path-effect12719"
effect="skeletal"
lpeversion="0"
hide_knot="false" />
<inkscape:path-effect
effect="skeletal"
id="path-effect12715"
is_visible="true"
pattern="m 4176.4353,1393.8123 c 1.1289,-1.7427 2.2338,-2.9184 2.9093,-4.8116 0.4125,-1.156 -0.031,-16.8273 0.665,-16.8273 0.6421,0 0.2358,15.574 0.6242,16.7092 0.6713,1.9621 1.7981,3.1516 2.95,4.9297 11.1033,14.807 11.2215,45.5151 0,60.2344 -0.7017,0.9204 -1.6244,2.6721 -2.3635,4.5072 -0.7184,1.7837 -1.2633,-18.8714 -1.2633,-17.6169 0,-1.3448 -0.5565,19.2474 -1.2656,17.457 -0.7386,-1.8651 -1.6429,-3.5839 -2.2561,-4.3473 -11.7523,-14.6327 -11.1808,-45.7893 0,-60.2344 z"
copytype="single_stretched"
prop_scale="0.88207218"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="true"
vertical_pattern="true"
fuse_tolerance="0"
pattern-nodetypes="cscscsscssc"
lpeversion="0"
hide_knot="false" />
<inkscape:path-effect
pattern-nodetypes="cscscsscssc"
fuse_tolerance="0"
vertical_pattern="true"
prop_units="true"
tang_offset="0"
normal_offset="0"
spacing="0"
scale_y_rel="false"
prop_scale="0.88207218"
copytype="single_stretched"
pattern="m 4176.4353,1398.5578 c 1.1289,-1.7428 2.2338,-2.9184 2.9093,-4.8116 0.4125,-1.1561 -0.031,-16.8273 0.665,-16.8273 0.6421,0 0.2358,15.574 0.6242,16.7092 0.6713,1.9621 1.7981,3.1515 2.95,4.9297 11.1033,14.807 11.2215,45.515 0,60.2343 -0.7017,0.9205 -1.6244,2.6722 -2.3635,4.5073 -0.7184,1.7836 -1.2633,-18.8714 -1.2633,-17.617 0,-1.3447 -0.5565,19.2475 -1.2656,17.4571 -0.7386,-1.8652 -1.6429,-3.5839 -2.2561,-4.3474 -11.7523,-14.6327 -11.1808,-45.7892 0,-60.2343 z"
is_visible="true"
id="path-effect12711"
effect="skeletal"
lpeversion="0"
hide_knot="false" />
<inkscape:path-effect
effect="skeletal"
id="path-effect12616"
is_visible="true"
pattern="m 4231.537,1404.0525 c 1.1289,-1.7427 2.2338,-2.9184 2.9093,-4.8116 0.4125,-1.156 -0.031,-16.8273 0.6649,-16.8273 0.6422,0 0.2359,15.574 0.6242,16.7092 0.6713,1.9621 1.7981,3.1516 2.95,4.9297 11.1033,14.807 11.2215,45.5151 0,60.2344 -0.7017,0.9204 -1.6243,2.6721 -2.3634,4.5072 -0.7184,1.7837 -1.2634,-18.8714 -1.2634,-17.6169 0,-1.3447 -0.5565,19.2474 -1.2655,17.457 -0.7387,-1.8651 -1.6429,-3.5838 -2.2561,-4.3473 -11.7524,-14.6327 -11.1808,-45.7893 0,-60.2344 z"
copytype="single_stretched"
prop_scale="0.88207218"
scale_y_rel="false"
spacing="0"
normal_offset="0"
tang_offset="0"
prop_units="true"
vertical_pattern="true"
fuse_tolerance="0"
pattern-nodetypes="cscscsscssc"
lpeversion="0"
hide_knot="false" />
<inkscape:path-effect
effect="ellipse_5pts"
id="path-effect12614"
is_visible="false"
lpeversion="0" />
<linearGradient
inkscape:collect="always"
id="linearGradient1176">
<stop
style="stop-color:#fdc324;stop-opacity:1"
offset="0"
id="stop1170" />
<stop
id="stop1172"
offset="0.8829243779"
style="stop-color:#fb8510;stop-opacity:1" />
<stop
style="stop-color:#fb410e;stop-opacity:1"
offset="1"
id="stop1174" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4304">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop4306" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop4308" />
</linearGradient>
<linearGradient
id="linearGradient5010"
inkscape:collect="always">
<stop
id="stop5012"
offset="0"
style="stop-color:#fdc324;stop-opacity:1" />
<stop
style="stop-color:#fb5010;stop-opacity:1;"
offset="0.8829243779"
id="stop5016" />
<stop
id="stop5014"
offset="1"
style="stop-color:#fb410e;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient4733"
inkscape:collect="always">
<stop
id="stop4735"
offset="0"
style="stop-color:#1abafb;stop-opacity:1" />
<stop
style="stop-color:#19aff2;stop-opacity:1;"
offset="0.6658641696"
id="stop4739" />
<stop
id="stop4737"
offset="1"
style="stop-color:#187fcb;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4182">
<stop
style="stop-color:#04a5e7;stop-opacity:1;"
offset="0"
id="stop4184" />
<stop
style="stop-color:#2982c4;stop-opacity:1"
offset="1"
id="stop4186" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4715">
<circle
transform="rotate(-7.0121541)"
r="21.990837"
cy="535.98236"
cx="166.16179"
id="circle4717"
style="opacity:1;fill:url(#radialGradient4719);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4182"
id="radialGradient4719"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.90375526,-0.01183805,0.01309761,0.99991422,8.8420044,1.9777154)"
cx="163.26299"
cy="524.61469"
fx="163.26299"
fy="524.61469"
r="21.990837" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4857">
<circle
transform="rotate(-7.0121541)"
r="20.994516"
cy="547.18286"
cx="257.22266"
id="circle4859"
style="opacity:1;fill:url(#radialGradient4861);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="radialGradient4861"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.85037313,-0.14640233,0.12774601,0.74200851,47.860692,172.55092)"
cx="164.63748"
cy="531.20685"
fx="164.78966"
fy="519.24323"
r="21.990837" />
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter5080"
x="-0.16258018"
width="1.3251604"
y="-0.092115037"
height="1.1842301">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="3.753083949"
id="feGaussianBlur5082" />
</filter>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath5086">
<path
style="opacity:1;fill:url(#radialGradient5090);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle5088"
transform="rotate(-7.0121541)"
r="21.2975940704"
cy="547.763061523"
cx="261.940002441"
d="" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5010"
id="radialGradient5090"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.94081295,-0.13201913,0.11519568,0.82092341,44.333431,128.77695)"
cx="164.63748"
cy="531.20685"
fx="165.19966"
fy="522.50458"
r="21.990837" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4304"
id="linearGradient4818"
gradientUnits="userSpaceOnUse"
x1="538.8783"
y1="1254.7184"
x2="538.8783"
y2="1463.9575"
gradientTransform="translate(0,-2501.2316)" />
<mask
maskUnits="userSpaceOnUse"
id="mask4814">
<rect
style="opacity:0.821;fill:url(#linearGradient4818);fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4816"
width="534.79858"
height="279.44431"
x="273.93802"
y="-1314.6536"
transform="scale(1,-1)" />
</mask>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath1276">
<circle
style="opacity:1;fill:url(#radialGradient1280);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle1278"
cx="440.63205"
cy="722.66998"
r="85.281738"
transform="rotate(-7.0121541)" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient1176"
id="radialGradient1280"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(4.6443382,-1.2687174,1.1434364,4.1857275,-939.86166,-1313.7824)"
cx="163.84512"
cy="535.58044"
fx="164.13194"
fy="524.82343"
r="21.990837" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath1713">
<path
style="opacity:1;fill:url(#radialGradient1717);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 518.8522,558.0521 c -0.82495,-10e-4 -1.65149,0.008 -2.48033,0.0264 -3.44325,0.0774 -6.88048,0.32689 -10.29881,0.7477 -5.92658,0.72912 -17.20559,3.60819 -17.20559,3.60819 l 6.91055,14.03625 c 0,0 8.00571,-1.85496 12.17321,-2.3677 2.90897,-0.35809 5.83402,-0.57046 8.76419,-0.63629 45.14453,-1.01173 82.94959,34.62 86.4993,76.24601 4.23839,49.70191 -36.47733,87.05581 -73.79756,91.14458 -0.12198,-4.28104 75.73972,20.55263 91.79648,-92.08877 -6.37636,-51.85265 -50.39015,-90.64928 -102.36144,-90.7164 z"
id="path1715"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sccccccsccs" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient1176"
id="radialGradient1717"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(6.0139763,-1.6118698,1.4523165,5.4215643,-1286.7694,-2022.8268)"
cx="163.84512"
cy="535.58044"
fx="164.13194"
fy="524.82343"
r="21.990837" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath1545">
<rect
style="opacity:1;fill:#eff0f1;fill-opacity:1;fill-rule:nonzero;stroke:#fcfcfc;stroke-width:1.84406;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect1547"
width="499.94531"
height="626.17499"
x="1503.0391"
y="115.11468" />
</clipPath>
<style
id="current-color-scheme"
type="text/css">
.ColorScheme-Text {
color:#f2f2f2;
}
</style>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2129">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.91875;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2131"
width="90.85743"
height="216.4682"
x="-4259.5063"
y="1335.9559"
ry="0.79583901"
transform="scale(-1,1)" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3852">
<rect
style="opacity:0.547;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#bb0000;stroke-width:1.10063;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3854"
width="117.72582"
height="199.94704"
x="-5563.061"
y="1545.0594"
ry="0.52556229"
transform="scale(-1,1)" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2142">
<path
style="opacity:0.892;fill:none;fill-opacity:0;fill-rule:nonzero;stroke:#fffafa;stroke-width:0.344063;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.374332;paint-order:markers fill stroke"
d="m 3696.4014,591.63757 v 219.42444 h 177.3285 V 591.63757 Z m 103.6395,111.05164 c 3.718,0 7.1638,0.70279 10.2319,2.15515 a 2.6924666,2.6924666 0 0 1 1.3074,3.53028 l -0.9723,2.18078 a 2.6924666,2.6924666 0 0 1 -3.6639,1.31104 c -2.1746,-1.08732 -4.3873,-1.61133 -6.7621,-1.61133 -3.7727,0 -6.2834,1.07384 -8.2617,3.27759 -1.9791,2.20458 -3.0579,5.25668 -3.0579,9.62951 0,4.51996 1.0495,7.63935 2.8803,9.76502 1.8165,2.10909 4.2427,3.16772 8.0603,3.16772 2.6784,0 5.0788,-0.34226 7.2271,-0.99792 a 2.6924666,2.6924666 0 0 1 3.4772,2.57446 v 2.13318 a 2.6924666,2.6924666 0 0 1 -1.7981,2.53967 c -2.6875,0.94525 -5.8344,1.36231 -9.4757,1.36231 -5.4481,0 -10.197,-1.89711 -13.5095,-5.62134 -3.3288,-3.74252 -4.8761,-8.88316 -4.8761,-14.9707 0,-3.86297 0.736,-7.40293 2.2705,-10.50843 a 2.6924666,2.6924666 0 0 1 0.01,-0.0128 c 1.5539,-3.10779 3.8721,-5.61989 6.8097,-7.33155 2.9591,-1.73083 6.391,-2.57263 10.1074,-2.57263 z m -48.219,0.35706 h 1.5418 a 2.6924666,2.6924666 0 0 1 2.5067,1.70837 l 13.656,34.80286 a 2.6924666,2.6924666 0 0 1 -2.5067,3.67492 h -2.7265 a 2.6924666,2.6924666 0 0 1 -2.5049,-1.70654 l -4.1418,-10.52673 h -10.4169 l -4.1656,10.53222 a 2.6924666,2.6924666 0 0 1 -2.5031,1.70105 h -2.6788 a 2.6924666,2.6924666 0 0 1 -2.4994,-3.69323 l 13.9398,-34.80286 a 2.6924666,2.6924666 0 0 1 2.4994,-1.69006 z m 77.2083,0.14099 h 2.4188 a 2.6924666,2.6924666 0 0 1 2.6916,2.69165 v 11.48437 l 12.7881,-13.34655 a 2.6924666,2.6924666 0 0 1 1.9446,-0.82947 h 3.0835 a 2.6924666,2.6924666 0 0 1 1.9336,4.56482 l -12.6251,13.02429 13.2458,18.17871 a 2.6924666,2.6924666 0 0 1 -2.1753,4.27734 h -2.9645 a 2.6924666,2.6924666 0 0 1 -2.1771,-1.10962 l -11.5594,-15.9082 -1.4942,1.31653 v 13.00964 a 2.6924666,2.6924666 0 0 1 -2.6916,2.69165 h -2.4188 a 2.6924666,2.6924666 0 0 1 -2.6917,-2.69165 v -34.66186 a 2.6924666,2.6924666 0 0 1 2.6917,-2.69165 z m -76.4942,14.30786 -2.3181,5.93994 h 4.5612 z"
id="path2144"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4182"
id="linearGradient1962"
x1="4533.3271"
y1="2365.7585"
x2="4573.1943"
y2="2342.7412"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(3.753257,0,0,3.753257,-16367.842,-8500.4241)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient1977"
gradientUnits="userSpaceOnUse"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415"
gradientTransform="matrix(0,1.6537964,-1.6537964,0,8966.582,-2491.3872)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient1983"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,4.4670474,-4.4670474,0,22821.673,-7136.1767)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient1987"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-4.4670474,-4.4670474,0,22821.673,7810.8518)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient1991"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-0.6718043,0.6718042,0,-2481.8694,1362.3567)"
x1="1632.0477"
y1="4981.3447"
x2="1693.9222"
y2="4946.9316" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2011"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.6537964,0,0,1.6537964,-6852.8864,-3543.355)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2016"
gradientUnits="userSpaceOnUse"
x1="4620.3696"
y1="2304.967"
x2="4539.2959"
y2="2351.7751"
gradientTransform="matrix(1.6537964,0,0,1.6537964,-6815.2795,-3580.97)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2024"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.6537964,0,0,1.6537964,-6773.4163,-3603.767)"
x1="4620.3696"
y1="2304.967"
x2="4539.2959"
y2="2351.7751" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2028"
gradientUnits="userSpaceOnUse"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162"
gradientTransform="matrix(0,1.6537964,-1.6537964,0,4545.1713,-7297.62)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2032"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.6537964,-1.6537964,0,4545.1714,7972.7634)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2036"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.6537964,1.6537964,0,-3098.608,7972.7634)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2184"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-2.6306245,2.6306245,0,-4989.2651,12512.226)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2186"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-2.6306245,-2.6306245,0,7169.374,12512.226)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2188"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,2.6306245,-2.6306245,0,7169.3738,-11777.732)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2190"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.6306245,0,0,2.6306245,-10834.629,-5902.075)"
x1="4620.3696"
y1="2304.967"
x2="4539.2959"
y2="2351.7751" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2192"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.6306245,0,0,2.6306245,-10901.219,-5865.8128)"
x1="4620.3696"
y1="2304.967"
x2="4539.2959"
y2="2351.7751" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2194"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-1.0686109,1.0686107,0,-4008.2449,1997.3295)"
x1="1632.0477"
y1="4981.3447"
x2="1693.9222"
y2="4946.9316" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2196"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,2.6306245,-2.6306245,0,14202.326,-4132.6592)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2009"
id="linearGradient2198"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.6306245,0,0,2.6306245,-10961.038,-5805.9802)"
x1="4620.3696"
y1="2304.967"
x2="4567.6602"
y2="2342.3162" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2200"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-7.1055448,-7.1055448,0,36241.038,12254.68)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4733"
id="linearGradient2202"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,7.1055448,-7.1055448,0,36241.038,-11520.931)"
x1="1710.802"
y1="4975.228"
x2="1652.1422"
y2="4926.0415" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4182"
id="linearGradient2204"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(5.9701483,0,0,5.9701483,-26096.079,-13690.983)"
x1="4533.3271"
y1="2365.7585"
x2="4573.1943"
y2="2342.7412" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="1020.3148"
inkscape:cy="-114.96383"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1714"
inkscape:window-height="1203"
inkscape:window-x="552"
inkscape:window-y="164"
inkscape:window-maximized="0"
inkscape:object-nodes="true"
inkscape:snap-global="true"
inkscape:snap-page="false"
inkscape:lockguides="false"
inkscape:document-rotation="0"
fit-margin-top="30"
fit-margin-left="30"
fit-margin-bottom="30"
fit-margin-right="30">
<inkscape:grid
type="xygrid"
id="grid1761"
originx="151.86636"
originy="-166.49869" />
<sodipodi:guide
position="4396.866,-873.03128"
orientation="0,1"
id="guide12660"
inkscape:locked="false" />
<sodipodi:guide
position="4356.202,-851.11722"
orientation="1,0"
id="guide12666"
inkscape:locked="false" />
<sodipodi:guide
position="4387.784,-904.14456"
orientation="0,1"
id="guide12692"
inkscape:locked="false" />
<sodipodi:guide
position="4386.9051,-921.42972"
orientation="1,0"
id="guide12694"
inkscape:locked="false" />
<sodipodi:guide
position="4372.1395,-876.42972"
orientation="1,0"
id="guide12696"
inkscape:locked="false" />
<sodipodi:guide
position="968.67798,222.36216"
orientation="-0.70710678,-0.70710678"
id="guide2114" />
</sodipodi:namedview>
<metadata
id="metadata7">
<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>
<g
inkscape:label="Camada 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(151.86636,-166.4987)">
<path
clip-path="url(#clipPath5086)"
sodipodi:nodetypes="cscssscscccscc"
inkscape:connector-curvature="0"
id="path5279"
d="m 338.65051,492.26754 6.78652,6.38162 c 3.12988,2.94314 3.15859,8.98109 1.39414,16.79863 -2.23777,8.35146 -8.50357,13.53359 -15.111,15.04217 -6.31742,1.44237 -13.30427,-0.34272 -17.90992,-4.61744 -1.44603,-1.34212 -2.21872,-3.81133 -1.67407,-5.84402 0.60965,-2.27523 0.73619,-5.45316 2.06641,-6.24219 -0.76814,0.26722 -1.70405,0.57479 -2.82422,1.63086 -1.88644,1.77848 -1.96369,4.28221 -4.42969,4.97266 0.25165,-7.08965 -4.15819,-10.96822 -4.46346,-14.11351 -2.9188,16.12091 12.65231,34.52007 31.91417,29.35887 12.41302,-3.09834 19.81219,-12.21234 22.25881,-22.50042 1.41285,-5.94104 0.97674,-12.06732 -0.30664,-17.20899 z"
style="opacity:0.656;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter5080)"
transform="translate(0,171.82695)" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.75px;line-height:125%;font-family:'Helvetica Neue LT Std';-inkscape-font-specification:'Helvetica Neue LT Std, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="5413.5938"
y="1750.3309"
id="text3551" />
<flowRoot
xml:space="preserve"
id="flowRoot3585"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:'Helvetica Neue LT Std';-inkscape-font-specification:'Helvetica Neue LT Std, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion
id="flowRegion3587"><rect
id="rect3589"
width="638"
height="558"
x="7608"
y="2084.51977539" /></flowRegion><flowPara
id="flowPara3591" /></flowRoot>
<flowRoot
xml:space="preserve"
id="flowRoot3593"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:'Helvetica Neue LT Std';-inkscape-font-specification:'Helvetica Neue LT Std, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"><flowRegion
id="flowRegion3595"><rect
id="rect3597"
width="1124"
height="944"
x="6470"
y="1612.51965332" /></flowRegion><flowPara
id="flowPara3599" /></flowRoot>
<path
id="rect1131"
style="opacity:1;fill:url(#linearGradient1962);fill-opacity:1;stroke:#ffffff;stroke-width:0.68156246;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="m 630.35714,244.02067 h 117.49083 l 68.9633,68.9633 v 117.491 H 630.35714 Z"
sodipodi:nodetypes="cccccc" />
<path
id="path1981"
style="opacity:0.404507;fill:url(#linearGradient1983);fill-opacity:1;stroke:none;stroke-width:0.775215;stroke-linecap:square;stroke-linejoin:round;paint-order:stroke fill markers"
d="m 816.8116,312.98431 v 117.66976 l -186.63323,-186.63323 117.66977,0 z"
sodipodi:nodetypes="ccccc" />
<path
id="path1985"
style="opacity:0.404507;fill:url(#linearGradient1987);fill-opacity:1;stroke:none;stroke-width:0.775215;stroke-linecap:square;stroke-linejoin:round;paint-order:stroke fill markers"
d="M 816.8116,430.65407 V 312.98431 L 782.11165,278.71335 630.17837,430.65407 Z"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:url(#linearGradient2011);stroke-width:0.46513;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 782.30514,278.53475 -59.0235,59.03688"
id="path2003"
sodipodi:nodetypes="cc" />
<path
id="path1975"
style="opacity:1;fill:url(#linearGradient1977);fill-opacity:1;stroke:#ffffff;stroke-width:0.68156246;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="m 819.91214,240.91981 v 69.0956 l -69.09561,-69.0956 z"
sodipodi:nodetypes="cccc" />
<path
id="path1989"
style="opacity:1;fill:url(#linearGradient1991);fill-opacity:1;stroke:#ffffff;stroke-width:0.68156246;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1;paint-order:stroke fill markers;stroke-miterlimit:4;stroke-dasharray:none"
d="m 827.46585,252.44015 v -28.06774 l 28.06807,28.06774 z"
sodipodi:nodetypes="cccc" />
<path
style="fill:none;stroke:url(#linearGradient2016);stroke-width:0.46513;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 819.91214,240.91981 785.44752,275.3922"
id="path2014"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:url(#linearGradient2024);stroke-width:0.46513;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 841.59952,238.30333 -14.13367,14.13682"
id="path2022"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:url(#linearGradient2028);stroke-width:0.46513;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 723.28164,337.57163 -59.03688,-59.0235"
id="path2026"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:url(#linearGradient2032);stroke-width:0.46513;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 723.28164,337.57163 -59.03688,59.0235"
id="path2030"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:url(#linearGradient2036);stroke-width:0.46513;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 723.28164,337.57163 59.0369,59.0235"
id="path2034"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:93.0993px;line-height:125%;font-family:'Helvetica Neue LT Std';-inkscape-font-specification:'Helvetica Neue LT Std, Normal';text-align:start;letter-spacing:6.17598px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#292929;fill-opacity:1;stroke:none;stroke-width:8.58756px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-81.289284"
y="449.83054"
id="text2108"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><tspan
sodipodi:role="line"
id="tspan2106"
x="-81.289284"
y="449.83054"
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Light';letter-spacing:6.17598px;word-spacing:10.7995px;fill:#292929;fill-opacity:1;stroke-width:8.58756px">KDDockWidgets</tspan></text>
<path
id="path2162"
style="opacity:1;fill:url(#linearGradient2204);fill-opacity:1;stroke:#ffffff;stroke-width:1.08414;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="M 942.24318,218.43936 H 1129.131 l 109.697,109.69702 v 186.888 H 942.24318 Z"
sodipodi:nodetypes="cccccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
id="path2164"
style="opacity:0.404507;fill:url(#linearGradient2202);fill-opacity:1;stroke:none;stroke-width:1.2331;stroke-linecap:square;stroke-linejoin:round;paint-order:stroke fill markers"
d="M 1238.8285,328.13692 V 515.30927 L 941.95882,218.43962 h 187.17238 z"
sodipodi:nodetypes="ccccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
id="path2166"
style="opacity:0.404507;fill:url(#linearGradient2200);fill-opacity:1;stroke:none;stroke-width:1.2331;stroke-linecap:square;stroke-linejoin:round;paint-order:stroke fill markers"
d="M 1238.8285,515.30927 V 328.13692 l -55.1957,-54.51338 -241.67398,241.68573 z"
sodipodi:nodetypes="ccccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2198);stroke-width:0.739863;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1183.9405,273.33945 -93.8862,93.90749"
id="path2168"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
id="path2170"
style="opacity:1;fill:url(#linearGradient2196);fill-opacity:1;stroke:#ffffff;stroke-width:1.08414;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="M 1243.7603,213.50695 V 323.41441 L 1133.8529,213.50695 Z"
sodipodi:nodetypes="cccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
id="path2172"
style="opacity:1;fill:url(#linearGradient2194);fill-opacity:1;stroke:#ffffff;stroke-width:1.08414;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="m 1255.7759,231.83187 v -44.64618 l 44.6465,44.64618 z"
sodipodi:nodetypes="cccc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2192);stroke-width:0.739863;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1243.7603,213.50695 -54.8213,54.83378"
id="path2174"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2190);stroke-width:0.739863;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1278.2576,209.34502 -22.4817,22.48685"
id="path2176"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2188);stroke-width:0.739863;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1090.0543,367.24694 -93.90751,-93.8862"
id="path2178"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2186);stroke-width:0.739863;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1090.0543,367.24694 -93.90751,93.8862"
id="path2180"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:url(#linearGradient2184);stroke-width:0.739863;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1090.0543,367.24694 93.9075,93.8862"
id="path2182"
sodipodi:nodetypes="cc"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,10 +1,10 @@
Format: 1.0
Source: kddockwidgets
Version: 0.99.9
Version: 1.1.1-1
Binary: kddockwidgets
Maintainer: Allen Winter <allen.winter@kdab.com>
Architecture: any
Build-Depends: debhelper (>=9), cdbs, cmake, qt5-default, qtbase5-dev, libqt5x11extras5-dev
Files:
00000000000000000000000000000000 00000 kddockwidgets-0.99.9.tar.gz
00000000000000000000000000000000 00000 kddockwidgets-1.1.1.tar.gz

View File

@@ -1,5 +1,5 @@
Name: kddockwidgets
Version: 0.99.9
Version: 1.1.1
Release: 1
Summary: KDAB's Dock Widget Framework for Qt
Source0: %{name}-%{version}.tar.gz
@@ -88,5 +88,11 @@ cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
%{_libdir}/libkddockwidgets_multisplitter.so
%changelog
* Thu Aug 06 2020 Allen Winter <allen.winter@kdb.com> 0.99.9
* Fri Dec 11 2020 Allen Winter <allen.winter@kdab.com> 1.1.1
1.1.1 final
* Mon Oct 26 2020 Allen Winter <allen.winter@kdab.com> 1.1.0
1.1.0 final
* Wed Sep 02 2020 Allen Winter <allen.winter@kdab.com> 1.0.0
1.0.0 final
* Thu Aug 06 2020 Allen Winter <allen.winter@kdab.com> 0.99.9
1.0.0 release candidate

View File

@@ -74,8 +74,8 @@ create_python_bindings(
${CMAKE_CURRENT_BINARY_DIR}
)
# Make moduled import from build dir works
# Make module import from build dir work
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${CMAKE_CURRENT_BINARY_DIR}/__init__.py)
# install
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py DESTINATION ${PYTHON_BINDINGS_INSTALL_PREFIX}/PyKDDockWidgets)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/PyKDDockWidgets)

View File

@@ -11,6 +11,7 @@
<!-- this is used in a public virtual pure function we need to declare it
otherwise shiboken will ignore the function and will fail to create a wrapper -->
<primitive-type name="DropAreaWithCentralFrame"/>
<primitive-type name="SideBar"/>
<!-- Some plublic enum and flags -->
<enum-type name="Location"/>
@@ -19,6 +20,9 @@
<enum-type name="RestoreOption" flags="RestoreOptions"/>
<enum-type name="DefaultSizeMode"/>
<enum-type name="FrameOption" flags="FrameOptions"/>
<enum-type name="DropIndicatorType"/>
<enum-type name="SideBarLocation"/>
<enum-type name="TitleBarButtonType"/>
<!-- our classes
For class we can use two types:
@@ -32,6 +36,7 @@
<!-- this class contains a internal enum, so it should be declared
inside of the object-type -->
<enum-type name="Option" flags="Options" />
<enum-type name="IconPlace" flags="IconPlaces" />
</object-type>
<object-type name="DockWidget" />

View File

@@ -24,6 +24,7 @@ add_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS
set(DOCKSLIBS_SRCS
Config.cpp
Qt5Qt6Compat_p.h
FocusScope.cpp
FrameworkWidgetFactory.cpp
DockWidgetBase.cpp
MainWindowBase.cpp
@@ -36,6 +37,7 @@ set(DOCKSLIBS_SRCS
private/FloatingWindow.cpp
private/Logging.cpp
private/TitleBar.cpp
private/SideBar.cpp
private/DockRegistry.cpp
private/Draggable.cpp
private/WindowBeingDragged.cpp
@@ -43,6 +45,8 @@ set(DOCKSLIBS_SRCS
private/Frame.cpp
private/DropAreaWithCentralFrame.cpp
private/WidgetResizeHandler.cpp
private/indicators/ClassicIndicators.cpp
private/indicators/ClassicIndicatorsWindow.cpp
)
set(DOCKS_INSTALLABLE_INCLUDES
@@ -51,22 +55,27 @@ set(DOCKS_INSTALLABLE_INCLUDES
FrameworkWidgetFactory.h
DockWidgetBase.h
KDDockWidgets.h
FocusScope.h
QWidgetAdapter.h
LayoutSaver.h
LayoutSaver_p.h
)
set(DOCKS_INSTALLABLE_PRIVATE_INCLUDES
private/DragController_p.h
private/Draggable_p.h
private/DropIndicatorOverlayInterface_p.h
private/FloatingWindow_p.h
private/Frame_p.h
private/SideBar_p.h
private/TitleBar_p.h
private/WindowBeingDragged_p.h
)
set(DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES
private/widgets/QWidgetAdapter_widgets_p.h
private/widgets/TitleBarWidget_p.h
private/widgets/SideBarWidget_p.h
private/widgets/FloatingWindowWidget_p.h
private/widgets/FrameWidget_p.h
private/widgets/TabBarWidget_p.h
@@ -74,7 +83,7 @@ set(DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES
private/widgets/TabWidget_p.h
)
if(OPTION_QTQUICK)
if(${PROJECT_NAME}_QTQUICK)
set(DOCKSLIBS_SRCS ${DOCKSLIBS_SRCS}
private/quick/DockWidgetQuick.cpp
private/quick/QWidgetAdapter_quick.cpp
@@ -95,11 +104,12 @@ else()
private/widgets/TabBarWidget.cpp
private/widgets/FloatingWindowWidget.cpp
private/widgets/FrameWidget.cpp
private/widgets/SideBarWidget.cpp
private/widgets/TabWidgetWidget.cpp
private/widgets/TitleBarWidget.cpp
private/widgets/DockWidget.cpp
private/widgets/QWidgetAdapter_widgets.cpp
private/indicators/ClassicIndicators.cpp
private/indicators/SegmentedIndicators.cpp
# private/indicators/AnimatedIndicators.cpp
)
@@ -157,18 +167,24 @@ if(CMAKE_COMPILER_IS_GNUCXX OR IS_CLANG_BUILD)
endif()
endif()
if(OPTION_QTQUICK)
if(${PROJECT_NAME}_QTQUICK)
target_link_libraries(kddockwidgets PUBLIC Qt5::Widgets Qt5::Quick Qt5::QuickControls2 kddockwidgets_multisplitter)
else()
target_link_libraries(kddockwidgets PUBLIC Qt5::Widgets kddockwidgets_multisplitter)
endif()
if(NOT WIN32 AND NOT APPLE)
find_package(Qt5X11Extras)
target_link_libraries(kddockwidgets PUBLIC Qt5::X11Extras)
if (WIN32)
target_link_libraries(kddockwidgets PRIVATE Qt5::GuiPrivate Dwmapi)
elseif(NOT APPLE)
find_package(Qt5X11Extras)
target_link_libraries(kddockwidgets PUBLIC Qt5::X11Extras)
endif()
set_target_properties(kddockwidgets PROPERTIES VERSION ${${PROJECT_NAME}_SOVERSION})
set_target_properties(kddockwidgets PROPERTIES
SOVERSION ${${PROJECT_NAME}_SOVERSION}
VERSION ${${PROJECT_NAME}_VERSION}
)
#version libraries on Windows
if(WIN32)
set(postfix ${${PROJECT_NAME}_VERSION_MAJOR})
@@ -199,6 +215,9 @@ install(FILES private/multisplitter/Separator_qwidget.h DESTINATION include/kddo
install(FILES private/multisplitter/multisplitter_export.h DESTINATION include/kddockwidgets/private/multisplitter)
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES} DESTINATION include/kddockwidgets/private/widgets)
install(FILES private/indicators/ClassicIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
install(FILES private/indicators/SegmentedIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
KDDockWidgetsConfigVersion.cmake
@@ -217,11 +236,11 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgetsConfig.cmake"
DESTINATION ${INSTALL_LIBRARY_DIR}/cmake/KDDockWidgets
)
if(OPTION_DEVELOPER_MODE)
if(${PROJECT_NAME}_DEVELOPER_MODE)
# Under developer mode since kddw might be a sub-folder of a project setting a different value for QT_DISABLE_DEPRECATED_BEFORE
target_compile_definitions(kddockwidgets PRIVATE QT_DISABLE_DEPRECATED_BEFORE=0x060000)
if (NOT OPTION_QTQUICK) # TODO: We can support it
if (NOT ${PROJECT_NAME}_QTQUICK) # TODO: We can support it
add_executable(kddockwidgets_linter layoutlinter_main.cpp)
target_link_libraries(kddockwidgets_linter kddockwidgets kddockwidgets_multisplitter Qt5::Widgets)
endif()

View File

@@ -47,8 +47,10 @@ public:
QQmlEngine *m_qmlEngine = nullptr;
DockWidgetFactoryFunc m_dockWidgetFactoryFunc = nullptr;
MainWindowFactoryFunc m_mainWindowFactoryFunc = nullptr;
TabbingAllowedFunc m_tabbingAllowedFunc = nullptr;
FrameworkWidgetFactory *m_frameworkWidgetFactory;
Flags m_flags = Flag_Default;
qreal m_draggedWindowOpacity = Q_QNAN;
};
Config::Config()
@@ -142,6 +144,26 @@ void Config::setSeparatorThickness(int value)
Layouting::Config::self().setSeparatorThickness(value);
}
void Config::setDraggedWindowOpacity(qreal opacity)
{
d->m_draggedWindowOpacity = opacity;
}
qreal Config::draggedWindowOpacity() const
{
return d->m_draggedWindowOpacity;
}
void Config::setTabbingAllowedFunc(TabbingAllowedFunc func)
{
d->m_tabbingAllowedFunc = func;
}
TabbingAllowedFunc Config::tabbingAllowedFunc() const
{
return d->m_tabbingAllowedFunc;
}
void Config::setQmlEngine(QQmlEngine *qmlEngine)
{
if (d->m_qmlEngine) {
@@ -163,6 +185,9 @@ void Config::Private::fixFlags()
if (QOperatingSystemVersion::current().majorVersion() < 10) {
// Aero-snap requires Windows 10
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
} else {
// Unconditional now
m_flags |= Flag_AeroSnapWithClientDecos;
}
// These are mutually exclusive:

View File

@@ -35,6 +35,14 @@ class FrameworkWidgetFactory;
typedef KDDockWidgets::DockWidgetBase* (*DockWidgetFactoryFunc)(const QString &name);
typedef KDDockWidgets::MainWindowBase* (*MainWindowFactoryFunc)(const QString &name);
/// @brief Function to allow the user more granularity to disallow dock widgets to tab together
/// @param source The dock widgets being dragged
/// @param target The dock widgets within an existing docked tab group
/// @return true if the docking is allowed.
/// @sa setTabbingAllowedFunc
typedef bool (*TabbingAllowedFunc)(const QVector<DockWidgetBase*> &source,
const QVector<DockWidgetBase*> &target);
/**
* @brief Singleton to allow to choose certain behaviours of the framework.
*
@@ -53,17 +61,29 @@ public:
///@brief Flag enum to tune certain behaviours, the defaults are Flag_Default
enum Flag {
Flag_None = 0, ///> No option set
Flag_NativeTitleBar = 1, ///> Enables the Native OS title bar on OSes that support it (Windows 10, macOS), ignored otherwise. This is mutually exclusive with Flag_AeroSnap
Flag_AeroSnapWithClientDecos = 2, ///> Enables AeroSnap even if we're not using the native title bar. Only supported on Windows 10.
Flag_HideTitleBarWhenTabsVisible = 8, ///> Hides the title bar if there's tabs visible. The empty space in the tab bar becomes draggable.
Flag_AlwaysShowTabs = 16, ///> Always show tabs, even if there's only one,
Flag_AllowReorderTabs = 32, /// Allows user to re-order tabs by dragging them
Flag_TabsHaveCloseButton = 64, /// Tabs will have a close button. Equivalent to QTabWidget::setTabsClosable(true).
Flag_DoubleClickMaximizes = 128, /// Double clicking the titlebar will maximize a floating window instead of re-docking it
Flag_TitleBarHasMaximizeButton = 256, /// The title bar will have a maximize/restore button when floating. This is mutually-exclusive with the floating button (since many apps behave that way).
Flag_LazyResize = 1024, /// The dock widgets are resized in a lazy manner. The actual resize only happens when you release the mouse button.
Flag_Default = Flag_AeroSnapWithClientDecos ///> The defaults
Flag_None = 0, ///< No option set
Flag_NativeTitleBar = 1, ///< Enables the Native OS title bar on OSes that support it (Windows 10, macOS), ignored otherwise. This is mutually exclusive with Flag_AeroSnap
Flag_AeroSnapWithClientDecos = 2, ///< Deprecated. This is now default and cannot be turned off. Moving a window on Windows 10 uses native moving, as that works well across screens with different HDPI settings. There's no reason to use manual client/Qt window moving.
Flag_AlwaysTitleBarWhenFloating = 4, ///< Floating windows will have a title bar even if Flag_HideTitleBarWhenTabsVisible is specified. Unneeded if Flag_HideTitleBarWhenTabsVisible isn't specified, as that's the default already.
Flag_HideTitleBarWhenTabsVisible = 8, ///< Hides the title bar if there's tabs visible. The empty space in the tab bar becomes draggable.
Flag_AlwaysShowTabs = 16, ///< Always show tabs, even if there's only one,
Flag_AllowReorderTabs = 32, ///< Allows user to re-order tabs by dragging them
Flag_TabsHaveCloseButton = 64, ///< Tabs will have a close button. Equivalent to QTabWidget::setTabsClosable(true).
Flag_DoubleClickMaximizes = 128, ///< Double clicking the titlebar will maximize a floating window instead of re-docking it
Flag_TitleBarHasMaximizeButton = 256, ///< The title bar will have a maximize/restore button when floating. This is mutually-exclusive with the floating button (since many apps behave that way).
Flag_TitleBarIsFocusable = 512, ///< You can click the title bar and it will focus the last focused widget in the focus scope. If no previously focused widget then it focuses the user's dock widget guest, which should accept focus or use a focus proxy.
Flag_LazyResize = 1024, ///< The dock widgets are resized in a lazy manner. The actual resize only happens when you release the mouse button.
// These two are internal, for testing purposes across platforms. Use Flag_DontUseUtilityFloatingWindows instead.
Flag_internal_DontUseQtToolWindowsForFloatingWindows = 0x800, ///< FloatingWindows will use Qt::Window instead of Qt::Tool. Internal, use Flag_DontUseUtilityFloatingWindows instead.
Flag_internal_DontUseParentForFloatingWindows = 0x1000, ///< FloatingWindows won't have a parent top-level. Internal, use Flag_DontUseUtilityFloatingWindows instead.
Flag_DontUseUtilityFloatingWindows = Flag_internal_DontUseQtToolWindowsForFloatingWindows | Flag_internal_DontUseParentForFloatingWindows,
Flag_TitleBarHasMinimizeButton = 0x2000 | Flag_DontUseUtilityFloatingWindows, ///< The title bar will have a minimize button when floating. This implies Flag_DontUseUtilityFloatingWindows too, otherwise they wouldn't appear in the task bar.
Flag_TitleBarNoFloatButton = 0x4000, ///< The TitleBar won't show the float button
Flag_AutoHideSupport = 0x8000 | Flag_TitleBarNoFloatButton, ///< Supports minimizing dock widgets to the side-bar.
///< By default it also turns off the float button, but you can remove Flag_TitleBarNoFloatButton to have both.
Flag_Default = Flag_AeroSnapWithClientDecos ///< The defaults
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -130,6 +150,41 @@ public:
///Note: Only use this function at startup before creating any DockWidget or MainWindow.
void setSeparatorThickness(int value);
///@brief sets the dragged window opacity
///1.0 is fully opaque while 0.0 is fully transparent
void setDraggedWindowOpacity(qreal opacity);
///@brief returns the opacity to use when dragging dock widgets
///By default it's 1.0, fully opaque
qreal draggedWindowOpacity() const;
/**
* @brief Allows the user to intercept a docking attempt to center (tabbed) and disallow it.
*
* Whenever the user tries to tab two widgets together, the framework will call @p func. If
* it returns true, then tabbing is allowed, otherwise not.
*
* Example:
* @code
* #include <kddockwidgets/Config.h>
* (...)
*
* auto func = [] (const KDDockWidgets::DockWidgetBase::List &source,
* const KDDockWidgets::DockWidgetBase::List &target)
* {
* // disallows dockFoo to be tabbed with dockBar.
* return !(source.contains(dockFoo) && target.contains(dockBar));
* }
* @endcode
* KDDockWidgets::Config::self()->setTabbingAllowedFunc(func);
*/
void setTabbingAllowedFunc(TabbingAllowedFunc func);
///@brief Used internally by the framework. Returns the function which was passed to setTabbingAllowedFunc()
///By default it's nullptr.
///@sa setTabbingAllowedFunc().
TabbingAllowedFunc tabbingAllowedFunc() const;
///@brief Sets the QQmlEngine to use. Applicable only when using QtQuick.
void setQmlEngine(QQmlEngine *);
QQmlEngine* qmlEngine() const;

View File

@@ -22,6 +22,7 @@
#include "FrameworkWidgetFactory.h"
#include "private/Position_p.h"
#include "WindowBeingDragged_p.h"
#include "SideBar_p.h"
#include <QAction>
#include <QEvent>
@@ -57,10 +58,12 @@ public:
}
});
q->connect(floatAction, &QAction::toggled, q, [this] (bool enabled) {
q->connect(floatAction, &QAction::toggled, q, [this] (bool checked) {
if (!m_updatingFloatAction) { // guard against recursiveness
q->setFloating(enabled);
q->setFloating(checked);
}
Q_EMIT q->isFloatingChanged(checked);
});
toggleAction->setCheckable(true);
@@ -77,10 +80,29 @@ public:
return qobject_cast<FloatingWindow*>(q->window());
}
MainWindowBase *mainWindow() const
{
if (q->isWindow())
return nullptr;
// Note: Don't simply use window(), as the MainWindow might be embedded into something else
QWidgetOrQuick *p = q->parentWidget();
while (p) {
if (auto window = qobject_cast<MainWindowBase*>(p))
return window;
if (p->isWindow())
return nullptr;
p = p->parentWidget();
}
return nullptr;
}
QPoint defaultCenterPosForFloating();
void updateTitle();
void updateIcon();
void toggle(bool enabled);
void updateToggleAction();
void updateFloatAction();
@@ -88,7 +110,7 @@ public:
void onDockWidgetHidden();
void show();
void close();
void restoreToPreviousPosition();
bool restoreToPreviousPosition();
void maybeRestoreToPreviousPosition();
int currentTabIndex() const;
@@ -101,7 +123,8 @@ public:
const QString name;
QStringList affinities;
QString title;
QIcon icon;
QIcon titleBarIcon;
QIcon tabBarIcon;
QWidgetOrQuick *widget = nullptr;
DockWidgetBase *const q;
DockWidgetBase::Options options;
@@ -123,6 +146,8 @@ DockWidgetBase::DockWidgetBase(const QString &name, Options options)
if (name.isEmpty())
qWarning() << Q_FUNC_INFO << "Name can't be null";
setAttribute(Qt::WA_PendingMoveEvent, false);
}
DockWidgetBase::~DockWidgetBase()
@@ -244,15 +269,12 @@ bool DockWidgetBase::isFloating() const
return fw && fw->hasSingleDockWidget();
}
void DockWidgetBase::setFloating(bool floats)
bool DockWidgetBase::setFloating(bool floats)
{
const bool alreadyFloating = isFloating();
qCDebug(docking) << Q_FUNC_INFO << "yes=" << floats
<< "; already floating=" << alreadyFloating;
if ((floats && alreadyFloating) || (!floats && !alreadyFloating))
return; // Nothing to do
return true; // Nothing to do
if (floats) {
d->saveTabIndex();
@@ -262,6 +284,7 @@ void DockWidgetBase::setFloating(bool floats)
qWarning() << "DockWidget::setFloating: Tabbed but no frame exists"
<< this;
Q_ASSERT(false);
return false;
}
frame->detachTab(this);
@@ -274,9 +297,10 @@ void DockWidgetBase::setFloating(bool floats)
if (auto fw = floatingWindow())
fw->setSuggestedGeometry(lastGeo, /*preserveCenter=*/true);
}
return true;
} else {
saveLastFloatingGeometry();
d->restoreToPreviousPosition();
return d->restoreToPreviousPosition();
}
}
@@ -305,7 +329,7 @@ void DockWidgetBase::setTitle(const QString &title)
if (title != d->title) {
d->title = title;
d->updateTitle();
Q_EMIT titleChanged();
Q_EMIT titleChanged(title);
}
}
@@ -355,16 +379,26 @@ void DockWidgetBase::setAsCurrentTab()
frame->setCurrentDockWidget(this);
}
void DockWidgetBase::setIcon(const QIcon &icon)
void DockWidgetBase::setIcon(const QIcon &icon, IconPlaces places)
{
d->icon = icon;
d->updateIcon();
if (places & IconPlace::TitleBar)
d->titleBarIcon = icon;
if (places & IconPlace::TabBar)
d->tabBarIcon = icon;
Q_EMIT iconChanged();
}
QIcon DockWidgetBase::icon() const
QIcon DockWidgetBase::icon(IconPlace place) const
{
return d->icon;
if (place == IconPlace::TitleBar)
return d->titleBarIcon;
if (place == IconPlace::TabBar)
return d->tabBarIcon;
return {};
}
void DockWidgetBase::forceClose()
@@ -420,6 +454,22 @@ bool DockWidgetBase::isMainWindow() const
return qobject_cast<MainWindowBase*>(widget());
}
bool DockWidgetBase::isInMainWindow() const
{
return d->mainWindow() != nullptr;
}
MainWindowBase* DockWidgetBase::mainWindow() const
{
return d->mainWindow();
}
bool DockWidgetBase::isFocused() const
{
auto f = this->frame();
return f && f->isFocused() && isCurrentTab();
}
void DockWidgetBase::setAffinityName(const QString &affinity)
{
setAffinities({ affinity });
@@ -443,6 +493,30 @@ void DockWidgetBase::setAffinities(const QStringList &affinityNames)
d->affinities = affinities;
}
void DockWidgetBase::moveToSideBar()
{
if (MainWindowBase *m = mainWindow())
m->moveToSideBar(this);
}
bool DockWidgetBase::isOverlayed() const
{
if (MainWindowBase *m = mainWindow())
return m->overlayedDockWidget() == this;
return false;
}
SideBarLocation DockWidgetBase::sideBarLocation() const
{
return DockRegistry::self()->sideBarLocationForDockWidget(this);
}
bool DockWidgetBase::hasPreviousDockedLocation() const
{
return d->m_lastPositions.isValid();
}
FloatingWindow *DockWidgetBase::morphIntoFloatingWindow()
{
qCDebug(creation) << "DockWidget::morphIntoFloatingWindow() this=" << this
@@ -455,9 +529,12 @@ FloatingWindow *DockWidgetBase::morphIntoFloatingWindow()
QRect geo = d->m_lastPositions.lastFloatingGeometry();
if (geo.isNull()) {
geo = geometry();
const QPoint center = d->defaultCenterPosForFloating();
if (!center.isNull())
geo.moveCenter(center);
if (!testAttribute(Qt::WA_PendingMoveEvent)) { // If user already moved it, we don't interfere
const QPoint center = d->defaultCenterPosForFloating();
if (!center.isNull())
geo.moveCenter(center);
}
}
auto frame = Config::self().frameworkWidgetFactory()->createFrame();
@@ -514,6 +591,11 @@ void DockWidgetBase::saveLastFloatingGeometry()
}
}
void DockWidgetBase::updateFloatAction()
{
d->updateFloatAction();
}
QPoint DockWidgetBase::Private::defaultCenterPosForFloating()
{
MainWindowBase::List mainWindows = DockRegistry::self()->mainwindows();
@@ -534,10 +616,6 @@ void DockWidgetBase::Private::updateTitle()
toggleAction->setText(title);
}
void DockWidgetBase::Private::updateIcon()
{
}
void DockWidgetBase::Private::toggle(bool enabled)
{
if (enabled) {
@@ -601,19 +679,24 @@ void DockWidgetBase::Private::close()
if (Frame *frame = q->frame()) {
frame->removeWidget(q);
q->setParent(nullptr);
if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
sb->removeDockWidget(q);
}
}
}
void DockWidgetBase::Private::restoreToPreviousPosition()
bool DockWidgetBase::Private::restoreToPreviousPosition()
{
if (!m_lastPositions.isValid())
return;
return false;
Layouting::Item *item = m_lastPositions.lastItem();
MultiSplitter *layout = DockRegistry::self()->layoutForItem(item);
Q_ASSERT(layout);
layout->restorePlaceholder(q, item, m_lastPositions.lastTabIndex());
return true;
}
void DockWidgetBase::Private::maybeRestoreToPreviousPosition()

View File

@@ -61,6 +61,8 @@ class DOCKS_EXPORT DockWidgetBase : public QWidget
#endif
{
Q_OBJECT
Q_PROPERTY(bool isFocused READ isFocused NOTIFY isFocusedChanged)
Q_PROPERTY(bool isFloating READ isFloating WRITE setFloating NOTIFY isFloatingChanged)
public:
typedef QVector<DockWidgetBase *> List;
@@ -72,6 +74,14 @@ public:
};
Q_DECLARE_FLAGS(Options, Option)
enum class IconPlace {
TitleBar = 1,
TabBar = 2,
All = TitleBar | TabBar
};
Q_ENUM(IconPlace)
Q_DECLARE_FLAGS(IconPlaces, IconPlace)
/**
* @brief constructs a new DockWidget
* @param uniqueName the name of the dockwidget, should be unique. Use title for user visible text.
@@ -122,14 +132,14 @@ public:
/**
* @brief sets the widget which this dock widget hosts.
* @param widget widget to show inside this dock widget. Must not be null.
* @param widget the widget to show inside this dock widget. Must not be null.
*
* Ownership for @p widget is transfered to DockWidgetBase.
* Ownsership for any previously existing widget is transfered back to the user. Meaning if you
* Ownership for @p widget is transferred to DockWidgetBase.
* Ownsership for any previously existing widget is transferred back to the user. Meaning if you
* call setWidget(A) followed by setWidget(B) then A will have to be deleted by you, while B is
* owned by the dock widget.
*/
void setWidget(QWidgetOrQuick *widget);
virtual void setWidget(QWidgetOrQuick *widget);
/**
* @brief returns the widget which this dock widget hosts
@@ -148,8 +158,10 @@ public:
/**
* @brief setter to make the dock widget float or dock.
* @param floats If true makes the dock widget float, otherwise docks it.
*
* Returns true if the request was accomplished
*/
void setFloating(bool floats);
bool setFloating(bool floats);
/**
* @brief Returns the QAction that allows to hide/show the dock widget
@@ -223,14 +235,22 @@ public:
/**
* @brief Sets an icon to show on title bars and tab bars.
* By default none is shown.
* @param places Specifies where the icon will be shown (TitleBar, TabBar or both)
*
* By default there's no icon set.
*
* @sa icon()
*/
void setIcon(const QIcon &icon);
void setIcon(const QIcon &icon, IconPlaces places = IconPlace::All);
/**
* @brief Returns the dock widget's icon.
* @brief Returns the dock widget's titlebar or tabbar icon (depending on the passed @p place)
*
* By default it's null.
*
* @sa setIcon()
*/
QIcon icon() const;
QIcon icon(IconPlace place = IconPlace::TitleBar) const;
/**
* @brief Like QWidget::close() but the hosted widget won't be asked if we
@@ -304,6 +324,50 @@ public:
*/
bool isMainWindow() const;
/**
* @brief Returns whether this dock widget is docked into a main window.
*
* Note that isFloating() returning false might either mean the dock widget is docked into a
* main window or into a floating window (groupped/nested with other dock widgets. Use this function
* then if you need to disambiguate
*/
bool isInMainWindow() const;
/// @brief Returns the main window this dock widget is in. nullptr if it's not inside a main window
MainWindowBase *mainWindow() const;
///@brief Returns whether This or any child of this dock widget is focused
///Not to be confused with QWidget::hasFocus(), which just refers to 1 widget. This includes
///variant includes children.
///@sa isFocusedChanged()
bool isFocused() const;
/**
* @brief Minimizes this dock widget to the MainWindow's side-bar.
*
* It will be undocked from current layout. It's previous docked position will be remembered.
*
* This action is only available if the dock widget is docked into a MainWindow.
* The dockwidget will initially be visible and overlayed on top of the current layout (this is
* the auto-hide feature).
*/
void moveToSideBar();
/// @brief Returns whether this dock widget is overlayed on top of the main window, instead of
/// docked into the layout. This is only relevant when using the auto-hide and side-bar feature.
bool isOverlayed() const;
///@brief Returns whether this dock widget is in a side bar, and which.
/// SideBarLocation::None is returned if it's not in a sidebar.
/// This is only relevant when using the auto-hide and side-bar feature.
SideBarLocation sideBarLocation() const;
/// @brief Returns whether this floating dock widget knows its previous docked location
/// Result only makes sense if it's floating.
///
/// When you call dockWidget->setFloating(false) it will only dock if it knows where to.
bool hasPreviousDockedLocation() const;
Q_SIGNALS:
///@brief signal emitted when the parent changed
void parentChanged();
@@ -318,7 +382,8 @@ Q_SIGNALS:
void iconChanged();
///@brief signal emitted when the title changed
void titleChanged();
///@param title the new title
void titleChanged(const QString &title);
///@brief emitted when the hosted widget changed
void widgetChanged(KDDockWidgets::QWidgetOrQuick *);
@@ -327,6 +392,21 @@ Q_SIGNALS:
///@sa setOptions(), options()
void optionsChanged(KDDockWidgets::DockWidgetBase::Options);
///@brief emitted when isFocused changes
///@sa isFocused
void isFocusedChanged(bool);
///@brief emitted when isOverlayed changes
///@sa isOverlayed
void isOverlayedChanged(bool);
///@brief emitted when isFloating changes
bool isFloatingChanged(bool);
///@brief emitted when this dock widget is removed from a side-bar.
///Only relevant for the auto-hide/sidebar feature
void removedFromSideBar();
protected:
void onParentChanged();
void onShown(bool spontaneous);
@@ -364,6 +444,7 @@ private:
friend class KDDockWidgets::DragController;
friend class KDDockWidgets::DockRegistry;
friend class KDDockWidgets::LayoutSaver;
friend class KDDockWidgets::MainWindowBase;
/**
* @brief the Frame which contains this dock widgets.
@@ -392,6 +473,9 @@ private:
///@brief If this dock widget is floating, then it saves its geometry
void saveLastFloatingGeometry();
///@brief Updates the floatAction state
void updateFloatAction();
class Private;
Private *const d;
};

135
src/FocusScope.cpp Normal file
View File

@@ -0,0 +1,135 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
/**
* @file
* @brief FocusScope
*
* @author Sérgio Martins \<sergio.martins@kdab.com\>
*/
#include "FocusScope.h"
#include "TitleBar_p.h"
#include <QObject>
#include <QApplication>
#include <QPointer>
using namespace KDDockWidgets;
// Our Private inherits from QObject since FocusScope can't (Since Frame is already QObject)
class FocusScope::Private : public QObject
{
public:
Private(FocusScope *qq, QWidgetAdapter *thisWidget)
: q(qq)
, m_thisWidget(thisWidget)
{
connect(qApp, &QGuiApplication::focusObjectChanged,
this, &Private::onFocusObjectChanged);
onFocusObjectChanged(qApp->focusObject());
m_inCtor = false;
}
~Private() override;
void setIsFocused(bool);
void onFocusObjectChanged(QObject *);
bool isInFocusScope(WidgetType *) const;
FocusScope *const q;
QWidgetAdapter *const m_thisWidget;
bool m_isFocused = false;
bool m_inCtor = true;
QPointer<WidgetType> m_lastFocusedInScope;
};
FocusScope::Private::~Private()
{
}
FocusScope::FocusScope(QWidgetAdapter *thisWidget)
: d(new Private(this, thisWidget))
{
}
FocusScope::~FocusScope()
{
delete d;
}
bool FocusScope::isFocused() const
{
return d->m_isFocused;
}
WidgetType *FocusScope::focusedWidget() const
{
return d->m_lastFocusedInScope;
}
void FocusScope::focus(Qt::FocusReason reason)
{
if (d->m_lastFocusedInScope) {
d->m_lastFocusedInScope->setFocus(reason);
} else {
if (auto frame = qobject_cast<Frame*>(d->m_thisWidget)) {
if (DockWidgetBase *dw = frame->currentDockWidget()) {
if (auto guest = dw->widget()) {
if (guest->focusPolicy() != Qt::NoFocus)
guest->setFocus(reason);
}
}
} else {
// Not a use case right now
d->m_thisWidget->setFocus(reason);
}
}
}
void FocusScope::Private::setIsFocused(bool is)
{
if (is != m_isFocused) {
m_isFocused = is;
if (!m_inCtor) // Hack so we don't call pure-virtual
Q_EMIT q->isFocusedChanged();
}
}
void FocusScope::Private::onFocusObjectChanged(QObject *obj)
{
auto widget = qobject_cast<WidgetType*>(obj);
if (!widget)
return;
const bool is = isInFocusScope(widget);
if (is && m_lastFocusedInScope != widget && !qobject_cast<TitleBar*>(obj)) {
m_lastFocusedInScope = widget;
Q_EMIT q->focusedWidgetChanged();
}
setIsFocused(is);
}
bool FocusScope::Private::isInFocusScope(WidgetType *widget) const
{
WidgetType *p = widget;
while (p) {
if (p == m_thisWidget)
return true;
p = KDDockWidgets::Private::parentWidget(p);
}
return false;
}

61
src/FocusScope.h Normal file
View File

@@ -0,0 +1,61 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
/**
* @file
* @brief FocusScope
*
* @author Sérgio Martins \<sergio.martins@kdab.com\>
*/
#ifndef KD_DOCKWIDGETS_FOCUSSCOPE_H
#define KD_DOCKWIDGETS_FOCUSSCOPE_H
#include "docks_export.h"
#include "QWidgetAdapter.h"
namespace KDDockWidgets
{
///@brief Allows to implement a similar functionality to QtQuick's FocusScope item, in QtWidgets
class FocusScope
{
public:
///@brief constructor
explicit FocusScope(QWidgetAdapter *thisWidget);
virtual ~FocusScope();
///@brief Returns true if this FocusScope is focused.
///This is similar to the QWidget::hasFocus(), except that it counts with the children being focused too.
///i.e: If any child is focused then this FocusScope has focus too.
bool isFocused() const;
///@brief Returns the widget that's focused in this scope
///The widget itself might not have focus as in QWidget::hasFocus(), but will get actual focus
///as soon as this scope is focused.
WidgetType* focusedWidget() const;
///@brief Sets focus on this scope.
///
/// This will call QWidget::focus() on the last QWidget that was focused in this scope.
void focus(Qt::FocusReason = Qt::OtherFocusReason);
/*Q_SIGNALS:*/
///@brief reimplement in the 1st QObject derived class
virtual void isFocusedChanged() = 0;
virtual void focusedWidgetChanged() = 0;
private:
class Private;
Private *const d;
};
}
#endif

View File

@@ -15,6 +15,7 @@
#include "multisplitter/Separator_p.h"
#include "FloatingWindow_p.h"
#include "Config.h"
#include "indicators/ClassicIndicators_p.h"
#ifdef KDDOCKWIDGETS_QTWIDGETS
# include "indicators/ClassicIndicators_p.h"
@@ -22,9 +23,14 @@
# include "widgets/FrameWidget_p.h"
# include "widgets/TitleBarWidget_p.h"
# include "widgets/TabBarWidget_p.h"
# include "widgets/SideBarWidget_p.h"
# include "widgets/TabWidgetWidget_p.h"
# include "multisplitter/Separator_qwidget.h"
# include "widgets/FloatingWindowWidget_p.h"
# include "indicators/SegmentedIndicators_p.h"
# include <QRubberBand>
# include <QToolButton>
#else
# include "quick/FrameQuick_p.h"
# include "quick/DockWidgetQuick.h"
@@ -35,6 +41,8 @@
using namespace KDDockWidgets;
DropIndicatorType DefaultWidgetFactory::s_dropIndicatorType = DropIndicatorType::Classic;
FrameworkWidgetFactory::~FrameworkWidgetFactory()
{
}
@@ -82,8 +90,39 @@ FloatingWindow *DefaultWidgetFactory::createFloatingWindow(Frame *frame, MainWin
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *dropArea) const
{
switch (s_dropIndicatorType) {
case DropIndicatorType::Classic:
return new ClassicIndicators(dropArea);
case DropIndicatorType::Segmented:
return new SegmentedIndicators(dropArea);
}
return new ClassicIndicators(dropArea);
}
QWidgetOrQuick *DefaultWidgetFactory::createRubberBand(QWidgetOrQuick *parent) const
{
return new QRubberBand(QRubberBand::Rectangle, parent);
}
SideBar *DefaultWidgetFactory::createSideBar(SideBarLocation loc, MainWindowBase *parent) const
{
return new SideBarWidget(loc, parent);
}
QAbstractButton* DefaultWidgetFactory::createTitleBarButton(QWidget *parent, TitleBarButtonType type) const
{
if (!parent) {
qWarning() << Q_FUNC_INFO << "Parent not provided";
return nullptr;
}
auto button = new Button(parent);
button->setIcon(iconForButtonType(type, parent->devicePixelRatioF()));
return button;
}
#else
Frame *DefaultWidgetFactory::createFrame(QWidgetOrQuick *parent, FrameOptions options) const
@@ -116,9 +155,9 @@ FloatingWindow *DefaultWidgetFactory::createFloatingWindow(Frame *frame, MainWin
return new FloatingWindowQuick(frame, parent);
}
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *) const
DropIndicatorOverlayInterface *DefaultWidgetFactory::createDropIndicatorOverlay(DropArea *dropArea) const
{
return nullptr;
return new ClassicIndicators(dropArea);
}
TabBar *DefaultWidgetFactory::createTabBar(TabWidget *parent) const
@@ -140,4 +179,75 @@ Layouting::Separator *DefaultWidgetFactory::createSeparator(Layouting::Widget *p
return new Layouting::SeparatorQuick(parent);
}
QWidgetOrQuick *DefaultWidgetFactory::createRubberBand(QWidgetOrQuick *parent) const
{
return new QWidgetOrQuick(parent);
}
SideBar *DefaultWidgetFactory::createSideBar(SideBarLocation loc, MainWindowBase *parent) const
{
Q_UNUSED(loc);
Q_UNUSED(parent);
qWarning() << Q_FUNC_INFO << "Not implemented yet";
return nullptr;
}
#endif // QtQuick
// iconForButtonType impl is the same for QtQuick and QtWidgets
QIcon DefaultWidgetFactory::iconForButtonType(TitleBarButtonType type, qreal dpr) const
{
QString iconName;
switch (type) {
case TitleBarButtonType::AutoHide:
iconName = QStringLiteral("auto-hide");
break;
case TitleBarButtonType::UnautoHide:
iconName = QStringLiteral("unauto-hide");
break;
case TitleBarButtonType::Close:
iconName = QStringLiteral("close");
break;
case TitleBarButtonType::Minimize:
iconName = QStringLiteral("min");
break;
case TitleBarButtonType::Maximize:
iconName = QStringLiteral("max");
break;
case TitleBarButtonType::Normal:
// We're using the same icon as dock/float
iconName = QStringLiteral("dock-float");
break;
case TitleBarButtonType::Float:
iconName = QStringLiteral("dock-float");
break;
}
if (iconName.isEmpty())
return {};
QIcon icon(QStringLiteral(":/img/%1.png").arg(iconName));
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
const bool isFractional = int(dpr) != dpr;
if (isFractional) {
// We don't support 1.5x yet.
// Problem with Linux is that rendering is off due to a rounding bug only fixed in 5.15.2
// Will enable for fractional later.
// QTBUG-86170
// Mostly affects Linux. Unless you're using Qt::HighDpiScaleFactorRoundingPolicy::PassThrough, in which case it will
// affect other OSes too.
return icon;
}
#else
// Not using Qt's sugar syntax, which doesn't support 1.5x anyway when we need it.
// Simply add the high-res files and Qt will pick them when needed
icon.addFile(QStringLiteral(":/img/%1-1.5x.png").arg(iconName));
Q_UNUSED(dpr);
#endif
icon.addFile(QStringLiteral(":/img/%1-2x.png").arg(iconName));
return icon;
}

View File

@@ -23,6 +23,10 @@
* @author Sérgio Martins \<sergio.martins@kdab.com\>
*/
QT_BEGIN_NAMESPACE
class QAbstractButton;
QT_END_NAMESPACE
namespace Layouting {
class Separator;
class Widget;
@@ -37,6 +41,7 @@ class TabWidget;
class TitleBar;
class Frame;
class DropArea;
class SideBar;
class TabBar;
/**
@@ -117,6 +122,27 @@ public:
/// Override to provide your own DropIndicatorOverlayInterface sub-class.
///@param dropArea Just forward to DropIndicatorOverlayInterface's constructor.
virtual DropIndicatorOverlayInterface *createDropIndicatorOverlay(DropArea *dropArea) const = 0;
///@brief Called internally by the framework to create a RubberBand to show as drop zone
///Returns a rubber band
virtual QWidgetOrQuick *createRubberBand(QWidgetOrQuick *parent) const = 0;
///@brief Called internally by the framework to create a SideBar
///@param loc The side-bar location without the main window. Just forward into your SideBar sub-class ctor.
///@param parent The MainWindow. Just forward into your SideBar sub-class ctor.
virtual SideBar *createSideBar(SideBarLocation loc, MainWindowBase *parent) const = 0;
#ifdef KDDOCKWIDGETS_QTWIDGETS
///@brief Called internally by the framework to create a title bar button
///@p parent the button's parent
virtual QAbstractButton* createTitleBarButton(QWidget *parent, TitleBarButtonType) const = 0;
#else
// QtQuick will have some other base class for buttons
#endif
/// @brief Returns the icon to be used with the specified @p type
/// @param dpr the device pixel ratio of the button
virtual QIcon iconForButtonType(TitleBarButtonType type, qreal dpr) const = 0;
private:
Q_DISABLE_COPY(FrameworkWidgetFactory)
};
@@ -137,6 +163,16 @@ public:
FloatingWindow *createFloatingWindow(MainWindowBase *parent = nullptr) const override;
FloatingWindow *createFloatingWindow(Frame *frame, MainWindowBase *parent = nullptr) const override;
DropIndicatorOverlayInterface *createDropIndicatorOverlay(DropArea*) const override;
QWidgetOrQuick *createRubberBand(QWidgetOrQuick *parent) const override;
SideBar *createSideBar(SideBarLocation loc, MainWindowBase *parent) const override;
#ifdef KDDOCKWIDGETS_QTWIDGETS
QAbstractButton* createTitleBarButton(QWidget *parent, TitleBarButtonType) const override;
#endif
QIcon iconForButtonType(TitleBarButtonType type, qreal dpr) const override;
static DropIndicatorType s_dropIndicatorType;
private:
Q_DISABLE_COPY(DefaultWidgetFactory)
};

View File

@@ -53,7 +53,8 @@ namespace KDDockWidgets
enum FrameOption {
FrameOption_None = 0,
FrameOption_AlwaysShowsTabs = 1,
FrameOption_IsCentralFrame = 2
FrameOption_IsCentralFrame = 2,
FrameOption_IsOverlayed = 4
};
Q_DECLARE_FLAGS(FrameOptions, FrameOption)
@@ -73,6 +74,11 @@ namespace KDDockWidgets
SizePolicy, ///< Uses the item's sizeHint() and sizePolicy()
};
enum class DropIndicatorType {
Classic, ///< The default
Segmented
};
///@internal
inline QString locationStr(Location loc)
{
@@ -91,6 +97,32 @@ namespace KDDockWidgets
return QString();
}
/// @brief Each main window supports 4 sidebars
enum class SideBarLocation {
None,
North,
East,
West,
South
};
///@brief describes a type of button you can have in the title bar
enum class TitleBarButtonType {
Close,
Float,
Minimize,
Maximize,
Normal, // Restore from maximized state
AutoHide,
UnautoHide
};
///@internal
inline uint qHash(SideBarLocation loc, uint seed)
{
return ::qHash(static_cast<uint>(loc), seed);
}
}
Q_DECLARE_OPERATORS_FOR_FLAGS(KDDockWidgets::FrameOptions)

View File

@@ -12,7 +12,7 @@
include(CMakeFindDependencyMacro)
find_dependency(Qt5Widgets REQUIRED)
if (@OPTION_QTQUICK@)
if (@KDDockWidgets_QTQUICK@)
find_dependency(Qt5Quick REQUIRED)
endif()

View File

@@ -17,10 +17,13 @@
*/
#include "MainWindow.h"
#include "Config.h"
#include "DropArea_p.h"
#include "Frame_p.h"
#include "Logging_p.h"
#include "SideBar_p.h"
#include "DropAreaWithCentralFrame_p.h"
#include "FrameworkWidgetFactory.h"
#include <QApplication>
#include <QVBoxLayout>
@@ -31,11 +34,21 @@ using namespace KDDockWidgets;
class MainWindow::Private
{
public:
explicit Private(MainWindowOptions, MainWindowBase *)
{
}
};
explicit Private(MainWindowOptions, MainWindowBase *mainWindow)
: m_supportsAutoHide(Config::self().flags() & Config::Flag_AutoHideSupport)
{
if (m_supportsAutoHide) {
for (auto location : { SideBarLocation::North, SideBarLocation::East,
SideBarLocation::West, SideBarLocation::South}) {
m_sideBars.insert(location, Config::self().frameworkWidgetFactory()->createSideBar(location, mainWindow) );
}
}
}
const bool m_supportsAutoHide;
QHash<SideBarLocation, SideBar*> m_sideBars;
};
namespace KDDockWidgets {
class MyCentralWidget : public QWidget
@@ -67,9 +80,24 @@ MainWindow::MainWindow(const QString &name, MainWindowOptions options,
, d(new Private(options, this))
{
auto centralWidget = new MyCentralWidget(this);
auto layout = new QVBoxLayout(centralWidget);
layout->setContentsMargins(1, 5, 1, 1);
layout->addWidget(dropArea()); // 1 level of indirection so we can add some margins
auto layout = new QHBoxLayout(centralWidget); // 1 level of indirection so we can add some margins
layout->setSpacing(0);
layout->setContentsMargins(centerWidgetMargins());
if (d->m_supportsAutoHide) {
layout->addWidget(sideBar(SideBarLocation::West));
auto innerVLayout = new QVBoxLayout();
innerVLayout->setSpacing(0);
innerVLayout->setContentsMargins(0, 0, 0, 0);
innerVLayout->addWidget(sideBar(SideBarLocation::North));
innerVLayout->addWidget(dropArea());
innerVLayout->addWidget(sideBar(SideBarLocation::South));
layout->addLayout(innerVLayout);
layout->addWidget(sideBar(SideBarLocation::East));
} else {
layout->addWidget(dropArea());
}
setCentralWidget(centralWidget);
// qApp->installEventFilter(this);
@@ -84,3 +112,24 @@ void MainWindow::setCentralWidget(QWidget *w)
{
QMainWindow::setCentralWidget(w);
}
SideBar *MainWindow::sideBar(SideBarLocation location) const
{
return d->m_sideBars.value(location);
}
void MainWindow::resizeEvent(QResizeEvent *ev)
{
MainWindowBase::resizeEvent(ev);
onResized(ev); // Also call our own handler, since QtQuick doesn't have resizeEvent()
}
QMargins MainWindow::centerWidgetMargins() const
{
return { 1, 5, 1, 1};
}
QRect MainWindow::centralAreaGeometry() const
{
return centralWidget()->geometry();
}

View File

@@ -23,6 +23,8 @@
namespace KDDockWidgets {
class SideBar;
/**
* @brief The QMainwindow sub-class that the application should use to be able
* to dock KDDockWidget::DockWidget instances.
@@ -45,6 +47,13 @@ public:
///@brief Destructor
~MainWindow() override;
///@brief returns the sidebar for the specified location
SideBar *sideBar(SideBarLocation) const override;
protected:
void resizeEvent(QResizeEvent *) override;
QMargins centerWidgetMargins() const override;
QRect centralAreaGeometry() const override;
private:
using QMainWindow::setCentralWidget;
void setCentralWidget(QWidget *); // overridden just to make it private

View File

@@ -22,7 +22,10 @@
#include "DropArea_p.h"
#include "Frame_p.h"
#include "Utils_p.h"
#include "SideBar_p.h"
#include "Logging_p.h"
#include "Item_p.h"
#include "FrameworkWidgetFactory.h"
#include "DropAreaWithCentralFrame_p.h"
using namespace KDDockWidgets;
@@ -42,15 +45,20 @@ public:
return m_options & MainWindowOption_HasCentralFrame;
}
QRect rectForOverlay(Frame *, SideBarLocation) const;
SideBarLocation preferredSideBar(DockWidgetBase *) const;
void updateOverlayGeometry();
QString name;
QStringList affinities;
const MainWindowOptions m_options;
MainWindowBase *const q;
QPointer<DockWidgetBase> m_overlayedDockWidget;
DropAreaWithCentralFrame *const m_dropArea;
};
MainWindowBase::MainWindowBase(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
QWidgetOrQuick *parent, Qt::WindowFlags flags)
WidgetType *parent, Qt::WindowFlags flags)
: QMainWindowOrQuick(parent, flags)
, d(new Private(this, options))
{
@@ -149,6 +157,295 @@ void MainWindowBase::layoutParentContainerEqually(DockWidgetBase *dockWidget)
dropArea()->layoutParentContainerEqually(dockWidget);
}
QRect MainWindowBase::Private::rectForOverlay(Frame *frame, SideBarLocation location) const
{
SideBar *sb = q->sideBar(location);
if (!sb)
return {};
const QRect centralAreaGeo = q->centralAreaGeometry();
const QMargins centerWidgetMargins = q->centerWidgetMargins();
QRect rect;
const int margin = 1;
switch (location) {
case SideBarLocation::North:
case SideBarLocation::South: {
SideBar *leftSideBar = q->sideBar(SideBarLocation::West);
SideBar *rightSideBar = q->sideBar(SideBarLocation::East);
const int leftSideBarWidth = (leftSideBar && leftSideBar->isVisible()) ? leftSideBar->width()
: 0;
const int rightSideBarWidth = (rightSideBar && rightSideBar->isVisible()) ? rightSideBar->width()
: 0;
rect.setHeight(qMax(300, frame->minSize().height()));
rect.setWidth(centralAreaGeo.width() - margin * 2 - leftSideBarWidth - rightSideBarWidth);
rect.moveLeft(margin + leftSideBarWidth);
if (location == SideBarLocation::South) {
rect.moveTop(centralAreaGeo.bottom() - centerWidgetMargins.bottom() - rect.height() - sb->height());
} else {
rect.moveTop(centralAreaGeo.y() + sb->height() + centerWidgetMargins.top());
}
break;
}
case SideBarLocation::West:
case SideBarLocation::East: {
SideBar *topSideBar = q->sideBar(SideBarLocation::North);
SideBar *bottomSideBar = q->sideBar(SideBarLocation::South);
const int topSideBarHeight = (topSideBar && topSideBar->isVisible()) ? topSideBar->height()
: 0;
const int bottomSideBarHeight = (bottomSideBar && bottomSideBar->isVisible()) ? bottomSideBar->height()
: 0;
rect.setWidth(qMax(300, frame->minSize().width()));
rect.setHeight(centralAreaGeo.height() - topSideBarHeight - bottomSideBarHeight - centerWidgetMargins.top() - centerWidgetMargins.bottom());
rect.moveTop(sb->mapTo(q, QPoint(0, 0)).y() + topSideBarHeight - 1);
if (location == SideBarLocation::East) {
rect.moveLeft(centralAreaGeo.width() - rect.width() - sb->width() - centerWidgetMargins.right() - margin);
} else {
rect.moveLeft(margin + centralAreaGeo.x() + centerWidgetMargins.left() + sb->width());
}
break;
}
case SideBarLocation::None:
break;
}
return rect;
}
static SideBarLocation opposedSideBarLocationForBorder(Layouting::Item::LayoutBorderLocation loc)
{
switch (loc) {
case Layouting::Item::LayoutBorderLocation_North:
return SideBarLocation::South;
case Layouting::Item::LayoutBorderLocation_East:
return SideBarLocation::West;
case Layouting::Item::LayoutBorderLocation_West:
return SideBarLocation::East;
case Layouting::Item::LayoutBorderLocation_South:
return SideBarLocation::North;
case Layouting::Item::LayoutBorderLocation_All:
case Layouting::Item::LayoutBorderLocation_Verticals:
case Layouting::Item::LayoutBorderLocation_Horizontals:
case Layouting::Item::LayoutBorderLocation_None:
break;
}
qWarning() << Q_FUNC_INFO << "Unknown loc" << loc;
return SideBarLocation::None;
}
static SideBarLocation sideBarLocationForBorder(Layouting::Item::LayoutBorderLocations loc)
{
switch (loc) {
case Layouting::Item::LayoutBorderLocation_North:
return SideBarLocation::North;
case Layouting::Item::LayoutBorderLocation_East:
return SideBarLocation::East;
case Layouting::Item::LayoutBorderLocation_West:
return SideBarLocation::West;
case Layouting::Item::LayoutBorderLocation_South:
return SideBarLocation::South;
case Layouting::Item::LayoutBorderLocation_All:
case Layouting::Item::LayoutBorderLocation_Verticals:
case Layouting::Item::LayoutBorderLocation_Horizontals:
case Layouting::Item::LayoutBorderLocation_None:
break;
}
return SideBarLocation::None;
}
SideBarLocation MainWindowBase::Private::preferredSideBar(DockWidgetBase *dw) const
{
// TODO: Algorithm can still be made smarter
Layouting::Item *item = q->multiSplitter()->itemForFrame(dw->frame());
if (!item) {
qWarning() << Q_FUNC_INFO << "No item for dock widget";
return SideBarLocation::None;
}
const Layouting::Item::LayoutBorderLocations borders = item->adjacentLayoutBorders();
const qreal aspectRatio = dw->width() / (dw->height() * 1.0);
/// 1. It's touching all borders
if (borders == Layouting::Item::LayoutBorderLocation_All) {
return aspectRatio > 1.0 ? SideBarLocation::South
: SideBarLocation::East;
}
/// 2. It's touching 3 borders
for (auto borderLoc : { Layouting::Item::LayoutBorderLocation_North, Layouting::Item::LayoutBorderLocation_East,
Layouting::Item::LayoutBorderLocation_West, Layouting::Item::LayoutBorderLocation_South }) {
if (borders == (Layouting::Item::LayoutBorderLocation_All & ~borderLoc))
return opposedSideBarLocationForBorder(borderLoc);
}
/// 3. It's touching left and right borders
if ((borders & Layouting::Item::LayoutBorderLocation_Verticals) == Layouting::Item::LayoutBorderLocation_Verticals) {
// We could measure the distance to the top though.
return SideBarLocation::South;
}
/// 4. It's touching top and bottom borders
if ((borders & Layouting::Item::LayoutBorderLocation_Horizontals) == Layouting::Item::LayoutBorderLocation_Horizontals) {
// We could measure the distance to the left though.
return SideBarLocation::East;
}
// 5. It's in a corner
if (borders == (Layouting::Item::LayoutBorderLocation_West | Layouting::Item::LayoutBorderLocation_South)) {
return aspectRatio > 1.0 ? SideBarLocation::South
: SideBarLocation::West;
} else if (borders == (Layouting::Item::LayoutBorderLocation_East | Layouting::Item::LayoutBorderLocation_South)) {
return aspectRatio > 1.0 ? SideBarLocation::South
: SideBarLocation::East;
} else if (borders == (Layouting::Item::LayoutBorderLocation_West | Layouting::Item::LayoutBorderLocation_North)) {
return aspectRatio > 1.0 ? SideBarLocation::North
: SideBarLocation::West;
} else if (borders == (Layouting::Item::LayoutBorderLocation_East | Layouting::Item::LayoutBorderLocation_North)) {
return aspectRatio > 1.0 ? SideBarLocation::North
: SideBarLocation::East;
}
{
// 6. It's only touching 1 border
SideBarLocation loc = sideBarLocationForBorder(borders);
if (loc != SideBarLocation::None)
return loc;
}
// It's not touching any border, use aspect ratio.
return aspectRatio > 1.0 ? SideBarLocation::South
: SideBarLocation::West;
}
void MainWindowBase::Private::updateOverlayGeometry()
{
if (!m_overlayedDockWidget)
return;
SideBar *sb = q->sideBarForDockWidget(m_overlayedDockWidget);
if (!sb) {
qWarning() << Q_FUNC_INFO << "Expected a sidebar";
return;
}
m_overlayedDockWidget->frame()->QWidgetAdapter::setGeometry(rectForOverlay(m_overlayedDockWidget->frame(), sb->location()));
}
void MainWindowBase::moveToSideBar(DockWidgetBase *dw)
{
moveToSideBar(dw, d->preferredSideBar(dw));
}
void MainWindowBase::moveToSideBar(DockWidgetBase *dw, SideBarLocation location)
{
if (SideBar *sb = sideBar(location)) {
dw->forceClose();
sb->addDockWidget(dw);
} else {
// Shouldn't happen
qWarning() << Q_FUNC_INFO << "Minimization supported, probably disabled in Config::self().flags()";
}
}
void MainWindowBase::restoreFromSideBar(DockWidgetBase *dw)
{
// First un-overlay it, if it's overlayed
if (dw == d->m_overlayedDockWidget)
clearSideBarOverlay();
SideBar *sb = sideBarForDockWidget(dw);
if (!sb) {
// Doesn't happen
qWarning() << Q_FUNC_INFO << "Dock widget isn't in any sidebar";
return;
}
sb->removeDockWidget(dw);
dw->setFloating(false); // dock it
}
void MainWindowBase::overlayOnSideBar(DockWidgetBase *dw)
{
if (!dw)
return;
const SideBar *sb = sideBarForDockWidget(dw);
if (sb == nullptr) {
qWarning() << Q_FUNC_INFO << "You need to add the dock widget to the sidebar before you can overlay it";
return;
}
if (d->m_overlayedDockWidget == dw) {
// Already overlayed
return;
}
// We only support one overlay at a time, remove any existing overlay
clearSideBarOverlay();
auto frame = Config::self().frameworkWidgetFactory()->createFrame(this, FrameOption_IsOverlayed);
d->m_overlayedDockWidget = dw;
frame->addWidget(dw);
d->updateOverlayGeometry();
frame->QWidgetAdapter::show();
Q_EMIT dw->isOverlayedChanged(true);
}
void MainWindowBase::toggleOverlayOnSideBar(DockWidgetBase *dw)
{
const bool wasOverlayed = d->m_overlayedDockWidget == dw;
clearSideBarOverlay();
if (!wasOverlayed) {
overlayOnSideBar(dw);
}
}
void MainWindowBase::clearSideBarOverlay()
{
if (!d->m_overlayedDockWidget)
return;
Frame *frame = d->m_overlayedDockWidget->frame();
d->m_overlayedDockWidget->setParent(nullptr);
Q_EMIT d->m_overlayedDockWidget->isOverlayedChanged(false);
d->m_overlayedDockWidget = nullptr;
delete frame;
}
SideBar *MainWindowBase::sideBarForDockWidget(const DockWidgetBase *dw) const
{
for (auto loc : { SideBarLocation::North, SideBarLocation::South,
SideBarLocation::East, SideBarLocation::West }) {
if (SideBar *sb = sideBar(loc)) {
if (sb->contains(const_cast<DockWidgetBase *>(dw)))
return sb;
}
}
return nullptr;
}
DockWidgetBase *MainWindowBase::overlayedDockWidget() const
{
return d->m_overlayedDockWidget;
}
bool MainWindowBase::sideBarIsVisible(SideBarLocation loc) const
{
if (SideBar *sb = sideBar(loc))
return sb->isVisible();
return false;
}
void MainWindowBase::setUniqueName(const QString &uniqueName)
{
if (uniqueName.isEmpty())
@@ -163,6 +460,12 @@ void MainWindowBase::setUniqueName(const QString &uniqueName)
}
}
void MainWindowBase::onResized(QResizeEvent *)
{
if (d->m_overlayedDockWidget)
d->updateOverlayGeometry();
}
bool MainWindowBase::deserialize(const LayoutSaver::MainWindow &mw)
{
if (mw.options != options()) {

View File

@@ -26,6 +26,7 @@
#include "LayoutSaver_p.h"
#include <QVector>
#include <QMargins>
namespace KDDockWidgets {
@@ -34,6 +35,7 @@ class Frame;
class DropArea;
class MultiSplitter;
class DropAreaWithCentralFrame;
class SideBar;
/**
* @brief The MainWindow base-class. MainWindow and MainWindowBase are only
@@ -52,7 +54,7 @@ class DOCKS_EXPORT MainWindowBase : public QMainWindow
public:
typedef QVector<MainWindowBase*> List;
explicit MainWindowBase(const QString &uniqueName, MainWindowOptions options = MainWindowOption_HasCentralFrame,
QWidgetOrQuick *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
WidgetType *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
~MainWindowBase() override;
@@ -131,8 +133,45 @@ public:
/// sub-tree.
void layoutParentContainerEqually(DockWidgetBase *dockWidget);
///@brief Moves the dock widget into one of the MainWindow's sidebar.
/// Means the dock widget is removed from the layout, and the sidebar shows a button that if pressed
/// will toggle the dock widget's visibility as an overlay over the layout. This is the auto-hide
/// functionality.
///
/// The chosen side bar will depend on some heuristics, mostly proximity.
void moveToSideBar(DockWidgetBase *);
/// @brief overload that allows to specify which sidebar to use, instead of using heuristics.
void moveToSideBar(DockWidgetBase *, SideBarLocation);
/// @brief Removes the dock widget from the sidebar and docks it into the main window again
void restoreFromSideBar(DockWidgetBase *);
///@brief Shows the dock widget overlayed on top of the main window, placed next to the sidebar
void overlayOnSideBar(DockWidgetBase *);
///@brief Shows or hides an overlay. It's assumed the dock widget is already in a side-bar.
void toggleOverlayOnSideBar(DockWidgetBase *);
/// @brief closes any overlayed dock widget. The sidebar still displays them as button.
void clearSideBarOverlay();
/// @brief Returns the sidebar this dockwidget is in. nullptr if not in any.
SideBar *sideBarForDockWidget(const DockWidgetBase *) const;
/// @brief returns the dock widget which is currently overlayed. nullptr if none.
/// This is only relevant when using the auto-hide and side-bar feature.
DockWidgetBase *overlayedDockWidget() const;
/// @brief Returns whether the specified sidebar is visible
bool sideBarIsVisible(SideBarLocation) const;
protected:
void setUniqueName(const QString &uniqueName);
void onResized(QResizeEvent *); // Because QtQuick doesn't have resizeEvent()
virtual QMargins centerWidgetMargins() const = 0;
virtual SideBar* sideBar(SideBarLocation) const = 0;
virtual QRect centralAreaGeometry() const { return {}; }
Q_SIGNALS:
void uniqueNameChanged();

View File

@@ -79,6 +79,8 @@ public:
, LayoutGuestWidgetBase(this)
{
}
~LayoutGuestWidget() override;
};
}

View File

@@ -0,0 +1 @@
#include "../../../../private/indicators/ClassicIndicators_p.h"

View File

@@ -0,0 +1 @@
#include "../../../../private/indicators/SegmentedIndicators_p.h"

View File

@@ -0,0 +1,12 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sergio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "../../../../private/widgets/SideBarWidget_p.h"

BIN
src/img/auto-hide-1.5x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

BIN
src/img/auto-hide-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

BIN
src/img/auto-hide.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
src/img/close-1.5x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 B

BIN
src/img/close-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

BIN
src/img/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

BIN
src/img/dock-float-1.5x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

BIN
src/img/dock-float-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

BIN
src/img/dock-float.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

BIN
src/img/max-1.5x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

BIN
src/img/max-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

BIN
src/img/max.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

BIN
src/img/min-1.5x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

BIN
src/img/min-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

BIN
src/img/min.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

BIN
src/img/unauto-hide-2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

BIN
src/img/unauto-hide.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@@ -14,6 +14,9 @@
#include "Logging_p.h"
#include "Position_p.h"
#include "MultiSplitter_p.h"
#include "QWidgetAdapter.h"
#include "Config.h"
#include "SideBar_p.h"
#include <QPointer>
#include <QDebug>
@@ -52,6 +55,9 @@ DockRegistry::DockRegistry(QObject *parent)
KDDockWidgets::registerQmlTypes();
#endif
connect(qApp, &QGuiApplication::focusObjectChanged,
this, &DockRegistry::onFocusObjectChanged);
initKDDockWidgetResources();
}
@@ -65,6 +71,35 @@ void DockRegistry::maybeDelete()
delete this;
}
void DockRegistry::onFocusObjectChanged(QObject *obj)
{
DockWidgetBase *const unfocusedDW = m_focusedDockWidget.data();
DockWidgetBase *newFocusedDockWidget = nullptr;
// Check if it's inside a dock widget:
auto p = qobject_cast<WidgetType*>(obj);
while (p) {
if (auto dw = qobject_cast<DockWidgetBase*>(p)) {
newFocusedDockWidget = dw;
break;
}
p = KDDockWidgets::Private::parentWidget(p);
}
// Nothing changed
if (m_focusedDockWidget.data() == newFocusedDockWidget)
return;
m_focusedDockWidget = newFocusedDockWidget;
if (unfocusedDW)
Q_EMIT unfocusedDW->isFocusedChanged(false);
if (m_focusedDockWidget)
Q_EMIT m_focusedDockWidget->isFocusedChanged(true);
}
bool DockRegistry::isEmpty() const
{
return m_dockWidgets.isEmpty() && m_mainWindows.isEmpty() && m_nestedWindows.isEmpty();
@@ -119,6 +154,56 @@ QStringList DockRegistry::dockWidgetNames() const
return names;
}
bool DockRegistry::isProbablyObscured(QWindow *window, FloatingWindow *exclude) const
{
if (!window)
return false;
const QRect geo = window->geometry();
for (FloatingWindow *fw : m_nestedWindows) {
QWindow *fwWindow = fw->QWidgetAdapter::windowHandle();
if (fw == exclude || fwWindow == window)
continue;
if (fwWindow->geometry().intersects(geo)) {
// fw might be bellow, but we don't have a way to check. So be conservative and return true.
return true;
}
}
// Floating windows are Tool (keep above), unless we disabled it in Config
const bool targetIsToolWindow = !(Config::self().flags() & Config::Flag_DontUseUtilityFloatingWindows) && floatingWindowForHandle(window) != nullptr;
for (MainWindowBase *mw : m_mainWindows) {
QWindow *mwWindow = mw->window()->windowHandle();
if (mwWindow != window && !targetIsToolWindow && mwWindow->geometry().intersects(geo)) {
// Two main windows that intersect. Return true. If the target is a tool window it will be above, so we don't care.
return true;
}
}
return false;
}
SideBarLocation DockRegistry::sideBarLocationForDockWidget(const DockWidgetBase *dw) const
{
if (SideBar *sb = sideBarForDockWidget(dw))
return sb->location();
return SideBarLocation::None;
}
SideBar *DockRegistry::sideBarForDockWidget(const DockWidgetBase *dw) const
{
for (auto mw : m_mainWindows) {
if (SideBar *sb = mw->sideBarForDockWidget(dw))
return sb;
}
return nullptr;
}
MainWindowBase::List DockRegistry::mainWindowsWithAffinity(const QStringList &affinities) const
{
MainWindowBase::List result;
@@ -175,6 +260,9 @@ void DockRegistry::registerDockWidget(DockWidgetBase *dock)
void DockRegistry::unregisterDockWidget(DockWidgetBase *dock)
{
if (m_focusedDockWidget == dock)
m_focusedDockWidget = nullptr;
m_dockWidgets.removeOne(dock);
maybeDelete();
}
@@ -475,7 +563,35 @@ bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
m_nestedWindows.append(fw);
}
}
} else if (event->type() == QEvent::MouseButtonPress) {
if (!(Config::self().flags() & Config::Flag_AutoHideSupport))
return false;
auto p = watched;
while (p) {
if (auto dw = qobject_cast<DockWidgetBase*>(p)) {
onDockWidgetPressed(dw);
return false;
}
p = p->parent();
}
}
return false;
}
void DockRegistry::onDockWidgetPressed(DockWidgetBase *dw)
{
// Here we implement "auto-hide". If there's a overlayed dock widget, we hide it if some other
// dock widget is clicked.
MainWindowBase *mainWindow = dw->mainWindow();
if (!mainWindow) // Only docked widgets are interesting
return;
DockWidgetBase *overlayedDockWidget = mainWindow->overlayedDockWidget();
if (overlayedDockWidget && dw != overlayedDockWidget) {
mainWindow->clearSideBarOverlay();
}
}

View File

@@ -18,6 +18,7 @@
#include <QVector>
#include <QObject>
#include <QPointer>
/**
* DockRegistry is a singleton that knows about all DockWidgets.
@@ -27,6 +28,8 @@
namespace KDDockWidgets
{
class SideBar;
class DOCKS_EXPORT DockRegistry : public QObject
{
Q_OBJECT
@@ -48,6 +51,8 @@ public:
void registerFrame(Frame *);
void unregisterFrame(Frame *);
DockWidgetBase *focusedDockWidget() const;
DockWidgetBase *dockByName(const QString &) const;
MainWindowBase *mainWindowByName(const QString &) const;
@@ -162,17 +167,35 @@ public:
/// @brief Returns a list of all known dock widget unique names
QStringList dockWidgetNames() const;
/// @brief returns if the specified window has some other window on top (with higher Z)
/// This is an approximation, as we don't have ways to compare Z, so we mostly intersect
/// geometries.
/// @param target The window which we want to know if it's probably obscured
/// @param exclude This window should not be counted as an obscurer. (It's being dragged).
bool isProbablyObscured(QWindow *target, FloatingWindow *exclude) const;
///@brief Returns whether the specified dock widget is in a side bar, and which.
/// SideBarLocation::None is returned if it's not in a sidebar.
/// This is only relevant when using the auto-hide and side-bar feature.
SideBarLocation sideBarLocationForDockWidget(const DockWidgetBase *) const;
///@brief Overload that returns the SideBar itself
SideBar* sideBarForDockWidget(const DockWidgetBase *) const;
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private:
explicit DockRegistry(QObject *parent = nullptr);
void onDockWidgetPressed(DockWidgetBase *dw);
void maybeDelete();
void onFocusObjectChanged(QObject *);
bool m_isProcessingAppQuitEvent = false;
DockWidgetBase::List m_dockWidgets;
MainWindowBase::List m_mainWindows;
Frame::List m_frames;
QVector<FloatingWindow*> m_nestedWindows;
QVector<MultiSplitter*> m_layouts;
QPointer<DockWidgetBase> m_focusedDockWidget;
};
}

View File

@@ -175,6 +175,27 @@ void StateDragging::onEntry(QEvent *)
q->m_windowBeingDragged = q->m_draggable->makeWindow();
if (q->m_windowBeingDragged) {
#ifdef Q_OS_WIN
# if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
if (!q->m_nonClientDrag && KDDockWidgets::usesNativeDraggingAndResizing()) {
// Started as a client move, as the dock widget was docked,
// but now that we're dragging it as a floating window, switch to native drag
FloatingWindow *fw = q->m_windowBeingDragged->floatingWindow();
q->m_nonClientDrag = true;
q->m_windowBeingDragged.reset();
const HWND hwnd = HWND(fw->windowHandle()->winId());
q->m_windowBeingDragged = fw->makeWindow();
QWindow *window = fw->windowHandle();
window->startSystemMove();
// Mouse press was done in another window, so we need to ungrab
ReleaseCapture();
PostMessage(hwnd, WM_SYSCOMMAND, 0xF012, 0); // SC_DRAGMOVE
}
# endif
#endif
qCDebug(state) << "StateDragging entered. m_draggable=" << q->m_draggable << "; m_windowBeingDragged=" << q->m_windowBeingDragged->floatingWindow();
auto fw = q->m_windowBeingDragged->floatingWindow();
@@ -337,6 +358,18 @@ void DragController::releaseMouse(QWidgetOrQuick *target)
}
}
FloatingWindow *DragController::windowBeingDragged() const
{
return m_windowBeingDragged ? m_windowBeingDragged->floatingWindow()
: nullptr;
}
void DragController::enableFallbackMouseGrabber()
{
if (!m_fallbackMouseGrabber)
m_fallbackMouseGrabber = new FallbackMouseGrabber(this);
}
static QMouseEvent *mouseEvent(QEvent *e)
{
switch (e->type()) {
@@ -371,7 +404,8 @@ bool DragController::eventFilter(QObject *o, QEvent *e)
if (!w)
return QStateMachine::eventFilter(o, e);
qCDebug(mouseevents) << "DragController::eventFilter e=" << e->type() << "; o=" << o;
qCDebug(mouseevents) << "DragController::eventFilter e=" << e->type() << "; o=" << o
<< "; m_nonClientDrag=" << m_nonClientDrag;
switch (e->type()) {
case QEvent::NonClientAreaMouseButtonPress: {
@@ -427,14 +461,16 @@ template <typename T>
static WidgetType* qtTopLevelUnderCursor_impl(QPoint globalPos, const QVector<QWindow*> &windows, T windowBeingDragged)
{
for (int i = windows.size() -1; i >= 0; --i) {
auto tl = KDDockWidgets::Private::widgetForWindow(windows.at(i));
QWindow *window = windows.at(i);
auto tl = KDDockWidgets::Private::widgetForWindow(window);
if (!tl->isVisible() || tl == windowBeingDragged || KDDockWidgets::Private::isMinimized(tl))
continue;
if (windowBeingDragged && KDDockWidgets::Private::windowForWidget(windowBeingDragged) == KDDockWidgets::Private::windowForWidget(tl))
continue;
if (KDDockWidgets::Private::geometry(tl).contains(globalPos)) {
if (window->geometry().contains(globalPos)) {
qCDebug(toplevels) << Q_FUNC_INFO << "Found top-level" << tl;
return tl;
}

View File

@@ -12,6 +12,8 @@
#ifndef KD_DRAGCONTROLLER_P_H
#define KD_DRAGCONTROLLER_P_H
#include "docks_export.h"
#include "TitleBar_p.h"
#include "WindowBeingDragged_p.h"
@@ -26,7 +28,7 @@ class DropArea;
class Draggable;
class FallbackMouseGrabber;
class DragController : public QStateMachine
class DOCKS_EXPORT DragController : public QStateMachine
{
Q_OBJECT
public:
@@ -50,6 +52,11 @@ public:
void grabMouseFor(QWidgetOrQuick *);
void releaseMouse(QWidgetOrQuick *);
FloatingWindow *windowBeingDragged() const;
/// Experimental, internal, not for general use.
void enableFallbackMouseGrabber();
Q_SIGNALS:
void mousePressed();
void manhattanLengthMove();

View File

@@ -71,6 +71,13 @@ Frame *DropArea::frameContainingPos(QPoint globalPos) const
return nullptr;
}
void DropArea::updateFloatingActions()
{
const Frame::List frames = this->frames();
for (Frame *frame : frames)
frame->updateFloatingActions();
}
Layouting::Item *DropArea::centralFrame() const
{
for (Layouting::Item *item : this->items()) {
@@ -103,6 +110,8 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location, DockWidgetBa
dw->saveLastFloatingGeometry();
const bool hadSingleFloatingFrame = hasSingleFloatingFrame();
// Check if the dock widget already exists in the layout
if (contains(dw)) {
Frame *oldFrame = dw->frame();
@@ -124,6 +133,12 @@ void DropArea::addDockWidget(DockWidgetBase *dw, Location location, DockWidgetBa
} else {
addWidget(frame, location, relativeToFrame, DefaultSizeMode::Fair, option);
}
if (hadSingleFloatingFrame && !hasSingleFloatingFrame()) {
// The dock widgets that already existed in our layout need to have their floatAction() updated
// otherwise it's still checked. Only the dropped dock widget got updated
updateFloatingActions();
}
}
bool DropArea::contains(DockWidgetBase *dw) const
@@ -131,6 +146,12 @@ bool DropArea::contains(DockWidgetBase *dw) const
return dw->frame() && MultiSplitter::contains(dw->frame());
}
bool DropArea::hasSingleFloatingFrame() const
{
const Frame::List frames = this->frames();
return frames.size() == 1 && frames.first()->isFloating();
}
QStringList DropArea::affinities() const
{
if (auto mw = mainWindow()) {
@@ -197,15 +218,24 @@ bool DropArea::drop(FloatingWindow *droppedWindow, QPoint globalPos)
qCDebug(dropping) << "DropArea::drop:" << droppedWindow;
hover(droppedWindow, globalPos);
auto droploc = m_dropIndicatorOverlay->currentDropLocation();
Frame *acceptingFrame = m_dropIndicatorOverlay->hoveredFrame();
if (!(acceptingFrame || isOutterLocation(m_dropIndicatorOverlay->currentDropLocation()))) {
qWarning() << "DropArea::drop: asserted with frame=" << acceptingFrame << "; Location=" << m_dropIndicatorOverlay->currentDropLocation();
return false;
}
bool result = true;
return drop(droppedWindow, acceptingFrame, droploc);
}
bool DropArea::drop(FloatingWindow *droppedWindow, Frame *acceptingFrame,
DropIndicatorOverlayInterface::DropLocation droploc)
{
bool result = true;
const bool needToFocusNewlyDroppedWidgets = Config::self().flags() & Config::Flag_TitleBarIsFocusable;
const DockWidgetBase::List droppedDockWidgets = needToFocusNewlyDroppedWidgets ? droppedWindow->multiSplitter()->dockWidgets()
: DockWidgetBase::List(); // just so save some memory allocations for the case where this variable isn't used
auto droploc = m_dropIndicatorOverlay->currentDropLocation();
switch (droploc) {
case DropIndicatorOverlayInterface::DropLocation_Left:
case DropIndicatorOverlayInterface::DropLocation_Top:
@@ -221,7 +251,7 @@ bool DropArea::drop(FloatingWindow *droppedWindow, QPoint globalPos)
break;
case DropIndicatorOverlayInterface::DropLocation_Center:
qCDebug(hovering) << "Tabbing" << droppedWindow << "into" << acceptingFrame;
if (!validateAffinity(droppedWindow))
if (!validateAffinity(droppedWindow, acceptingFrame))
return false;
acceptingFrame->addWidget(droppedWindow);
break;
@@ -232,9 +262,23 @@ bool DropArea::drop(FloatingWindow *droppedWindow, QPoint globalPos)
break;
}
if (result)
if (result) {
// Window receiving the drop gets raised:
raiseAndActivate();
if (needToFocusNewlyDroppedWidgets) {
// Let's also focus the newly dropped dock widget
if (droppedDockWidgets.size() > 0) {
// If more than 1 was dropped, we only focus the first one
Frame *frame = droppedDockWidgets.first()->frame();
frame->FocusScope::focus(Qt::MouseFocusReason);
} else {
// Doesn't happen.
qWarning() << Q_FUNC_INFO << "Nothing was dropped?";
}
}
}
return result;
}
@@ -253,7 +297,11 @@ bool DropArea::drop(QWidgetOrQuick *droppedWindow, KDDockWidgets::Location locat
if (!validateAffinity(floatingWindow))
return false;
const bool hadSingleFloatingFrame = hasSingleFloatingFrame();
addMultiSplitter(floatingWindow->dropArea(), location, relativeTo, DefaultSizeMode::FairButFloor);
if (hadSingleFloatingFrame != hasSingleFloatingFrame())
updateFloatingActions();
floatingWindow->scheduleDeleteLater();
return true;
} else {
@@ -271,14 +319,19 @@ void DropArea::removeHover()
}
template<typename T>
bool DropArea::validateAffinity(T *window) const
bool DropArea::validateAffinity(T *window, Frame *acceptingFrame) const
{
if (!DockRegistry::self()->affinitiesMatch(window->affinities(), affinities())) {
// Commented the warning, so we don't warn when hovering over
//qWarning() << Q_FUNC_INFO << "Refusing to dock widget with incompatible affinity."
//<< window->affinityName() << affinityName();
return false;
}
if (acceptingFrame) {
// We're dropping into another frame (as tabbed), so also check the affinity of the frame
// not only of the main window, which might be more forgiving
if (!DockRegistry::self()->affinitiesMatch(window->affinities(), acceptingFrame->affinities())) {
return false;
}
}
return true;
}

View File

@@ -29,7 +29,6 @@ namespace KDDockWidgets {
class Frame;
class Draggable;
class DropIndicatorOverlayInterface;
struct WindowBeingDragged;
/**
@@ -44,8 +43,8 @@ public:
void removeHover();
void hover(FloatingWindow *floatingWindow, QPoint globalPos);
///@brief Called when a user drops a widget via DND
bool drop(FloatingWindow *droppedWindow, QPoint globalPos);
bool drop(QWidgetOrQuick *droppedwindow, KDDockWidgets::Location location, Frame *relativeTo);
int numFrames() const;
Frame::List frames() const;
@@ -55,6 +54,10 @@ public:
bool contains(DockWidgetBase *) const;
/// Returns whether this layout has a single dock widget which is floating
/// Implies it's in a FloatingWindow and that it has only one dock widget
bool hasSingleFloatingFrame() const;
QStringList affinities() const;
void layoutParentContainerEqually(DockWidgetBase *);
private:
@@ -63,9 +66,15 @@ private:
friend class TestDocks;
friend class DropIndicatorOverlayInterface;
friend class AnimatedIndicators;
friend class FloatingWindow;
template <typename T>
bool validateAffinity(T *) const;
bool validateAffinity(T *, Frame *acceptingFrame = nullptr) const;
bool drop(FloatingWindow *droppedWindow, Frame *acceptingFrame, DropIndicatorOverlayInterface::DropLocation);
bool drop(QWidgetOrQuick *droppedwindow, KDDockWidgets::Location location, Frame *relativeTo);
Frame *frameContainingPos(QPoint globalPos) const;
void updateFloatingActions();
bool m_inDestructor = false;
QString m_affinityName;
DropIndicatorOverlayInterface *m_dropIndicatorOverlay = nullptr;

View File

@@ -27,33 +27,45 @@ DropIndicatorOverlayInterface::DropIndicatorOverlayInterface(DropArea *dropArea)
void DropIndicatorOverlayInterface::setWindowBeingDragged(const FloatingWindow *window)
{
if (window != m_windowBeingDragged) {
m_windowBeingDragged = window;
if (m_windowBeingDragged) {
setGeometry(m_dropArea->QWidgetAdapter::rect());
raise();
} else {
setHoveredFrame(nullptr);
}
if (window == m_windowBeingDragged)
return;
updateVisibility();
m_windowBeingDragged = window;
if (m_windowBeingDragged) {
setGeometry(m_dropArea->QWidgetAdapter::rect());
raise();
} else {
setHoveredFrame(nullptr);
}
setVisible(m_windowBeingDragged != nullptr);
updateVisibility();
}
QRect DropIndicatorOverlayInterface::hoveredFrameRect() const
{
return m_hoveredFrameRect;
}
void DropIndicatorOverlayInterface::setHoveredFrame(Frame *frame)
{
if (frame != m_hoveredFrame) {
if (m_hoveredFrame)
disconnect(m_hoveredFrame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
if (frame == m_hoveredFrame)
return;
m_hoveredFrame = frame;
if (m_hoveredFrame)
connect(frame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
if (m_hoveredFrame)
disconnect(m_hoveredFrame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
updateVisibility();
Q_EMIT hoveredFrameChanged(m_hoveredFrame);
onHoveredFrameChanged(m_hoveredFrame);
m_hoveredFrame = frame;
if (m_hoveredFrame) {
connect(frame, &QObject::destroyed, this, &DropIndicatorOverlayInterface::onFrameDestroyed);
setHoveredFrameRect(m_hoveredFrame->QWidgetAdapter::geometry());
} else {
setHoveredFrameRect(QRect());
}
updateVisibility();
Q_EMIT hoveredFrameChanged(m_hoveredFrame);
onHoveredFrameChanged(m_hoveredFrame);
}
bool DropIndicatorOverlayInterface::isHovered() const
@@ -61,6 +73,11 @@ bool DropIndicatorOverlayInterface::isHovered() const
return m_windowBeingDragged != nullptr;
}
DropIndicatorOverlayInterface::DropLocation DropIndicatorOverlayInterface::currentDropLocation() const
{
return m_currentDropLocation;
}
KDDockWidgets::Location DropIndicatorOverlayInterface::multisplitterLocationFor(DropIndicatorOverlayInterface::DropLocation dropLoc)
{
switch (dropLoc) {
@@ -92,10 +109,25 @@ void DropIndicatorOverlayInterface::onFrameDestroyed()
void DropIndicatorOverlayInterface::onHoveredFrameChanged(Frame *)
{
}
void DropIndicatorOverlayInterface::setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation location)
{
m_currentDropLocation = location;
if (m_currentDropLocation != location) {
m_currentDropLocation = location;
Q_EMIT currentDropLocationChanged();
}
}
void DropIndicatorOverlayInterface::hover(QPoint globalPos)
{
hover_impl(globalPos);
}
void DropIndicatorOverlayInterface::setHoveredFrameRect(QRect rect)
{
if (m_hoveredFrameRect != rect) {
m_hoveredFrameRect = rect;
Q_EMIT hoveredFrameRectChanged();
}
}

View File

@@ -22,17 +22,12 @@ namespace KDDockWidgets {
class FloatingWindow;
class DropArea;
class DOCKS_EXPORT_FOR_UNIT_TESTS DropIndicatorOverlayInterface : public QWidgetAdapter
class DOCKS_EXPORT DropIndicatorOverlayInterface : public QWidgetAdapter
{
Q_OBJECT
Q_PROPERTY(QRect hoveredFrameRect READ hoveredFrameRect NOTIFY hoveredFrameRectChanged)
Q_PROPERTY(KDDockWidgets::DropIndicatorOverlayInterface::DropLocation currentDropLocation READ currentDropLocation NOTIFY currentDropLocationChanged)
public:
enum Type {
TypeNone = 0,
TypeClassic = 1,
TypeAnimated = 2
};
Q_ENUM(Type)
enum DropLocation {
DropLocation_None = 0,
DropLocation_Left,
@@ -43,36 +38,45 @@ public:
DropLocation_OutterLeft,
DropLocation_OutterTop,
DropLocation_OutterRight,
DropLocation_OutterBottom
DropLocation_OutterBottom,
DropLocation_First = DropLocation_Left,
DropLocation_Last = DropLocation_OutterBottom,
};
Q_ENUM(DropLocation)
explicit DropIndicatorOverlayInterface(DropArea *dropArea);
void setHoveredFrame(Frame *);
void setWindowBeingDragged(const FloatingWindow *);
QRect hoveredFrameRect() const;
bool isHovered() const;
DropLocation currentDropLocation() const { return m_currentDropLocation; }
DropLocation currentDropLocation() const;
Frame *hoveredFrame() const { return m_hoveredFrame; }
void setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation location);
virtual Type indicatorType() const = 0;
virtual void hover(QPoint globalPos) = 0;
void hover(QPoint globalPos);
virtual QPoint posForIndicator(DropLocation) const = 0; // Used by unit-tests only
virtual QPoint posForIndicator(DropLocation) const { return {}; }; // Used by unit-tests only
static KDDockWidgets::Location multisplitterLocationFor(DropLocation);
Q_SIGNALS:
void hoveredFrameChanged(KDDockWidgets::Frame *);
void hoveredFrameRectChanged();
void currentDropLocationChanged();
private:
void onFrameDestroyed();
void setHoveredFrameRect(QRect);
QRect m_hoveredFrameRect;
DropLocation m_currentDropLocation = DropLocation_None;
protected:
virtual void hover_impl(QPoint globalPos) = 0;
virtual void onHoveredFrameChanged(Frame *);
virtual void updateVisibility() = 0;
virtual void updateVisibility() {};
Frame *m_hoveredFrame = nullptr;
DropLocation m_currentDropLocation = DropLocation_None;
QPointer<const FloatingWindow> m_windowBeingDragged;
DropArea *const m_dropArea;
};

View File

@@ -25,9 +25,11 @@
#include <QCloseEvent>
#include <QAbstractNativeEventFilter>
#include <QWindow>
#include <QScopedValueRollback>
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
#if defined(Q_OS_WIN)
# include <Windows.h>
# include <dwmapi.h>
#endif
using namespace KDDockWidgets;
@@ -73,41 +75,23 @@ public:
}
#endif
FloatingWindow::FloatingWindow(MainWindowBase *parent)
: QWidgetAdapter(parent, KDDockWidgets::usesNativeDraggingAndResizing() ? Qt::Window : Qt::Tool)
, Draggable(this, KDDockWidgets::usesNativeDraggingAndResizing()) // FloatingWindow is only draggable when using a native title bar. Otherwise the KDDockWidgets::TitleBar is the draggable
, m_dropArea(new DropArea(this))
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
static Qt::WindowFlags windowFlagsToUse()
{
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
m_nchittestFilter = new NCHITTESTEventFilter(this);
qApp->installNativeEventFilter(m_nchittestFilter);
}
#endif
if (KDDockWidgets::usesNativeDraggingAndResizing())
return Qt::Window;
DockRegistry::self()->registerNestedWindow(this);
qCDebug(creation) << "FloatingWindow()" << this;
if (Config::self().flags() & Config::Flag_internal_DontUseQtToolWindowsForFloatingWindows)
return Qt::Window;
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
# if QT_VERSION < 0x051000
// On Windows with Qt 5.9 (and maybe later but we don't care), the WM_NCALCSIZE isn't being processed unless we explicitly create the window.
// So create it now, otherwise floating dock widgets will show a native title bar until resized.
create();
# endif
#endif
maybeCreateResizeHandler();
updateTitleBarVisibility();
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::onFrameCountChanged);
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::numFramesChanged);
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::onVisibleFrameCountChanged);
m_layoutDestroyedConnection = connect(m_dropArea, &QObject::destroyed, this, &FloatingWindow::scheduleDeleteLater);
return Qt::Tool;
}
static MainWindowBase* hackFindParentHarder(Frame *frame, MainWindowBase *candidateParent)
{
if (Config::self().flags() & Config::Flag_internal_DontUseParentForFloatingWindows) {
return nullptr;
}
// TODO: Using a parent helps the floating windows stay in front of the main window always.
// We're not receiving the parent via ctor argument as the app can have multiple-main windows,
// so use a hack here.
@@ -136,6 +120,53 @@ static MainWindowBase* hackFindParentHarder(Frame *frame, MainWindowBase *candid
}
}
MainWindowBase *actualParent(MainWindowBase *candidate)
{
return (Config::self().flags() & Config::Flag_internal_DontUseParentForFloatingWindows)
? nullptr
: candidate;
}
FloatingWindow::FloatingWindow(MainWindowBase *parent)
: QWidgetAdapter(actualParent(parent), windowFlagsToUse())
, Draggable(this, KDDockWidgets::usesNativeDraggingAndResizing()) // FloatingWindow is only draggable when using a native title bar. Otherwise the KDDockWidgets::TitleBar is the draggable
, m_dropArea(new DropArea(this))
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
{
#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
// On Windows with Qt 5.9 (and maybe earlier), the WM_NCALCSIZE isn't being processed unless we explicitly create the window.
// So create it now, otherwise floating dock widgets will show a native title bar until resized.
create();
if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
m_nchittestFilter = new NCHITTESTEventFilter(this);
qApp->installNativeEventFilter(m_nchittestFilter);
connect(windowHandle(), &QWindow::screenChanged, this, [this] {
// Qt honors our frame hijacking usually... but when screen changes we must give it a nudge.
// Otherwise what Qt thinks is the client area is not what Windows knows it is.
// SetWindowPos() will trigger an NCCALCSIZE message, which Qt will intercept and take note of the margins we're using.
SetWindowPos(HWND(winId()), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
});
// Show drop-shadow:
MARGINS margins = {0, 0, 0, 1}; // arbitrary, just needs to be > 0 it seems
DwmExtendFrameIntoClientArea(HWND(winId()), &margins);
}
#endif
DockRegistry::self()->registerNestedWindow(this);
qCDebug(creation) << "FloatingWindow()" << this;
maybeCreateResizeHandler();
updateTitleBarVisibility();
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::onFrameCountChanged);
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::numFramesChanged);
connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged, this, &FloatingWindow::onVisibleFrameCountChanged);
m_layoutDestroyedConnection = connect(m_dropArea, &QObject::destroyed, this, &FloatingWindow::scheduleDeleteLater);
}
FloatingWindow::FloatingWindow(Frame *frame, MainWindowBase *parent)
: FloatingWindow(hackFindParentHarder(frame, parent))
{
@@ -197,6 +228,11 @@ DockWidgetBase *FloatingWindow::singleDockWidget() const
return nullptr;
}
const DockWidgetBase::List FloatingWindow::dockWidgets() const
{
return m_dropArea->dockWidgets();
}
const Frame::List FloatingWindow::frames() const
{
Q_ASSERT(m_dropArea);
@@ -239,7 +275,15 @@ MultiSplitter *FloatingWindow::multiSplitter() const
bool FloatingWindow::isInDragArea(QPoint globalPoint) const
{
return dragRect().adjusted(8, 8, 0, 0).contains(globalPoint);
#ifdef Q_OS_WIN
// A click near the border will still send a Qt::NonClientMousePressEvent. We shouldn't
// interpret that as a drag, as it's for a native resize.
// Keep track of how we handled the WM_NCHITTEST
if (m_lastHitTest != 0 && m_lastHitTest != HTCAPTION)
return false;
#endif
return dragRect().contains(globalPoint);
}
bool FloatingWindow::anyNonClosable() const
@@ -296,6 +340,8 @@ void FloatingWindow::onFrameCountChanged(int count)
scheduleDeleteLater();
} else {
updateTitleBarVisibility();
if (count == 1) // if something was removed, then our single dock widget is floating, we need to check the QAction
dropArea()->updateFloatingActions();
}
}
@@ -309,6 +355,10 @@ void FloatingWindow::onVisibleFrameCountChanged(int count)
void FloatingWindow::updateTitleBarVisibility()
{
if (m_updatingTitleBarVisibility)
return; // Break recursion
QScopedValueRollback<bool> guard(m_updatingTitleBarVisibility, true);
updateTitleAndIcon();
bool visible = true;
@@ -316,7 +366,8 @@ void FloatingWindow::updateTitleBarVisibility()
if (KDDockWidgets::usesNativeTitleBar()) {
visible = false;
} else {
if (Config::self().flags() & Config::Flag_HideTitleBarWhenTabsVisible) {
const auto flags = Config::self().flags();
if ((flags & Config::Flag_HideTitleBarWhenTabsVisible) && !(flags & Config::Flag_AlwaysTitleBarWhenFloating)) {
if (hasSingleFrame()) {
visible = !frames().first()->hasTabsVisible();
}
@@ -349,10 +400,10 @@ void FloatingWindow::updateTitleAndIcon()
m_titleBar->setTitle(title);
m_titleBar->setIcon(icon);
if (KDDockWidgets::usesNativeTitleBar()) {
setWindowTitle(title);
setWindowIcon(icon);
}
// Even without a native title bar it's nice to set the window title/icon, so it shows
// in the taskbar (when minimization is supported), or Alt-Tab (in supporting Window Managers)
setWindowTitle(title);
setWindowIcon(icon);
}
void FloatingWindow::onCloseEvent(QCloseEvent *e)
@@ -417,3 +468,14 @@ QRect FloatingWindow::dragRect() const
return rect;
}
bool FloatingWindow::event(QEvent *ev)
{
if (ev->type() == QEvent::ActivationChange) {
// Since QWidget is missing a signal for window activation
Q_EMIT activatedChanged();
}
return QWidgetAdapter::event(ev);
}

View File

@@ -49,9 +49,15 @@ public:
std::unique_ptr<WindowBeingDragged> makeWindow() override;
DockWidgetBase *singleDockWidget() const override;
const QVector<DockWidgetBase*> dockWidgets() const;
const Frame::List frames() const;
DropArea *dropArea() const { return m_dropArea; }
#ifdef Q_OS_WIN
void setLastHitTest(int hitTest) {
m_lastHitTest = hitTest;
}
#endif
/**
* @brief Returns the title bar.
*
@@ -124,6 +130,7 @@ public:
QRect dragRect() const;
Q_SIGNALS:
void activatedChanged();
void numFramesChanged();
void windowStateChanged(QWindowStateChangeEvent *);
protected:
@@ -131,6 +138,7 @@ protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
#endif
bool event(QEvent *ev) override;
void onCloseEvent(QCloseEvent *) override;
DropArea *const m_dropArea;
@@ -143,8 +151,12 @@ private:
bool m_disableSetVisible = false;
bool m_deleteScheduled = false;
bool m_inDtor = false;
bool m_updatingTitleBarVisibility = false;
QMetaObject::Connection m_layoutDestroyedConnection;
QAbstractNativeEventFilter *m_nchittestFilter = nullptr;
#ifdef Q_OS_WIN
int m_lastHitTest = 0;
#endif
};
}

View File

@@ -48,6 +48,7 @@ static FrameOptions actualOptions(FrameOptions options)
Frame::Frame(QWidgetOrQuick *parent, FrameOptions options)
: LayoutGuestWidget(parent)
, FocusScope(this)
, m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
, m_options(actualOptions(options))
{
@@ -56,6 +57,7 @@ Frame::Frame(QWidgetOrQuick *parent, FrameOptions options)
qCDebug(creation) << "Frame" << ((void*)this) << s_dbg_numFrames;
connect(this, &Frame::currentDockWidgetChanged, this, &Frame::updateTitleAndIcon);
setDropArea(qobject_cast<DropArea *>(QWidgetAdapter::parentWidget()));
m_inCtor = false;
}
@@ -92,6 +94,16 @@ void Frame::updateTitleAndIcon()
}
}
void Frame::onDockWidgetTitleChanged()
{
updateTitleAndIcon();
if (!m_inCtor) { // don't call pure virtual in ctor
if (auto dw = qobject_cast<DockWidgetBase*>(sender()))
renameTab(indexOfDockWidget(dw), dw->title());
}
}
void Frame::addWidget(DockWidgetBase *dockWidget, AddingOption addingOption)
{
insertWidget(dockWidget, dockWidgetCount(), addingOption); // append
@@ -148,14 +160,14 @@ void Frame::insertWidget(DockWidgetBase *dockWidget, int index, AddingOption add
}
}
connect(dockWidget, &DockWidgetBase::titleChanged, this, &Frame::updateTitleAndIcon);
connect(dockWidget, &DockWidgetBase::iconChanged, this, &Frame::updateTitleAndIcon);
connect(dockWidget, &DockWidgetBase::titleChanged, this, &Frame::onDockWidgetTitleChanged);
connect(dockWidget, &DockWidgetBase::iconChanged, this, &Frame::onDockWidgetTitleChanged);
}
void Frame::removeWidget(DockWidgetBase *dw)
{
disconnect(dw, &DockWidgetBase::titleChanged, this, &Frame::updateTitleAndIcon);
disconnect(dw, &DockWidgetBase::iconChanged, this, &Frame::updateTitleAndIcon);
disconnect(dw, &DockWidgetBase::titleChanged, this, &Frame::onDockWidgetTitleChanged);
disconnect(dw, &DockWidgetBase::iconChanged, this, &Frame::onDockWidgetTitleChanged);
removeWidget_impl(dw);
}
@@ -233,6 +245,10 @@ void Frame::onDockWidgetCountChanged()
// We don't really keep track of the state, so emit even if the visibility didn't change. No biggie.
if (!(m_options & FrameOption_AlwaysShowsTabs))
Q_EMIT hasTabsVisibleChanged();
const DockWidgetBase::List docks = dockWidgets();
for (DockWidgetBase *dock : docks)
dock->updateFloatAction();
}
Q_EMIT numDockWidgetsChanged();
@@ -278,9 +294,16 @@ void Frame::updateTitleBarVisibility()
}
}
void Frame::updateFloatingActions()
{
const QVector<DockWidgetBase *> widgets = dockWidgets();
for (DockWidgetBase *dw : widgets)
dw->updateFloatAction();
}
bool Frame::containsMouse(QPoint globalPos) const
{
return QWidgetAdapter::rect().contains(LayoutGuestWidgetBase::mapFromGlobal(globalPos));
return QWidgetAdapter::rect().contains(KDDockWidgets::QWidgetAdapter::mapFromGlobal(globalPos));
}
TitleBar *Frame::titleBar() const
@@ -495,23 +518,26 @@ QStringList Frame::affinities() const
void Frame::setDropArea(DropArea *dt)
{
if (dt != m_dropArea) {
qCDebug(docking) << "Frame::setDropArea dt=" << dt;
const bool wasInMainWindow = dt && isInMainWindow();
if (m_dropArea)
disconnect(m_visibleWidgetCountChangedConnection);
if (dt == m_dropArea)
return;
m_dropArea = dt;
if (m_dropArea) {
// We keep the connect result so we don't dereference m_dropArea at shutdown
m_visibleWidgetCountChangedConnection = connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged,
this, &Frame::updateTitleBarVisibility);
updateTitleBarVisibility();
if (wasInMainWindow != isInMainWindow())
Q_EMIT isInMainWindowChanged();
}
qCDebug(docking) << "Frame::setDropArea dt=" << dt;
const bool wasInMainWindow = dt && isInMainWindow();
if (m_dropArea)
disconnect(m_visibleWidgetCountChangedConnection);
m_dropArea = dt;
if (m_dropArea) {
// We keep the connect result so we don't dereference m_dropArea at shutdown
m_visibleWidgetCountChangedConnection = connect(m_dropArea, &MultiSplitter::visibleWidgetCountChanged,
this, &Frame::updateTitleBarVisibility);
updateTitleBarVisibility();
if (wasInMainWindow != isInMainWindow())
Q_EMIT isInMainWindowChanged();
}
}
bool Frame::isTheOnlyFrame() const
@@ -521,6 +547,11 @@ bool Frame::isTheOnlyFrame() const
return m_dropArea && m_dropArea->numFrames() == 1;
}
bool Frame::isOverlayed() const
{
return m_options & FrameOption_IsOverlayed;
}
bool Frame::isFloating() const
{
if (isInMainWindow())
@@ -536,7 +567,7 @@ bool Frame::isInFloatingWindow() const
bool Frame::isInMainWindow() const
{
return m_dropArea && m_dropArea->isInMainWindow();
return mainWindow() != nullptr;
}
bool Frame::event(QEvent *e)
@@ -645,3 +676,14 @@ QRect Frame::dragRect() const
return rect;
}
DropArea *Frame::dropArea() const
{
return m_dropArea;
}
MainWindowBase *Frame::mainWindow() const
{
return m_dropArea ? m_dropArea->mainWindow()
: nullptr;
}

View File

@@ -24,6 +24,7 @@
#include "LayoutSaver_p.h"
#include "multisplitter/Widget_qwidget.h"
#include "multisplitter/Item_p.h"
#include "FocusScope.h"
#include <QWidget>
#include <QVector>
@@ -36,6 +37,7 @@ class TitleBar;
class DropArea;
class DockWidgetBase;
class FloatingWindow;
class MainWindowBase;
/**
* @brief A DockWidget wrapper that adds a QTabWidget and a TitleBar
@@ -47,7 +49,9 @@ class FloatingWindow;
* inside a MultiSplitter (DropArea). Be it a MultiSplitter belonging to a MainWindow or belonging
* to a FloatingWindow.
*/
class DOCKS_EXPORT Frame : public LayoutGuestWidget
class DOCKS_EXPORT Frame
: public LayoutGuestWidget
, public FocusScope
{
Q_OBJECT
Q_PROPERTY(KDDockWidgets::TitleBar* titleBar READ titleBar CONSTANT)
@@ -101,17 +105,26 @@ public:
int dockWidgetCount() const;
void updateTitleAndIcon();
void onDockWidgetTitleChanged();
void updateTitleBarVisibility();
void updateFloatingActions();
bool containsMouse(QPoint globalPos) const;
TitleBar *titleBar() const;
TitleBar *actualTitleBar() const;
QString title() const;
QIcon icon() const;
const QVector<DockWidgetBase *> dockWidgets() const;
void setDropArea(DropArea *);
///@brief Returns the drop area this Frame is in.
DropArea *dropArea() const;
bool isTheOnlyFrame() const;
///@brief Returns whether this frame is overlayed on top of the MainWindow (auto-hide feature);
bool isOverlayed() const;
/**
* @brief Returns whether this frame is floating. A floating frame isn't attached to any other MainWindow,
* and if it's attached to a FloatingWindow then it's considered floating if it's the only frame in that Window.
@@ -151,14 +164,18 @@ public:
*/
bool alwaysShowsTabs() const { return m_options & FrameOption_AlwaysShowsTabs; }
/// @brief returns whether the dockwidget @p w is inside this frame
bool contains(DockWidgetBase *w) const;
///@brief returns the FloatingWindow this frame is in, if any
FloatingWindow *floatingWindow() const;
/**
* @brief Returns the main window this frame is in.
* nullptr if not inside a main window.
*/
MainWindowBase *mainWindow() const;
/**
* @brief Puts the Frame back in its previous main window position
*
@@ -223,8 +240,12 @@ Q_SIGNALS:
void hasTabsVisibleChanged();
void layoutInvalidated();
void isInMainWindowChanged();
void isFocusedChanged() override; // override from non-QObject
void focusedWidgetChanged() override;
protected:
virtual void renameTab(int index, const QString &) = 0;
/**
* @brief Returns the minimum size of the dock widgets.
* This might be slightly smaller than Frame::minSize() due to the QTabWidget having some margins

View File

@@ -92,6 +92,9 @@ MainWindowBase *MultiSplitter::mainWindow() const
// Note that if pw is a FloatingWindow then pw->parentWidget() can be a MainWindow too, as it's parented
if (pw->objectName() == QLatin1String("MyCentralWidget"))
return qobject_cast<MainWindowBase*>(pw->parentWidget());
if (auto mw = qobject_cast<MainWindowBase*>(pw))
return mw;
}
return nullptr;
@@ -200,7 +203,17 @@ void MultiSplitter::addWidget(QWidgetOrQuick *w, Location location,
} else if (auto ms = qobject_cast<MultiSplitter*>(w)) {
newItem = ms->rootItem();
newItem->setHostWidget(this);
if (FloatingWindow *fw = ms->floatingWindow()) {
newItem->setSize_recursive(fw->size());
}
delete ms;
} else {
// This doesn't happen but let's make coverity happy.
// Tests will fail if this is ever printed.
qWarning() << Q_FUNC_INFO << "Unknown widget added" << w;
return;
}
Q_ASSERT(!newItem->geometry().isEmpty());
@@ -220,11 +233,10 @@ void MultiSplitter::addMultiSplitter(MultiSplitter *sourceMultiSplitter, Locatio
void MultiSplitter::removeItem(Layouting::Item *item)
{
if (!item)
if (!item) {
qWarning() << Q_FUNC_INFO << "nullptr item";
if (!item)
return;
}
item->parentContainer()->removeItem(item);
}
@@ -289,6 +301,16 @@ Layouting::Item *MultiSplitter::itemForFrame(const Frame *frame) const
return m_rootItem->itemForWidget(frame);
}
DockWidgetBase::List MultiSplitter::dockWidgets() const
{
DockWidgetBase::List dockWidgets;
const Frame::List frames = this->frames();
for (Frame *frame : frames)
dockWidgets << frame->dockWidgets();
return dockWidgets;
}
Frame::List MultiSplitter::framesFrom(QWidgetOrQuick *frameOrMultiSplitter) const
{
if (auto frame = qobject_cast<Frame*>(frameOrMultiSplitter))
@@ -422,7 +444,7 @@ QRect MultiSplitter::rectForDrop(const FloatingWindow *fw, Location location,
return {};
Layouting::ItemContainer *root = fw->dropArea()->rootItem();
item.setSize(root->size());
item.setSize(fw->size().boundedTo(root->maxSizeHint()));
item.setMinSize(root->minSize());
item.setMaxSizeHint(root->maxSizeHint());

View File

@@ -53,7 +53,7 @@ class Frame;
* It supports adding a widget to the left/top/bottom/right of the whole MultiSplitter or adding
* relative to a single widget.
*/
class DOCKS_EXPORT_FOR_UNIT_TESTS MultiSplitter
class DOCKS_EXPORT MultiSplitter
: public LayoutGuestWidget
{
Q_OBJECT
@@ -188,10 +188,13 @@ public:
Layouting::Item *itemForFrame(const Frame *frame) const;
/**
* @brief Returns a list of Frame objects contained in this layout
* @brief Returns this list of Frame objects contained in this layout
*/
QList<Frame*> frames() const;
/// @brief Returns the list of dock widgets contained in this layout
QVector<DockWidgetBase*> dockWidgets() const;
/// @brief restores the dockwidget @p dw to its previous position
void restorePlaceholder(DockWidgetBase *dw, Layouting::Item *, int tabIndex);

109
src/private/SideBar.cpp Normal file
View File

@@ -0,0 +1,109 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "SideBar_p.h"
#include "DockWidgetBase.h"
#include "MainWindowBase.h"
#include <QDebug>
using namespace KDDockWidgets;
SideBar::SideBar(SideBarLocation location, MainWindowBase *parent)
: QWidgetAdapter(parent)
, m_mainWindow(parent)
, m_location(location)
, m_orientation((location == SideBarLocation::North || location == SideBarLocation::South) ? Qt::Horizontal
: Qt::Vertical)
{
updateSize();
}
void SideBar::addDockWidget(DockWidgetBase *dw)
{
if (!dw)
return;
if (m_dockWidgets.contains(dw)) {
qWarning() << Q_FUNC_INFO << "Already contains dock widget" << dw->title();
return;
}
connect(dw, &QObject::destroyed, this, &SideBar::onDockWidgetDestroyed);
m_dockWidgets << dw;
addDockWidget_Impl(dw);
updateSize();
}
void SideBar::removeDockWidget(DockWidgetBase *dw)
{
if (!m_dockWidgets.contains(dw)) {
qWarning() << Q_FUNC_INFO << "Doesn't contain dock widget" << dw->title();
return;
}
disconnect(dw, &QObject::destroyed, this, &SideBar::onDockWidgetDestroyed);
m_dockWidgets.removeOne(dw);
removeDockWidget_Impl(dw);
Q_EMIT dw->removedFromSideBar();
updateSize();
}
bool SideBar::contains(DockWidgetBase *dw) const
{
return m_dockWidgets.contains(dw);
}
void SideBar::onButtonClicked(DockWidgetBase *dw)
{
toggleOverlay(dw);
}
void SideBar::onDockWidgetDestroyed(QObject *dw)
{
removeDockWidget(static_cast<DockWidgetBase*>(dw));
}
void SideBar::updateSize()
{
const int thickness = isEmpty() ? 0 : 30;
if (isVertical()) {
setFixedWidth(thickness);
} else {
setFixedHeight(thickness);
}
}
Qt::Orientation SideBar::orientation() const
{
return m_orientation;
}
bool SideBar::isEmpty() const
{
return m_dockWidgets.isEmpty();
}
SideBarLocation SideBar::location() const
{
return m_location;
}
MainWindowBase *SideBar::mainWindow() const
{
return m_mainWindow;
}
void SideBar::toggleOverlay(DockWidgetBase *dw)
{
m_mainWindow->toggleOverlayOnSideBar(dw);
}

70
src/private/SideBar_p.h Normal file
View File

@@ -0,0 +1,70 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#ifndef KD_SIDEBAR_P_H
#define KD_SIDEBAR_P_H
#include "docks_export.h"
#include "KDDockWidgets.h"
#include "QWidgetAdapter.h"
namespace KDDockWidgets {
class DockWidgetBase;
class MainWindowBase;
class DOCKS_EXPORT SideBar : public QWidgetAdapter
{
Q_OBJECT
public:
explicit SideBar(SideBarLocation, MainWindowBase *parent = nullptr);
void addDockWidget(DockWidgetBase *dw);
void removeDockWidget(DockWidgetBase *dw);
bool contains(DockWidgetBase *) const;
/// @brief Returns this side bar's orientation
Qt::Orientation orientation() const;
/// @brief returns if this side bar has vertical orientation
bool isVertical() const { return m_orientation == Qt::Vertical; }
/// @brief returns whether there's no dock widgets
bool isEmpty() const;
/// @brief returns the sidebar's location in the main window
SideBarLocation location() const;
/// @brief Returns the main window this side bar belongs to
MainWindowBase *mainWindow() const;
/// @brief Toggles the dock widget overlay. Equivalent to the user clicking on the button.
void toggleOverlay(DockWidgetBase *);
protected:
virtual void addDockWidget_Impl(DockWidgetBase *dock) = 0;
virtual void removeDockWidget_Impl(DockWidgetBase *dock) = 0;
void onButtonClicked(DockWidgetBase *dw);
private:
void onDockWidgetDestroyed(QObject *dw);
void updateSize();
MainWindowBase *const m_mainWindow;
QVector<DockWidgetBase *> m_dockWidgets;
const SideBarLocation m_location;
const Qt::Orientation m_orientation;
};
}
#endif

View File

@@ -16,7 +16,10 @@
#include "WindowBeingDragged_p.h"
#include "Utils_p.h"
#include "FrameworkWidgetFactory.h"
#include "Config.h"
#include "MainWindowBase.h"
#include <QTimer>
#include <QWindowStateChangeEvent>
using namespace KDDockWidgets;
@@ -26,9 +29,19 @@ TitleBar::TitleBar(Frame *parent)
, Draggable(this)
, m_frame(parent)
, m_floatingWindow(nullptr)
, m_supportsAutoHide(Config::self().flags() & Config::Flag_AutoHideSupport)
{
connect(m_frame, &Frame::numDockWidgetsChanged, this, &TitleBar::updateCloseButton);
connect(m_frame, &Frame::isFocusedChanged, this, &TitleBar::isFocusedChanged);
connect(m_frame, &Frame::isInMainWindowChanged, this, &TitleBar::updateAutoHideButton);
init();
if (Config::self().flags() & Config::Flag_TitleBarIsFocusable)
setFocusPolicy(Qt::StrongFocus);
QTimer::singleShot(0, this, &TitleBar::updateAutoHideButton); // have to wait after the frame is constructed
updateAutoHideButton();
}
TitleBar::TitleBar(FloatingWindow *parent)
@@ -36,18 +49,26 @@ TitleBar::TitleBar(FloatingWindow *parent)
, Draggable(this)
, m_frame(nullptr)
, m_floatingWindow(parent)
, m_supportsAutoHide(Config::self().flags() & Config::Flag_AutoHideSupport)
{
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateCloseButton);
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateFloatButton);
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateMaximizeButton);
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateMinimizeButton);
connect(m_floatingWindow, &FloatingWindow::windowStateChanged, this, &TitleBar::updateMaximizeButton);
connect(m_floatingWindow, &FloatingWindow::activatedChanged , this, &TitleBar::isFocusedChanged);
init();
updateAutoHideButton(); // always hidden when we're in a FloatingWindow.
}
void TitleBar::init()
{
qCDebug(creation) << "TitleBar" << this;
setFixedHeight(30);
connect(this, &TitleBar::isFocusedChanged, this, [this] {
// repaint
update();
});
}
TitleBar::~TitleBar()
@@ -79,6 +100,22 @@ void TitleBar::toggleMaximized()
m_floatingWindow->showMaximized();
}
void TitleBar::focusInEvent(QFocusEvent *ev)
{
QWidgetAdapter::focusInEvent(ev);
if (!m_frame || !(Config::self().flags() & Config::Flag_TitleBarIsFocusable))
return;
// For some reason QWidget::setFocusProxy() isn't working, so forward manually
m_frame->FocusScope::focus(ev->reason());
}
bool TitleBar::isOverlayed() const
{
return m_frame && m_frame->isOverlayed();
}
void TitleBar::setTitle(const QString &title)
{
if (title != m_title) {
@@ -129,7 +166,7 @@ std::unique_ptr<WindowBeingDragged> TitleBar::makeWindow()
QRect r = m_frame->QWidgetAdapter::geometry();
qCDebug(hovering) << "TitleBar::makeWindow original geometry" << r;
r.moveTopLeft(static_cast<Layouting::Widget*>(m_frame)->mapToGlobal(QPoint(0, 0))); // TODO: Remove static_cast if it compiles. Ambiguous base for now
r.moveTopLeft(m_frame->mapToGlobal(QPoint(0, 0)));
auto floatingWindow = Config::self().frameworkWidgetFactory()->createFloatingWindow(m_frame);
floatingWindow->setSuggestedGeometry(r);
@@ -156,6 +193,17 @@ bool TitleBar::supportsFloatingButton() const
return false;
}
if (Config::self().flags() & Config::Flag_TitleBarNoFloatButton) {
// Was explicitly disabled
return false;
}
if (DockWidgetBase *dw = singleDockWidget()) {
// Don't show the dock/undock button if the window is not dockable
if (dw->options() & DockWidgetBase::Option_NotDockable)
return false;
}
// If we have a floating window with nested dock widgets we can't re-attach, because we don't
// know where to
return !m_floatingWindow || m_floatingWindow->hasSingleFrame();
@@ -169,11 +217,35 @@ bool TitleBar::supportsMaximizeButton() const
return m_floatingWindow != nullptr;
}
bool TitleBar::supportsMinimizeButton() const
{
if ((Config::self().flags() & Config::Flag_TitleBarHasMinimizeButton) != Config::Flag_TitleBarHasMinimizeButton) // this specific flag is not base^2
return false;
return m_floatingWindow != nullptr;
}
bool TitleBar::supportsAutoHideButton() const
{
// Only dock widgets docked into the MainWindow can minimize
return m_supportsAutoHide && m_frame && m_frame->isInMainWindow();
}
bool TitleBar::hasIcon() const
{
return !m_icon.isNull();
}
bool TitleBar::isFocused() const
{
if (m_frame)
return m_frame->isFocused();
else if (m_floatingWindow)
return m_floatingWindow->isActiveWindow();
return false;
}
QIcon TitleBar::icon() const
{
return m_icon;
@@ -195,7 +267,6 @@ void TitleBar::onCloseClicked()
bool TitleBar::isFloating() const
{
if (m_floatingWindow)
return m_floatingWindow->hasSingleDockWidget(); // Debatable! Maybe it's always floating.
@@ -262,3 +333,37 @@ void TitleBar::onMaximizeClicked()
{
toggleMaximized();
}
void TitleBar::onMinimizeClicked()
{
if (!m_floatingWindow)
return;
if (!(Config::self().flags() & Config::Flag_DontUseUtilityFloatingWindows)) {
// Qt::Tool windows don't appear in the task bar.
// Unless someone tells me a good reason to allow this situation.
return;
}
m_floatingWindow->showMinimized();
}
void TitleBar::onAutoHideClicked()
{
if (!m_frame) {
// Doesn't happen
qWarning() << Q_FUNC_INFO << "Minimize not supported on floating windows";
return;
}
const auto &dockwidgets = m_frame->dockWidgets();
for (DockWidgetBase *dw : dockwidgets) {
if (dw->isOverlayed()) {
// restore
MainWindowBase *mainWindow = dw->mainWindow();
mainWindow->restoreFromSideBar(dw);
} else {
dw->moveToSideBar();
}
}
}

View File

@@ -27,6 +27,8 @@ class QHBoxLayout;
class QLabel;
QT_END_NAMESPACE
class TestCommon;
namespace KDDockWidgets {
class DockWidgetBase;
@@ -41,6 +43,7 @@ class DOCKS_EXPORT TitleBar : public QWidgetAdapter
Q_PROPERTY(bool hasIcon READ hasIcon NOTIFY iconChanged)
public:
typedef QVector<TitleBar *> List;
explicit TitleBar(Frame *parent);
explicit TitleBar(FloatingWindow *parent);
~TitleBar() override;
@@ -66,9 +69,20 @@ public:
///@brief returns whether this title bar supports a maximize/restore button
bool supportsMaximizeButton() const;
///@brief returns whether this title bar supports a minimize button
bool supportsMinimizeButton() const;
///@brief returns whether this title bar supports the auto-hide button
bool supportsAutoHideButton() const;
///@brief returns whether this title bar has an icon
bool hasIcon() const;
///@brief returns whether any of the DockWidgets this TitleBar controls has a child focus
///Not to be confused with QWidget::hasFocus(), which just refers to 1 widget. This works more
/// like QtQuick's FocusScope
bool isFocused() const;
///@brief the icon
QIcon icon() const;
@@ -86,24 +100,36 @@ public:
Q_SIGNALS:
void titleChanged();
void iconChanged();
void isFocusedChanged();
protected:
Q_INVOKABLE void onCloseClicked();
Q_INVOKABLE void onFloatClicked();
Q_INVOKABLE void onMaximizeClicked();
Q_INVOKABLE void onMinimizeClicked();
Q_INVOKABLE void toggleMaximized();
Q_INVOKABLE void onAutoHideClicked();
virtual void updateFloatButton() {}
virtual void updateMaximizeButton() {}
virtual void updateMinimizeButton() {}
virtual void updateAutoHideButton() {}
// The following are needed for the unit-tests
virtual bool isCloseButtonVisible() const { return true; }
virtual bool isCloseButtonEnabled() const { return true; }
virtual bool isFloatButtonVisible() const { return true; }
virtual bool isFloatButtonEnabled() const { return true; }
void focusInEvent(QFocusEvent *event) override;
bool isOverlayed() const;
private:
friend class TestDocks;
friend class ::TestCommon;
void init();
@@ -113,6 +139,7 @@ private:
Frame *const m_frame;
FloatingWindow *const m_floatingWindow;
const bool m_supportsAutoHide;
};

View File

@@ -24,8 +24,10 @@
#include <QScreen>
#include <QWindow>
#include <QAbstractButton>
#include <QLineEdit>
#if defined(Q_OS_WIN)
# include <QtGui/private/qhighdpiscaling_p.h>
# include <Windowsx.h>
# include <Windows.h>
# if defined(Q_CC_MSVC)
@@ -247,16 +249,20 @@ bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByt
} else if (!hasFixedWidth && xPos <= rect.right && xPos >= rect.right - borderWidth) {
*result = HTRIGHT;
} else {
const QRect htCaptionRect = w->dragRect(); // The rect on which we allow for Windows to do a native drag
if (yPos >= htCaptionRect.top() && yPos <= htCaptionRect.bottom() && xPos >= htCaptionRect.left() && xPos <= htCaptionRect.right()) {
QWidget *hoveredWidget = qApp->widgetAt(QPoint(xPos, yPos));
if (!qobject_cast<QAbstractButton*>(hoveredWidget)) {
const QPoint globalPosQt = QHighDpi::fromNativePixels(QPoint(xPos, yPos), w->windowHandle());
const QRect htCaptionRect = w->dragRect(); // The rect on which we allow for Windows to do Ba native drag
if (globalPosQt.y() >= htCaptionRect.top() && globalPosQt.y() <= htCaptionRect.bottom() && globalPosQt.x() >= htCaptionRect.left() && globalPosQt.x() <= htCaptionRect.right()) {
QWidget *hoveredWidget = qApp->widgetAt(globalPosQt);
if (!qobject_cast<QAbstractButton*>(hoveredWidget) &&
!qobject_cast<QLineEdit*>(hoveredWidget)) { // User might have a line edit on the toolbar. TODO: Not so elegant fix, we should make the user's tabbar implement some virtual method...
// User clicked on the title bar, let's allow it, so we get Aero-Snap.
*result = HTCAPTION;
}
}
}
w->setLastHitTest(*result);
return *result != 0;
} else if (msg->message == WM_NCLBUTTONDBLCLK) {
if ((Config::self().flags() & Config::Flag_DoubleClickMaximizes)) {
@@ -292,12 +298,17 @@ bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *w, const QByt
const QRect availableGeometry = screen->availableGeometry();
auto mmi = reinterpret_cast<MINMAXINFO *>(msg->lParam);
const qreal dpr = screen->devicePixelRatio();
mmi->ptMaxSize.y = availableGeometry.height();
mmi->ptMaxSize.x = availableGeometry.width() - 1; // Otherwise it gets bogus size
mmi->ptMaxSize.y = int(availableGeometry.height() * dpr);
mmi->ptMaxSize.x = int(availableGeometry.width() * dpr) - 1; // -1 otherwise it gets bogus size
mmi->ptMaxPosition.x = availableGeometry.x();
mmi->ptMaxPosition.y = availableGeometry.y();
QWindow *window = w->windowHandle();
mmi->ptMinTrackSize.x = int(window->minimumWidth() * dpr);
mmi->ptMinTrackSize.y = int(window->minimumHeight() * dpr);
*result = 0;
return true;
}

View File

@@ -47,11 +47,21 @@ WindowBeingDragged::WindowBeingDragged(FloatingWindow *fw, Draggable *draggable)
, m_draggable(bestDraggable(draggable)->asWidget())
{
init();
// Set opacity while dragging, if needed
const qreal opacity = Config::self().draggedWindowOpacity();
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
fw->setWindowOpacity(opacity);
}
WindowBeingDragged::~WindowBeingDragged()
{
grabMouse(false);
// Restore opacity to fully opaque if needed
const qreal opacity = Config::self().draggedWindowOpacity();
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
m_floatingWindow->setWindowOpacity(1);
}
void WindowBeingDragged::init()

View File

@@ -14,245 +14,25 @@
#include "DragController_p.h"
#include "Frame_p.h"
#include "Logging_p.h"
#include "Utils_p.h"
#include <QPainter>
#include <QRubberBand>
#define INDICATOR_WIDTH 40
#define OUTTER_INDICATOR_MARGIN 10
//#define KDDOCKWIDGETS_RUBBERBAND_IS_TOPLEVEL 1
#include "Config.h"
#include "DockRegistry_p.h"
#include "FrameworkWidgetFactory.h"
#include "ClassicIndicatorsWindow_p.h"
using namespace KDDockWidgets;
namespace KDDockWidgets {
class IndicatorWindow;
}
void Indicator::paintEvent(QPaintEvent *)
static IndicatorWindow* createIndicatorWindow(ClassicIndicators *classicIndicators)
{
QPainter p(this);
if (m_hovered)
p.drawImage(rect(), m_imageActive, rect());
else
p.drawImage(rect(), m_image, rect());
}
void Indicator::setHovered(bool hovered)
{
if (hovered != m_hovered) {
m_hovered = hovered;
update();
if (hovered) {
q->setDropLocation(m_dropLocation);
} else if (q->currentDropLocation() == m_dropLocation) {
q->setDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
}
}
}
QString Indicator::iconName(bool active) const
{
QString suffix = active ? QStringLiteral("_active")
: QString();
QString name;
switch (m_dropLocation) {
case DropIndicatorOverlayInterface::DropLocation_Center:
name = QStringLiteral("center");
break;
case DropIndicatorOverlayInterface::DropLocation_Left:
name = QStringLiteral("inner_left");
break;
case DropIndicatorOverlayInterface::DropLocation_Right:
name = QStringLiteral("inner_right");
break;
case DropIndicatorOverlayInterface::DropLocation_Bottom:
name = QStringLiteral("inner_bottom");
break;
case DropIndicatorOverlayInterface::DropLocation_Top:
name = QStringLiteral("inner_top");
break;
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
name = QStringLiteral("outter_left");
break;
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
name = QStringLiteral("outter_bottom");
break;
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
name = QStringLiteral("outter_right");
break;
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
name = QStringLiteral("outter_top");
break;
case DropIndicatorOverlayInterface::DropLocation_None:
return QString();
}
return name + suffix;
}
QString Indicator::iconFileName(bool active) const
{
const QString name = iconName(active);
return KDDockWidgets::windowManagerHasTranslucency() ? QStringLiteral(":/img/classic_indicators/%1.png").arg(name)
: QStringLiteral(":/img/classic_indicators/opaque/%1.png").arg(name);
}
IndicatorWindow::IndicatorWindow(ClassicIndicators *classicIndicators_, QWidget *)
: QWidget(nullptr, Qt::Tool | Qt::BypassWindowManagerHint)
, classicIndicators(classicIndicators_)
, m_center(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Center)) // Each indicator is not a top-level. Otherwise there's noticeable delay.
, m_left(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Left))
, m_right(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Right))
, m_bottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Bottom))
, m_top(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_Top))
, m_outterLeft(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterLeft))
, m_outterRight(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterRight))
, m_outterBottom(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterBottom))
, m_outterTop(new Indicator(classicIndicators, this, DropIndicatorOverlayInterface::DropLocation_OutterTop))
{
setWindowFlag(Qt::FramelessWindowHint, true);
setAttribute(Qt::WA_TranslucentBackground);
updatePosition();
m_indicators << m_center << m_left << m_right << m_top << m_bottom
<< m_outterBottom << m_outterTop << m_outterLeft << m_outterRight;
setObjectName(QStringLiteral("_docks_IndicatorWindow_Overlay"));
}
bool IndicatorWindow::event(QEvent *e)
{
if (e->type() == QEvent::Show) {
updatePosition();
}
return QWidget::event(e);
}
Indicator *IndicatorWindow::indicatorForLocation(DropIndicatorOverlayInterface::DropLocation loc) const
{
switch (loc) {
case DropIndicatorOverlayInterface::DropLocation_Center:
return m_center;
case DropIndicatorOverlayInterface::DropLocation_Left:
return m_left;
case DropIndicatorOverlayInterface::DropLocation_Right:
return m_right;
case DropIndicatorOverlayInterface::DropLocation_Bottom:
return m_bottom;
case DropIndicatorOverlayInterface::DropLocation_Top:
return m_top;
case DropIndicatorOverlayInterface::DropLocation_OutterLeft:
return m_outterLeft;
case DropIndicatorOverlayInterface::DropLocation_OutterBottom:
return m_outterBottom;
case DropIndicatorOverlayInterface::DropLocation_OutterRight:
return m_outterRight;
case DropIndicatorOverlayInterface::DropLocation_OutterTop:
return m_outterTop;
case DropIndicatorOverlayInterface::DropLocation_None:
return nullptr;
}
return nullptr;
}
void IndicatorWindow::updateMask()
{
QRegion region;
if (!KDDockWidgets::windowManagerHasTranslucency()) {
for (Indicator *indicator : qAsConst(m_indicators)) {
if (indicator->isVisible())
region = region.united(QRegion(indicator->geometry(), QRegion::Rectangle));
}
}
setMask(region);
}
void IndicatorWindow::resizeEvent(QResizeEvent *ev)
{
QWidget::resizeEvent(ev);
updatePositions();
}
void IndicatorWindow::updateIndicatorVisibility(bool visible)
{
Frame *hoveredFrame = classicIndicators->m_hoveredFrame;
const bool isTheOnlyFrame = hoveredFrame && hoveredFrame->isTheOnlyFrame();
const bool innerShouldBeVisible = visible && hoveredFrame;
const bool outterShouldBeVisible = visible && !isTheOnlyFrame;
for (Indicator *indicator : { m_center, m_left, m_right, m_bottom, m_top })
indicator->setVisible(innerShouldBeVisible);
for (Indicator *indicator : { m_outterTop, m_outterLeft, m_outterRight, m_outterBottom })
indicator->setVisible(outterShouldBeVisible);
updateMask();
}
void IndicatorWindow::hover(QPoint globalPos)
{
for (Indicator *indicator : qAsConst(m_indicators)) {
if (indicator->isVisible())
indicator->setHovered(indicator->rect().contains(indicator->mapFromGlobal(globalPos)));
}
}
void IndicatorWindow::updatePosition()
{
QRect rect = classicIndicators->rect();
QPoint pos = classicIndicators->mapToGlobal(QPoint(0, 0));
rect.moveTo(pos);
setGeometry(rect);
}
void IndicatorWindow::updatePositions()
{
QRect r = rect();
const int indicatorWidth = m_outterBottom->width();
const int halfIndicatorWidth = m_outterBottom->width() / 2;
m_outterLeft->move(r.x() + OUTTER_INDICATOR_MARGIN, r.center().y() - halfIndicatorWidth);
m_outterBottom->move(r.center().x() - halfIndicatorWidth, r.y() + height() - indicatorWidth - OUTTER_INDICATOR_MARGIN);
m_outterTop->move(r.center().x() - halfIndicatorWidth, r.y() + OUTTER_INDICATOR_MARGIN);
m_outterRight->move(r.x() + width() - indicatorWidth - OUTTER_INDICATOR_MARGIN, r.center().y() - halfIndicatorWidth);
Frame *hoveredFrame = classicIndicators->m_hoveredFrame;
if (hoveredFrame) {
QRect hoveredRect = hoveredFrame->QWidget::geometry();
m_center->move(r.topLeft() + hoveredRect.center() - QPoint(halfIndicatorWidth, halfIndicatorWidth));
m_top->move(m_center->pos() - QPoint(0, indicatorWidth + OUTTER_INDICATOR_MARGIN));
m_right->move(m_center->pos() + QPoint(indicatorWidth + OUTTER_INDICATOR_MARGIN, 0));
m_bottom->move(m_center->pos() + QPoint(0, indicatorWidth + OUTTER_INDICATOR_MARGIN));
m_left->move(m_center->pos() - QPoint(indicatorWidth + OUTTER_INDICATOR_MARGIN, 0));
}
}
Indicator::Indicator(ClassicIndicators *classicIndicators, IndicatorWindow *parent, ClassicIndicators::DropLocation location)
: QWidget(parent)
, q(classicIndicators)
, m_dropLocation(location)
{
m_image = QImage(iconFileName(/*active=*/ false)).scaled(INDICATOR_WIDTH, INDICATOR_WIDTH);
m_imageActive = QImage(iconFileName(/*active=*/ true)).scaled(INDICATOR_WIDTH, INDICATOR_WIDTH);
setFixedSize(m_image.size());
setVisible(true);
auto window = new IndicatorWindow(classicIndicators);
window->setObjectName(QStringLiteral("_docks_IndicatorWindow_Overlay"));
return window;
}
ClassicIndicators::ClassicIndicators(DropArea *dropArea)
: DropIndicatorOverlayInterface(dropArea) // Is parented on the drop-area, not a toplevel.
, m_rubberBand(new QRubberBand(QRubberBand::Rectangle, rubberBandIsTopLevel() ? nullptr : dropArea))
, m_indicatorWindow(new IndicatorWindow(this, /*parent=*/ nullptr)) // Top-level so the indicators can appear above the window being dragged.
, m_rubberBand(Config::self().frameworkWidgetFactory()->createRubberBand(dropArea))
, m_indicatorWindow(createIndicatorWindow(this))
{
setVisible(false);
if (rubberBandIsTopLevel())
m_rubberBand->setWindowOpacity(0.5);
}
ClassicIndicators::~ClassicIndicators()
@@ -260,20 +40,35 @@ ClassicIndicators::~ClassicIndicators()
delete m_indicatorWindow;
}
DropIndicatorOverlayInterface::Type ClassicIndicators::indicatorType() const
{
return TypeClassic;
}
void ClassicIndicators::hover(QPoint globalPos)
void ClassicIndicators::hover_impl(QPoint globalPos)
{
m_indicatorWindow->hover(globalPos);
}
QPoint ClassicIndicators::posForIndicator(DropIndicatorOverlayInterface::DropLocation loc) const
{
Indicator *indicator = m_indicatorWindow->indicatorForLocation(loc);
return indicator->mapToGlobal(indicator->rect().center());
return m_indicatorWindow->posForIndicator(loc);
}
bool ClassicIndicators::innerIndicatorsVisible() const
{
return m_innerIndicatorsVisible;
}
bool ClassicIndicators::outterIndicatorsVisible() const
{
return m_outterIndicatorsVisible;
}
bool ClassicIndicators::tabIndicatorVisible() const
{
return m_tabIndicatorVisible;
}
bool ClassicIndicators::onResize(QSize)
{
m_indicatorWindow->resize(window()->size());
return false;
}
void ClassicIndicators::updateVisibility()
@@ -281,29 +76,40 @@ void ClassicIndicators::updateVisibility()
if (isHovered()) {
m_indicatorWindow->updatePositions();
m_indicatorWindow->setVisible(true);
m_indicatorWindow->updateIndicatorVisibility(true);
updateWindowPosition();
updateIndicatorsVisibility(true);
raiseIndicators();
} else {
m_rubberBand->setVisible(false);
m_indicatorWindow->setVisible(false);
m_indicatorWindow->updateIndicatorVisibility(false);
updateIndicatorsVisibility(false);
}
}
void ClassicIndicators::showEvent(QShowEvent *e)
void ClassicIndicators::updateIndicatorsVisibility(bool visible)
{
QWidget::showEvent(e);
}
const bool isTheOnlyFrame = m_hoveredFrame && m_hoveredFrame->isTheOnlyFrame();
void ClassicIndicators::hideEvent(QHideEvent *e)
{
QWidget::hideEvent(e);
}
m_innerIndicatorsVisible = visible && m_hoveredFrame;
void ClassicIndicators::resizeEvent(QResizeEvent *ev)
{
QWidget::resizeEvent(ev);
m_indicatorWindow->resize(window()->size());
// If there's only 1 frame in the layout, the outter indicators are redundant, as they do the same thing as the internal ones.
// But there might be another window obscuring our target, so it's useful to show the outter indicators in this case
m_outterIndicatorsVisible = visible && (!isTheOnlyFrame ||
DockRegistry::self()->isProbablyObscured(m_hoveredFrame->window()->windowHandle(), DragController::instance()->windowBeingDragged()));
// Only allow to dock to center if the affinities match
auto tabbingAllowedFunc = Config::self().tabbingAllowedFunc();
m_tabIndicatorVisible = m_innerIndicatorsVisible && m_windowBeingDragged &&
DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), m_windowBeingDragged->affinities());
if (m_tabIndicatorVisible && tabbingAllowedFunc) {
const DockWidgetBase::List source = m_windowBeingDragged->floatingWindow()->dockWidgets();
const DockWidgetBase::List target = m_hoveredFrame->dockWidgets();
m_tabIndicatorVisible = tabbingAllowedFunc(source, target);
}
Q_EMIT innerIndicatorsVisibleChanged();
Q_EMIT outterIndicatorsVisibleChanged();
}
void ClassicIndicators::raiseIndicators()
@@ -346,12 +152,8 @@ void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location
}
if (location == DropLocation_Center) {
m_rubberBand->setGeometry(geometryForRubberband(m_hoveredFrame ? m_hoveredFrame->QWidget::geometry() : rect()));
m_rubberBand->setGeometry(m_hoveredFrame ? m_hoveredFrame->QWidgetAdapter::geometry() : rect());
m_rubberBand->setVisible(true);
if (rubberBandIsTopLevel()) {
m_rubberBand->raise();
raiseIndicators();
}
return;
}
@@ -384,32 +186,14 @@ void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location
QRect rect = m_dropArea->rectForDrop(m_windowBeingDragged, multisplitterLocation,
m_dropArea->itemForFrame(relativeToFrame));
m_rubberBand->setGeometry(geometryForRubberband(rect));
m_rubberBand->setGeometry(rect);
m_rubberBand->setVisible(true);
if (rubberBandIsTopLevel()) {
m_rubberBand->raise();
raiseIndicators();
}
}
QRect ClassicIndicators::geometryForRubberband(QRect localRect) const
void ClassicIndicators::updateWindowPosition()
{
if (!rubberBandIsTopLevel())
return localRect;
QPoint topLeftLocal = localRect.topLeft();
QPoint topLeftGlobal = m_dropArea->QWidget::mapToGlobal(topLeftLocal);
localRect.moveTopLeft(topLeftGlobal);
return localRect;
}
bool ClassicIndicators::rubberBandIsTopLevel() const
{
#ifdef KDDOCKWIDGETS_RUBBERBAND_IS_TOPLEVEL
return true;
#else
return false;
#endif
QRect rect = this->rect();
QPoint pos = mapToGlobal(QPoint(0, 0));
rect.moveTo(pos);
m_indicatorWindow->setGeometry(rect);
}

Some files were not shown because too many files have changed in this diff Show More