Compare commits
308 Commits
fix-python
...
v1.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbedc06e97 | ||
|
|
b5c2757874 | ||
|
|
fb6e2afd7b | ||
|
|
80bf6032f3 | ||
|
|
ece7b22bec | ||
|
|
72605292b7 | ||
|
|
7318675e84 | ||
|
|
8a51c31663 | ||
|
|
a586a7894b | ||
|
|
31fcbebaff | ||
|
|
392dac5691 | ||
|
|
29744c01c6 | ||
|
|
49e488df24 | ||
|
|
1a3f00eac8 | ||
|
|
c6ea8d5525 | ||
|
|
8f62004f5b | ||
|
|
f698b56dad | ||
|
|
4ed18fdf1d | ||
|
|
6e05f13c77 | ||
|
|
a146cd81b2 | ||
|
|
ac6d845c8d | ||
|
|
77f259a435 | ||
|
|
7ebc3f3533 | ||
|
|
0ee94b425e | ||
|
|
e57b46979d | ||
|
|
683b67abb0 | ||
|
|
697c140883 | ||
|
|
819725351a | ||
|
|
07db9f9a7a | ||
|
|
77d7cd7d58 | ||
|
|
e5cb42c4fe | ||
|
|
1fe1d619a9 | ||
|
|
b00d1d80b0 | ||
|
|
67bb42c5b4 | ||
|
|
f5099167b6 | ||
|
|
17df7b5b4e | ||
|
|
15dc64d550 | ||
|
|
03b575d16e | ||
|
|
4cacee45e8 | ||
|
|
873b860203 | ||
|
|
128ae2d889 | ||
|
|
b0ec0e22e4 | ||
|
|
6aa4e979dc | ||
|
|
36f225b859 | ||
|
|
48a75b2450 | ||
|
|
2af4f939dd | ||
|
|
b592d21064 | ||
|
|
3cdd5afe7a | ||
|
|
0ef56c1302 | ||
|
|
96f7f38a0e | ||
|
|
689ba7da8f | ||
|
|
951aeece6e | ||
|
|
2ea0d54e6c | ||
|
|
1c98fe04ca | ||
|
|
59a9ab6642 | ||
|
|
7ee5949ae2 | ||
|
|
721f08e29b | ||
|
|
df07133c9d | ||
|
|
b9e3024720 | ||
|
|
d848d3e39a | ||
|
|
3f26f4c8f2 | ||
|
|
dc9d709dd7 | ||
|
|
543f734650 | ||
|
|
3fb723a82f | ||
|
|
71c2f34ed4 | ||
|
|
d4b3bf9de6 | ||
|
|
2b234f313c | ||
|
|
d1b2d17f7d | ||
|
|
f062ab7a64 | ||
|
|
f009f57581 | ||
|
|
f86a818e69 | ||
|
|
bb80c2158d | ||
|
|
86fa6258f6 | ||
|
|
545536fab5 | ||
|
|
ef23553b66 | ||
|
|
fcf56664cc | ||
|
|
d932166bcd | ||
|
|
0c5783774d | ||
|
|
aa42ea15f7 | ||
|
|
9dd778d55d | ||
|
|
ac35a919f4 | ||
|
|
a32c5017e6 | ||
|
|
7995a6d13b | ||
|
|
d4ec2eec88 | ||
|
|
12ad3b3484 | ||
|
|
9a53c36c14 | ||
|
|
8fb3802343 | ||
|
|
c035df7e85 | ||
|
|
92f81e28ca | ||
|
|
7a87db608b | ||
|
|
d42fb81790 | ||
|
|
73934e2f90 | ||
|
|
1c8642298b | ||
|
|
bfc45bb0e9 | ||
|
|
58af9e2516 | ||
|
|
4228c044ea | ||
|
|
ccc0aec968 | ||
|
|
3718d3fe79 | ||
|
|
26ed9b722b | ||
|
|
6751669249 | ||
|
|
c7955dce1e | ||
|
|
2e432f402f | ||
|
|
07791cd901 | ||
|
|
1458da92d9 | ||
|
|
c56f998292 | ||
|
|
991075d69e | ||
|
|
234ca75728 | ||
|
|
e34d62d3e5 | ||
|
|
423be28afd | ||
|
|
eb7bed9601 | ||
|
|
fa09521012 | ||
|
|
bb30f322a3 | ||
|
|
0e35c93ae5 | ||
|
|
603224e553 | ||
|
|
9b82063d52 | ||
|
|
c210a523e3 | ||
|
|
e33151d482 | ||
|
|
835f67a106 | ||
|
|
a50f6ec602 | ||
|
|
4a49dbc6b4 | ||
|
|
05c843397b | ||
|
|
e4871eb340 | ||
|
|
0e696ff2dd | ||
|
|
9f15773a9b | ||
|
|
a00984f95a | ||
|
|
c7e9632f18 | ||
|
|
7080712501 | ||
|
|
03b574434c | ||
|
|
6a46744073 | ||
|
|
7e52c510b3 | ||
|
|
9bf060af9a | ||
|
|
b5973fcf8c | ||
|
|
ac7d06d4fe | ||
|
|
75e9137e3a | ||
|
|
5168940422 | ||
|
|
cfd2dafa53 | ||
|
|
188b0a0edd | ||
|
|
206c418ebc | ||
|
|
b0acf8d1ae | ||
|
|
f279ea41e6 | ||
|
|
d2a929f35d | ||
|
|
6f5258b5dd | ||
|
|
4f223a9439 | ||
|
|
ea98eb3d44 | ||
|
|
cdb8f85620 | ||
|
|
f459dcb8b3 | ||
|
|
967a539e71 | ||
|
|
db615da0ee | ||
|
|
c4b420bd31 | ||
|
|
a6c4730c44 | ||
|
|
eb1f4c5a14 | ||
|
|
b303af738c | ||
|
|
af5e11a265 | ||
|
|
8d7627069c | ||
|
|
9e94c0d67d | ||
|
|
55ddacf978 | ||
|
|
005e0552b6 | ||
|
|
54b28c42e2 | ||
|
|
2659ddb76b | ||
|
|
c85873c6ce | ||
|
|
6e32f3f915 | ||
|
|
b8891a5727 | ||
|
|
fcb6f5a6af | ||
|
|
0365f3194d | ||
|
|
76e2ec6429 | ||
|
|
a5d0a202a5 | ||
|
|
def752632f | ||
|
|
f296048063 | ||
|
|
1c1b816292 | ||
|
|
fbd463e18b | ||
|
|
9e01363648 | ||
|
|
67bf7e9775 | ||
|
|
d8c2100b24 | ||
|
|
d1a3e39f17 | ||
|
|
3d5c081333 | ||
|
|
e1085fb770 | ||
|
|
c294c19be7 | ||
|
|
87726fb0a7 | ||
|
|
d28e61f412 | ||
|
|
890e750c23 | ||
|
|
1fe5cfd121 | ||
|
|
c8eaf88cf1 | ||
|
|
f3f812205d | ||
|
|
7b2ec52831 | ||
|
|
72785cf869 | ||
|
|
e92ef472b3 | ||
|
|
deec6ffa31 | ||
|
|
47779c8d0a | ||
|
|
3e9e802b6c | ||
|
|
8bd429db4c | ||
|
|
d76b27863f | ||
|
|
576627eb17 | ||
|
|
74adb5f021 | ||
|
|
dcdcef1fb2 | ||
|
|
cf7311682e | ||
|
|
beb2128804 | ||
|
|
85cb289bc4 | ||
|
|
5293943a50 | ||
|
|
ee4d720c51 | ||
|
|
f8b698e669 | ||
|
|
0e3fcc7749 | ||
|
|
5755e5ff65 | ||
|
|
d9db3d0b29 | ||
|
|
87ba2e0ee7 | ||
|
|
eaeed567f3 | ||
|
|
a2054359a2 | ||
|
|
85b533d4c4 | ||
|
|
2d2c8524ee | ||
|
|
62271b11a7 | ||
|
|
869cacc568 | ||
|
|
0155790b02 | ||
|
|
2cb25fefe4 | ||
|
|
98225ac9a3 | ||
|
|
4bdfc35c8c | ||
|
|
f090a51485 | ||
|
|
b510c2fd5f | ||
|
|
03e58c7443 | ||
|
|
676086ba90 | ||
|
|
4f6b9e3dff | ||
|
|
c8a5bd3f15 | ||
|
|
5e83ddf7bd | ||
|
|
6b28a804f8 | ||
|
|
7c5e159677 | ||
|
|
63f8468f48 | ||
|
|
933a535494 | ||
|
|
518a7cb398 | ||
|
|
eac2cff09c | ||
|
|
9a601a5172 | ||
|
|
cf8f25988c | ||
|
|
a613e401e2 | ||
|
|
23e27ee953 | ||
|
|
633dc06e6f | ||
|
|
5ddf0ada76 | ||
|
|
c8664c4d44 | ||
|
|
d6d28b3f7b | ||
|
|
eddcfef5d8 | ||
|
|
737d63eede | ||
|
|
ba3890acfa | ||
|
|
9e8353f50f | ||
|
|
2db4398637 | ||
|
|
1348434b50 | ||
|
|
6cf527403e | ||
|
|
92843b4972 | ||
|
|
b2df16dcb0 | ||
|
|
8bb15f5447 | ||
|
|
2977f0b8c6 | ||
|
|
251423116f | ||
|
|
04e2a71b66 | ||
|
|
a06fec51c8 | ||
|
|
83eda81263 | ||
|
|
1bb476ca95 | ||
|
|
f0ac455ec1 | ||
|
|
44b2fc6944 | ||
|
|
113e6453ea | ||
|
|
283d814dc6 | ||
|
|
034dc25483 | ||
|
|
b1333b2c4c | ||
|
|
ff58ff72f9 | ||
|
|
00b4dbc821 | ||
|
|
35076bbdb6 | ||
|
|
2dc98804f4 | ||
|
|
961600fe74 | ||
|
|
7fdca76a4c | ||
|
|
32592f6ad1 | ||
|
|
1545e98e6d | ||
|
|
85b3feb10b | ||
|
|
d9fdd20caa | ||
|
|
9e2d001ac5 | ||
|
|
750f9b6142 | ||
|
|
1c3cf8cf2d | ||
|
|
db19cb40d7 | ||
|
|
037fa76fff | ||
|
|
caa2ece751 | ||
|
|
22f2975f3c | ||
|
|
d3323d824a | ||
|
|
41d1ea8f61 | ||
|
|
1e85b1e7fb | ||
|
|
75464708af | ||
|
|
f007451442 | ||
|
|
f591270d46 | ||
|
|
390423d0c1 | ||
|
|
1aed8c7429 | ||
|
|
0aee56114b | ||
|
|
b3ec7423e8 | ||
|
|
179cd4cf45 | ||
|
|
75d26c3cce | ||
|
|
9071664ef2 | ||
|
|
1980f9c42c | ||
|
|
2c917dcd7c | ||
|
|
5ccf15b9ed | ||
|
|
7eaac87640 | ||
|
|
5b9f08c754 | ||
|
|
02c165163a | ||
|
|
4bbc0f1d4f | ||
|
|
cf692797b6 | ||
|
|
0e4ec055b2 | ||
|
|
cf7c25cd88 | ||
|
|
60b5eb00a3 | ||
|
|
0705b4da72 | ||
|
|
09b3e685a9 | ||
|
|
64791eec82 | ||
|
|
dc3aa354ec | ||
|
|
890784ba5a | ||
|
|
c9468bef8a | ||
|
|
0b4c017f22 | ||
|
|
6de558773f | ||
|
|
94258abf43 | ||
|
|
10026ba191 |
12
.gitignore
vendored
@@ -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*
|
||||
|
||||
4
.vscode/settings.json
vendored
@@ -4,7 +4,7 @@
|
||||
"qevent": "cpp"
|
||||
},
|
||||
"cmake.configureSettings": {
|
||||
"OPTION_DEVELOPER_MODE" : "ON",
|
||||
"OPTION_QTQUICK" : true
|
||||
"KDDockWidgets_DEVELOPER_MODE" : "ON",
|
||||
"KDDockWidgets_QTQUICK" : true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
80
Changelog
@@ -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
|
||||
|
||||
27
README.md
@@ -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
|
||||
|
||||

|
||||
|
||||
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
<img src="kdab-logo-16x16.png">
|
||||
<font style="font-weight: bold;">Klarä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>
|
||||
|
||||
BIN
docs/api/kdab-kddockwidgets-logo-16x16.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"));
|
||||
|
||||
34
examples/qtquick/CMakeLists.txt
Normal 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
|
||||
)
|
||||
20
examples/qtquick/Guest.qml
Normal 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!"
|
||||
}
|
||||
}
|
||||
20
examples/qtquick/Guest1.qml
Normal 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 !"
|
||||
}
|
||||
}
|
||||
20
examples/qtquick/Guest2.qml
Normal 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!"
|
||||
}
|
||||
}
|
||||
20
examples/qtquick/Guest3.qml
Normal 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
@@ -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
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
8
examples/qtquick/resources_example.qrc
Normal 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>
|
||||
BIN
images/KDDockWidgets-128x128.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
320
images/KDDockWidgets-128x128.svg
Normal 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 |
BIN
images/KDDockWidgets-16x16.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
images/KDDockWidgets-24x24.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
images/KDDockWidgets-32x32.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
images/KDDockWidgets-48x48.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
images/KDDockWidgets-64x64.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
images/KDDockWidgets-banner.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
862
images/KDDockWidgets-banner.svg
Normal 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 |
BIN
images/KDDockWidgets-logo.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
77
src/Config.h
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(Qt5Widgets REQUIRED)
|
||||
if (@OPTION_QTQUICK@)
|
||||
if (@KDDockWidgets_QTQUICK@)
|
||||
find_dependency(Qt5Quick REQUIRED)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -79,6 +79,8 @@ public:
|
||||
, LayoutGuestWidgetBase(this)
|
||||
{
|
||||
}
|
||||
|
||||
~LayoutGuestWidget() override;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../../../private/indicators/ClassicIndicators_p.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../../../../private/indicators/SegmentedIndicators_p.h"
|
||||
@@ -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
|
After Width: | Height: | Size: 473 B |
BIN
src/img/auto-hide-2x.png
Normal file
|
After Width: | Height: | Size: 477 B |
BIN
src/img/auto-hide.png
Normal file
|
After Width: | Height: | Size: 208 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
src/img/close-1.5x.png
Normal file
|
After Width: | Height: | Size: 496 B |
BIN
src/img/close-2x.png
Normal file
|
After Width: | Height: | Size: 543 B |
BIN
src/img/close.png
Normal file
|
After Width: | Height: | Size: 405 B |
BIN
src/img/dock-float-1.5x.png
Normal file
|
After Width: | Height: | Size: 438 B |
BIN
src/img/dock-float-2x.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
src/img/dock-float.png
Normal file
|
After Width: | Height: | Size: 286 B |
BIN
src/img/max-1.5x.png
Normal file
|
After Width: | Height: | Size: 385 B |
BIN
src/img/max-2x.png
Normal file
|
After Width: | Height: | Size: 445 B |
BIN
src/img/max.png
Normal file
|
After Width: | Height: | Size: 274 B |
BIN
src/img/min-1.5x.png
Normal file
|
After Width: | Height: | Size: 317 B |
BIN
src/img/min-2x.png
Normal file
|
After Width: | Height: | Size: 386 B |
BIN
src/img/min.png
Normal file
|
After Width: | Height: | Size: 239 B |
BIN
src/img/unauto-hide-1.5x.png
Normal file
|
After Width: | Height: | Size: 461 B |
BIN
src/img/unauto-hide-2x.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
src/img/unauto-hide.png
Normal file
|
After Width: | Height: | Size: 218 B |
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||