Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db9babbdca | ||
|
|
463dd2261e | ||
|
|
4dd66969af | ||
|
|
2c98003219 | ||
|
|
dd853a8f72 | ||
|
|
88d5e6b29d | ||
|
|
71e5d8cc31 | ||
|
|
15b3843172 | ||
|
|
3cffe3b3be | ||
|
|
9dd87b7777 | ||
|
|
b057cf905b | ||
|
|
d7943d30d8 | ||
|
|
1826d68841 | ||
|
|
dc1e5103e2 | ||
|
|
33c5647e57 | ||
|
|
f6f772edc5 | ||
|
|
7e460d8f34 | ||
|
|
7af2095f2f | ||
|
|
8307598d5d | ||
|
|
13fe276dbe | ||
|
|
13a5a472cd | ||
|
|
b5c11ce199 | ||
|
|
83c8c22736 | ||
|
|
c8ca7bf9e1 | ||
|
|
0184deb54d | ||
|
|
389042f3cc | ||
|
|
736358a71f | ||
|
|
bffe671679 | ||
|
|
fafc0b7946 | ||
|
|
3574feea98 | ||
|
|
25b48920bb | ||
|
|
e22ca48674 | ||
|
|
3b9773f872 | ||
|
|
3e3cf10fff | ||
|
|
421b401b4f | ||
|
|
a0c97e3388 | ||
|
|
d2a3968897 | ||
|
|
4ea7953a76 | ||
|
|
0cc0972eea | ||
|
|
77b5d1630d | ||
|
|
f962989484 | ||
|
|
1ccdf445eb | ||
|
|
3fb8861eee | ||
|
|
78381badd1 | ||
|
|
8b1a9f2a41 | ||
|
|
9ee52a0011 | ||
|
|
97a431f367 | ||
|
|
3769ad9615 | ||
|
|
8332ab3ddc | ||
|
|
3b4a2f134f | ||
|
|
5899e3716c | ||
|
|
25bc05ae40 | ||
|
|
f42629a6e5 | ||
|
|
192cb2daaa | ||
|
|
63cc87af2d | ||
|
|
3e1ea3ec67 | ||
|
|
c27a09c13c | ||
|
|
6a7230e546 | ||
|
|
ca173de71d | ||
|
|
5732e8ed14 | ||
|
|
5cc7a0864b | ||
|
|
e4671f175c | ||
|
|
17fd6b2454 | ||
|
|
7ed3945d58 | ||
|
|
35de0a2fef | ||
|
|
8a0e475f21 | ||
|
|
63d14f2345 | ||
|
|
e91849759c | ||
|
|
ee3a3af408 | ||
|
|
ffe5d5f6cb | ||
|
|
d40580c550 | ||
|
|
8e19b81eb9 | ||
|
|
d5191696e1 | ||
|
|
1d01466181 | ||
|
|
aff4d426b8 | ||
|
|
2e7f0bf51d | ||
|
|
fa551b84f6 | ||
|
|
31d4b62181 | ||
|
|
7ec542a211 | ||
|
|
e615d1c618 | ||
|
|
c86813b1cb | ||
|
|
1fe651aaa7 | ||
|
|
ba7809236b | ||
|
|
84814b3c59 | ||
|
|
73ca6e6671 | ||
|
|
990fac9a0a | ||
|
|
31ec4cdecb | ||
|
|
e32aaccaac | ||
|
|
3302401a36 | ||
|
|
c0c1383254 | ||
|
|
13a7d27046 |
@@ -1,4 +1,4 @@
|
||||
[codespell]
|
||||
skip = ./build-*,.git
|
||||
skip = ./build-*,.git,*.svg,rc_assets.py
|
||||
interactive = 3
|
||||
ignore-words-list = overlay,overlayed
|
||||
|
||||
2
.krazy
2
.krazy
@@ -19,5 +19,5 @@ SKIP /KDDockWidgetsConfig.cmake.in
|
||||
#skip more files
|
||||
SKIP CMakePresets.json
|
||||
#skip the borrowed code in the cmake subdir
|
||||
SKIP /cmake/Qt5Portability.cmake|/cmake/ECM/|/cmake/InstallLocation.cmake
|
||||
SKIP /cmake/InstallLocation.cmake|/cmake/ECM/|/cmake/KDAB/
|
||||
|
||||
|
||||
298
CMakeLists.txt
298
CMakeLists.txt
@@ -19,12 +19,6 @@
|
||||
# Build static versions of the libraries
|
||||
# Default=false
|
||||
#
|
||||
# -DKDDockWidgets_UNINSTALL=[true|false]
|
||||
# Setup the uninstall target.
|
||||
# You may want to disable the uninstall target when you are using KDDockWidgets
|
||||
# as a submodule directly and have a custom uninstall target of your own.
|
||||
# Default=true
|
||||
#
|
||||
# -DKDDockWidgets_TESTS=[true|false]
|
||||
# Build the test harness.
|
||||
# Currently ignored unless you also set KDDockWidgets_DEVELOPER_MODE=True
|
||||
@@ -45,7 +39,7 @@
|
||||
# -DKDDockWidgets_PYTHON_BINDINGS=[true|false]
|
||||
# Build/Generate python bindings. Always false for Debug builds
|
||||
# (If your shiboken or pyside is installed in a non-standard locations
|
||||
# try passing the SHIBOKEN_CUSTOM_PREFIX and PYSIDE2_CUSTOM_PREFIX variables.)
|
||||
# try passing the SHIBOKEN_CUSTOM_PREFIX and PYSIDE_CUSTOM_PREFIX variables.)
|
||||
# Default=false
|
||||
#
|
||||
# -DKDDockWidgets_PYTHON_BINDINGS_INSTALL_PREFIX=[path]
|
||||
@@ -76,12 +70,6 @@
|
||||
# Default=true
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
if(POLICY CMP0020)
|
||||
cmake_policy(SET CMP0020 NEW)
|
||||
endif()
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
|
||||
# Allow using a non-KDAB install location.
|
||||
set(KDAB_INSTALL True CACHE INTERNAL "Install to default KDAB Location")
|
||||
@@ -102,65 +90,27 @@ endif()
|
||||
|
||||
set(${PROJECT_NAME}_VERSION_MAJOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 4)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 1)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 95)
|
||||
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
|
||||
set(PROJECT_VERSION ${${PROJECT_NAME}_VERSION}) #PROJECT_VERSION is needed by some ECM modules
|
||||
set(${PROJECT_NAME}_SOVERSION "1.4")
|
||||
set(${PROJECT_NAME}_SOVERSION "1.5")
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
option(${PROJECT_NAME}_QT6 "Build against Qt 6" OFF)
|
||||
option(${PROJECT_NAME}_DEVELOPER_MODE "Developer Mode" OFF)
|
||||
option(${PROJECT_NAME}_PYTHON_BINDINGS "Build python bindings" OFF)
|
||||
option(${PROJECT_NAME}_UNINSTALL "Enable the uninstall target" ON)
|
||||
option(${PROJECT_NAME}_QTQUICK "Build for QtQuick instead of QtWidgets" OFF)
|
||||
option(${PROJECT_NAME}_STATIC "Build statically" OFF)
|
||||
option(${PROJECT_NAME}_TESTS "Build the tests" OFF)
|
||||
option(${PROJECT_NAME}_EXAMPLES "Build the examples" ON)
|
||||
option(${PROJECT_NAME}_DOCS "Build the API documentation" OFF)
|
||||
option(${PROJECT_NAME}_WERROR "Use -Werror (will be true for developer-mode unconditionally)" OFF)
|
||||
option(${PROJECT_NAME}_X11EXTRAS "On Linux, link against QtX11Extras so we can detect if the compositor supports transparency. Not applicable to other platforms or Qt6." ON)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/ECM/modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/KDAB/modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/Python")
|
||||
|
||||
#Always build the test harness in developer-mode
|
||||
if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
set(${PROJECT_NAME}_TESTS ON)
|
||||
set(${PROJECT_NAME}_WERROR ON)
|
||||
include(ECMEnableSanitizers)
|
||||
endif()
|
||||
|
||||
option(${PROJECT_NAME}_QTQUICK "Build for QtQuick instead of QtWidgets" OFF)
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
set(IS_CLANG_BUILD TRUE)
|
||||
else()
|
||||
set(IS_CLANG_BUILD FALSE)
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_QT6)
|
||||
find_package(Qt6Widgets REQUIRED)
|
||||
find_package(Qt6Test REQUIRED)
|
||||
set(QT_MAJOR_VERSION 6)
|
||||
set(KDDockWidgets_LIBRARY_QTID "-qt6")
|
||||
else()
|
||||
find_package(Qt5Widgets 5.12 REQUIRED)
|
||||
find_package(Qt5Test 5.12 REQUIRED)
|
||||
set(QT_MAJOR_VERSION 5)
|
||||
set(KDDockWidgets_LIBRARY_QTID "")
|
||||
endif()
|
||||
include(KDQtInstallPaths) #to set QT_INSTALL_FOO variables
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
# Set a default build type if none was specified
|
||||
set(default_build_type "Release")
|
||||
@@ -174,6 +124,61 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_QT6)
|
||||
set(Qt_VERSION_MAJOR 6)
|
||||
set(QT_MIN_VERSION "6.0.0")
|
||||
find_package(Qt6Widgets ${QT_MIN_VERSION} REQUIRED)
|
||||
find_package(Qt6Test ${QT_MIN_VERSION} REQUIRED)
|
||||
set(${PROJECT_NAME}_LIBRARY_QTID "-qt6")
|
||||
else()
|
||||
set(Qt_VERSION_MAJOR 5)
|
||||
set(QT_MIN_VERSION "5.12")
|
||||
find_package(Qt5Widgets ${QT_MIN_VERSION} REQUIRED)
|
||||
find_package(Qt5Test ${QT_MIN_VERSION} REQUIRED)
|
||||
set(${PROJECT_NAME}_LIBRARY_QTID "")
|
||||
endif()
|
||||
include(KDQtInstallPaths) #to set QT_INSTALL_FOO variables
|
||||
|
||||
set(${PROJECT_NAME}_DEPS "widgets")
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
find_package(Qt${Qt_VERSION_MAJOR}Quick)
|
||||
find_package(Qt${Qt_VERSION_MAJOR}QuickControls2)
|
||||
add_definitions(-DKDDOCKWIDGETS_QTQUICK)
|
||||
set(${PROJECT_NAME}_DEPS "${${PROJECT_NAME}_DEPS} quick quickcontrols2")
|
||||
else()
|
||||
add_definitions(-DKDDOCKWIDGETS_QTWIDGETS)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT ${PROJECT_NAME}_QT6 AND ${PROJECT_NAME}_X11EXTRAS)
|
||||
set(${PROJECT_NAME}_DEPS "${${PROJECT_NAME}_DEPS} x11extras")
|
||||
endif()
|
||||
|
||||
#Always build the test harness in developer-mode
|
||||
if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
set(${PROJECT_NAME}_TESTS ON)
|
||||
set(${PROJECT_NAME}_WERROR ON)
|
||||
include(ECMEnableSanitizers)
|
||||
endif()
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
set(IS_CLANG_BUILD TRUE)
|
||||
else()
|
||||
set(IS_CLANG_BUILD FALSE)
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
# Default to hidden visibility for symbols
|
||||
set(CMAKE_C_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
|
||||
|
||||
macro(set_compiler_flags targetName)
|
||||
if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
target_compile_definitions(${targetName} PUBLIC DOCKS_DEVELOPER_MODE PRIVATE QT_FORCE_ASSERTS)
|
||||
@@ -191,22 +196,28 @@ macro(set_compiler_flags targetName)
|
||||
if(${PROJECT_NAME}_WERROR AND (NOT MSVC OR IS_CLANG_BUILD)) # clang-cl accepts these too
|
||||
target_compile_options(${targetName} PRIVATE -Werror -Wundef -Wno-error=deprecated-declarations)
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
||||
set(${PROJECT_NAME}_DEPS "widgets")
|
||||
if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE) OR
|
||||
(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) OR
|
||||
(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT WIN32))
|
||||
# Linker warnings should be treated as errors
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fatal-warnings ${CMAKE_MODULE_LINKER_FLAGS}")
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
find_package(Qt${QT_MAJOR_VERSION}Quick)
|
||||
find_package(Qt${QT_MAJOR_VERSION}QuickControls2)
|
||||
add_definitions(-DKDDOCKWIDGETS_QTQUICK)
|
||||
set(${PROJECT_NAME}_DEPS "${${PROJECT_NAME}_DEPS} quick quickcontrols2")
|
||||
else()
|
||||
add_definitions(-DKDDOCKWIDGETS_QTWIDGETS)
|
||||
endif()
|
||||
string(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" compileflags)
|
||||
if("${CMAKE_CXX_FLAGS} ${${compileflags}}" MATCHES "-fsanitize")
|
||||
set(sanitizers_enabled TRUE)
|
||||
else()
|
||||
set(sanitizers_enabled FALSE)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT ${PROJECT_NAME}_QT6)
|
||||
set(${PROJECT_NAME}_DEPS "${${PROJECT_NAME}_DEPS} x11extras")
|
||||
# cannot enable this for clang + sanitizers
|
||||
if(NOT sanitizers_enabled OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# Do not allow undefined symbols, even in non-symbolic shared libraries
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_SHARED_LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_MODULE_LINKER_FLAGS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_STATIC)
|
||||
@@ -226,18 +237,22 @@ endif()
|
||||
# setup default install locations
|
||||
include(InstallLocation)
|
||||
|
||||
add_subdirectory(src)
|
||||
if(${PROJECT_NAME}_PYTHON_BINDINGS)
|
||||
if(CMAKE_BUILD_TYPE MATCHES "^[Dd]eb" OR ${PROJECT_NAME}_STATIC)
|
||||
message(FATAL_ERROR "** Python Bindings are disabled in debug or static builds.")
|
||||
endif()
|
||||
add_subdirectory(python)
|
||||
endif()
|
||||
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
set(${PROJECT_NAME}_IS_ROOT_PROJECT TRUE)
|
||||
|
||||
# Generate .pri file for qmake users
|
||||
if(CMAKE_VERSION VERSION_GREATER "3.11.99" AND NOT CMAKE_CONFIGURATION_TYPES) # Not working with VS generator or older cmake versions
|
||||
message(STATUS "Building ${PROJECT_NAME} ${${PROJECT_NAME}_VERSION} in ${CMAKE_BUILD_TYPE} mode. Installing to ${CMAKE_INSTALL_PREFIX}")
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
|
||||
|
||||
install(FILES LICENSE.txt README.md DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(DIRECTORY LICENSES DESTINATION ${INSTALL_DOC_DIR})
|
||||
|
||||
# Generate .pri file for qmake users
|
||||
#TODO: ECM does not support Qt6 yet
|
||||
if(QT_MAJOR_VERSION EQUAL 5)
|
||||
if(Qt_VERSION_MAJOR EQUAL 5 AND
|
||||
CMAKE_VERSION VERSION_GREATER "3.11.99" AND NOT CMAKE_CONFIGURATION_TYPES) # Not working with VS generator or older cmake versions
|
||||
include(ECMGeneratePriFile)
|
||||
set(PROJECT_VERSION_STRING ${${PROJECT_NAME}_VERSION})
|
||||
ecm_generate_pri_file(BASE_NAME KDDockWidgets
|
||||
@@ -248,77 +263,80 @@ if(CMAKE_VERSION VERSION_GREATER "3.11.99" AND NOT CMAKE_CONFIGURATION_TYPES) #
|
||||
)
|
||||
install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Unable to generate the pri file for qmake users. Try updating CMake.")
|
||||
endif()
|
||||
|
||||
install(FILES LICENSE.txt README.md DESTINATION ${INSTALL_DOC_DIR})
|
||||
install(DIRECTORY LICENSES DESTINATION ${INSTALL_DOC_DIR})
|
||||
add_subdirectory(src)
|
||||
|
||||
if(${PROJECT_NAME}_EXAMPLES)
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
add_subdirectory(examples/qtquick)
|
||||
if(${PROJECT_NAME}_IS_ROOT_PROJECT)
|
||||
if(${PROJECT_NAME}_EXAMPLES)
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
add_subdirectory(examples/qtquick)
|
||||
else()
|
||||
add_subdirectory(examples/dockwidgets)
|
||||
add_subdirectory(examples/minimal)
|
||||
add_subdirectory(examples/minimal-mdi)
|
||||
set_compiler_flags(kddockwidgets_example)
|
||||
set_compiler_flags(kddockwidgets_minimal_example)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
|
||||
if(${PROJECT_NAME}_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
|
||||
# Require Qt5.15.1 or higher to run the tests_launcher tests on Mac
|
||||
if(NOT APPLE OR Qt5Widgets_VERSION VERSION_GREATER 5.15.0)
|
||||
# tst_docks.exe is pretty big (160 tests), so split it in more runs so we can use threads.
|
||||
add_test(NAME tst_docks0 COMMAND tests_launcher 0 5)
|
||||
add_test(NAME tst_docks1 COMMAND tests_launcher 1 5)
|
||||
add_test(NAME tst_docks2 COMMAND tests_launcher 2 5)
|
||||
add_test(NAME tst_docks3 COMMAND tests_launcher 3 5)
|
||||
add_test(NAME tst_docks4 COMMAND tests_launcher 4 5)
|
||||
add_test(NAME tst_docks5 COMMAND tests_launcher 5 5)
|
||||
add_test(NAME tst_docks6 COMMAND tests_launcher 6 5)
|
||||
add_test(NAME tst_docks7 COMMAND tests_launcher 7 5)
|
||||
add_test(NAME tst_docks8 COMMAND tests_launcher 8 5)
|
||||
add_test(NAME tst_docks9 COMMAND tests_launcher 9 5)
|
||||
add_test(NAME tst_docks10 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks11 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks12 COMMAND tests_launcher 11 5)
|
||||
add_test(NAME tst_docks13 COMMAND tests_launcher 12 5)
|
||||
add_test(NAME tst_docks14 COMMAND tests_launcher 13 5)
|
||||
add_test(NAME tst_docks15 COMMAND tests_launcher 14 5)
|
||||
add_test(NAME tst_docks16 COMMAND tests_launcher 15 5)
|
||||
add_test(NAME tst_docks17 COMMAND tests_launcher 16 5)
|
||||
add_test(NAME tst_docks18 COMMAND tests_launcher 17 5)
|
||||
add_test(NAME tst_docks19 COMMAND tests_launcher 18 5)
|
||||
add_test(NAME tst_docks20 COMMAND tests_launcher 19 5)
|
||||
add_test(NAME tst_docks21 COMMAND tests_launcher 20 5) # one more for rounding leftovers
|
||||
endif()
|
||||
if(NOT ${PROJECT_NAME}_QTQUICK)
|
||||
# tst_multisplitter depends on QWidget
|
||||
add_test(NAME tst_multisplitter COMMAND tst_multisplitter)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_DOCS)
|
||||
add_subdirectory(docs) # needs to go last, in case there are build source files
|
||||
else()
|
||||
add_subdirectory(examples/dockwidgets)
|
||||
add_subdirectory(examples/minimal)
|
||||
add_subdirectory(examples/minimal-mdi)
|
||||
set_compiler_flags(kddockwidgets_example)
|
||||
set_compiler_flags(kddockwidgets_minimal_example)
|
||||
add_custom_target(docs
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Sorry, there is no docs target since KDDockWidgets_DOCS=OFF."
|
||||
"Re-run cmake with the -DKDDockWidgets_DOCS=True option if you want to generate the documentation.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
|
||||
if(${PROJECT_NAME}_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
|
||||
# Require Qt5.15.1 or higher to run the tests_launcher tests on Mac
|
||||
if(NOT APPLE OR Qt5Widgets_VERSION VERSION_GREATER 5.15.0)
|
||||
# tst_docks.exe is pretty big (160 tests), so split it in more runs so we can use threads.
|
||||
add_test(NAME tst_docks0 COMMAND tests_launcher 0 5)
|
||||
add_test(NAME tst_docks1 COMMAND tests_launcher 1 5)
|
||||
add_test(NAME tst_docks2 COMMAND tests_launcher 2 5)
|
||||
add_test(NAME tst_docks3 COMMAND tests_launcher 3 5)
|
||||
add_test(NAME tst_docks4 COMMAND tests_launcher 4 5)
|
||||
add_test(NAME tst_docks5 COMMAND tests_launcher 5 5)
|
||||
add_test(NAME tst_docks6 COMMAND tests_launcher 6 5)
|
||||
add_test(NAME tst_docks7 COMMAND tests_launcher 7 5)
|
||||
add_test(NAME tst_docks8 COMMAND tests_launcher 8 5)
|
||||
add_test(NAME tst_docks9 COMMAND tests_launcher 9 5)
|
||||
add_test(NAME tst_docks10 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks11 COMMAND tests_launcher 10 5)
|
||||
add_test(NAME tst_docks12 COMMAND tests_launcher 11 5)
|
||||
add_test(NAME tst_docks13 COMMAND tests_launcher 12 5)
|
||||
add_test(NAME tst_docks14 COMMAND tests_launcher 13 5)
|
||||
add_test(NAME tst_docks15 COMMAND tests_launcher 14 5)
|
||||
add_test(NAME tst_docks16 COMMAND tests_launcher 15 5)
|
||||
add_test(NAME tst_docks17 COMMAND tests_launcher 16 5)
|
||||
add_test(NAME tst_docks18 COMMAND tests_launcher 17 5)
|
||||
add_test(NAME tst_docks19 COMMAND tests_launcher 18 5)
|
||||
add_test(NAME tst_docks20 COMMAND tests_launcher 19 5)
|
||||
add_test(NAME tst_docks21 COMMAND tests_launcher 20 5) # one more for rounding leftovers
|
||||
endif()
|
||||
if(NOT ${PROJECT_NAME}_QTQUICK)
|
||||
# tst_multisplitter depends on QWidget
|
||||
add_test(NAME tst_multisplitter COMMAND tst_multisplitter)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_DOCS)
|
||||
add_subdirectory(docs) # needs to go last, in case there are build source files
|
||||
#don't create the dummy docs target as it can conflict when used as a submodule
|
||||
#else()
|
||||
# add_custom_target(docs
|
||||
# COMMAND ${CMAKE_COMMAND} -E echo "Sorry, there is no docs target since KDDockWidgets_DOCS=OFF."
|
||||
# "Re-run cmake with the -DKDDockWidgets_DOCS=True option if you want to generate the documentation.")
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_UNINSTALL)
|
||||
# Add uninstall target
|
||||
include(ECMUninstallTarget)
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_PYTHON_BINDINGS)
|
||||
if(CMAKE_BUILD_TYPE MATCHES "^[Dd]eb" OR ${PROJECT_NAME}_STATIC)
|
||||
message(FATAL_ERROR "** Python Bindings are disabled in debug or static builds.")
|
||||
endif()
|
||||
add_subdirectory(python)
|
||||
endif()
|
||||
|
||||
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||
|
||||
@@ -74,6 +74,17 @@
|
||||
"CMAKE_UNITY_BUILD" : "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "release-no-x11extras",
|
||||
"displayName": "release-no-x11extras",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build-release-no-x11extras",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_UNITY_BUILD" : "ON",
|
||||
"KDDockWidgets_X11EXTRAS" : "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "release-qtquick",
|
||||
"displayName": "release-qtquick",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
* v1.5.0 (unreleased)
|
||||
- Install the Python bindings to "site-packages"
|
||||
- The Python bindings for Qt6 use the "PyKDDockWidgetsQt6" namespace
|
||||
- Co-installable with Qt6
|
||||
- Adds support for non-detachable central widget, MainWindowOption_HasCentralWidget. (#225)
|
||||
|
||||
* v1.4.1 (unreleased)
|
||||
-
|
||||
-
|
||||
|
||||
* v1.4.0 (16 July 2021)
|
||||
- No longer supports Qt versions less than 5.12
|
||||
|
||||
@@ -106,12 +106,18 @@ You can change the installation location by passing the option `-DCMAKE_INSTALL_
|
||||
|
||||
Using
|
||||
=====
|
||||
From your CMake project, add
|
||||
From your CMake Qt5 project, add
|
||||
|
||||
```
|
||||
find_package(KDDockWidgets CONFIG)
|
||||
```
|
||||
|
||||
or for Qt6
|
||||
|
||||
```
|
||||
find_package(KDDockWidgets-qt6 CONFIG)
|
||||
```
|
||||
|
||||
and link to the imported target `KDAB::kddockwidgets`.
|
||||
That's all you need to do (the imported target also brings in the include directories)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ if(NOT INSTALL_DATADIR)
|
||||
set(INSTALL_DATADIR ${CMAKE_INSTALL_DATADIR})
|
||||
endif()
|
||||
if(NOT INSTALL_DOC_DIR)
|
||||
set(INSTALL_DOC_DIR ${CMAKE_INSTALL_DOCDIR})
|
||||
set(INSTALL_DOC_DIR ${CMAKE_INSTALL_DOCDIR}${KDDockWidgets_LIBRARY_QTID})
|
||||
endif()
|
||||
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
@@ -5,43 +5,48 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
# Assumes you've already found Qt and Qt_VERSION_MAJOR is set
|
||||
#
|
||||
# Create variables for all the various install paths for the Qt version in use
|
||||
# Make sure to have found Qt before using this.
|
||||
# sets variables like QT_INSTALL_PREFIX, QT_INSTALL_DATA, QT_INSTALL_DOCS, etc.
|
||||
# run qmake -query to see a full list
|
||||
|
||||
if(TARGET Qt${QT_MAJOR_VERSION}::qmake)
|
||||
get_target_property(QT_QMAKE_EXECUTABLE Qt${QT_MAJOR_VERSION}::qmake LOCATION)
|
||||
if(NOT DEFINED Qt_VERSION_MAJOR)
|
||||
message(FATAL_ERROR "Please set Qt_VERSION_MAJOR first (ie. set(Qt_VERSION_MAJOR 5))")
|
||||
endif()
|
||||
|
||||
if(TARGET Qt${Qt_VERSION_MAJOR}::qmake)
|
||||
get_target_property(QT_QMAKE_EXECUTABLE Qt${Qt_VERSION_MAJOR}::qmake LOCATION)
|
||||
else()
|
||||
message(FATAL_ERROR "No supported Qt version found. Make sure you find Qt before calling this")
|
||||
message(FATAL_ERROR "No supported Qt version found. Make sure you find Qt before calling this")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${QT_QMAKE_EXECUTABLE} -query
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE ALL_VARS
|
||||
COMMAND ${QT_QMAKE_EXECUTABLE} -query
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE ALL_VARS
|
||||
)
|
||||
if(NOT return_code EQUAL 0)
|
||||
message(WARNING "Failed call: ${QMAKE_EXECUTABLE} -query")
|
||||
message(FATAL_ERROR "QMake call failed: ${return_code}")
|
||||
message(WARNING "Failed call: ${QMAKE_EXECUTABLE} -query")
|
||||
message(FATAL_ERROR "QMake call failed: ${return_code}")
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" VARS_LIST ${ALL_VARS})
|
||||
foreach(QVAL ${VARS_LIST})
|
||||
if(QVAL MATCHES "QT_INSTALL_")
|
||||
string(REPLACE ":" ";" QVAL_LIST ${QVAL})
|
||||
list(LENGTH QVAL_LIST listlen)
|
||||
list(GET QVAL_LIST 0 var)
|
||||
if(WIN32 AND ${listlen} GREATER 2)
|
||||
list(GET QVAL_LIST 2 path)
|
||||
list(GET QVAL_LIST 1 drive)
|
||||
set(path "${drive}:${path}")
|
||||
else()
|
||||
list(GET QVAL_LIST 1 path)
|
||||
if(QVAL MATCHES "QT_INSTALL_")
|
||||
string(REPLACE ":" ";" QVAL_LIST ${QVAL})
|
||||
list(LENGTH QVAL_LIST listlen)
|
||||
list(GET QVAL_LIST 0 var)
|
||||
if(WIN32 AND ${listlen} GREATER 2)
|
||||
list(GET QVAL_LIST 2 path)
|
||||
list(GET QVAL_LIST 1 drive)
|
||||
set(path "${drive}:${path}")
|
||||
else()
|
||||
list(GET QVAL_LIST 1 path)
|
||||
endif()
|
||||
if(NOT ${var}) #if set already on the command line for example
|
||||
set(${var} ${path} CACHE PATH "Qt install path for ${var}")
|
||||
endif()
|
||||
endif()
|
||||
if(NOT ${var}) #if set already on the command line for example
|
||||
set(${var} ${path} CACHE PATH "Qt install path for ${var}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
@@ -130,6 +130,11 @@ macro(CREATE_PYTHON_BINDINGS
|
||||
OUTPUT_NAME ${MODULE_NAME}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${MODULE_OUTPUT_DIR}
|
||||
)
|
||||
if(APPLE)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@loader_path")
|
||||
elseif(NOT WIN32) #ie. linux
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".pyd")
|
||||
@@ -130,6 +130,11 @@ macro(CREATE_PYTHON_BINDINGS
|
||||
OUTPUT_NAME ${MODULE_NAME}
|
||||
LIBRARY_OUTPUT_DIRECTORY ${MODULE_OUTPUT_DIR}
|
||||
)
|
||||
if(APPLE)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "@loader_path")
|
||||
elseif(NOT WIN32) #ie. linux
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "$ORIGIN")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".pyd")
|
||||
@@ -74,15 +74,15 @@ cmake . -DCMAKE_INSTALL_PREFIX=/usr -DKDDockWidgets_QT6=True -DCMAKE_BUILD_TYPE=
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%{_prefix}/share/doc/KDDockWidgets
|
||||
%{_prefix}/share/doc/KDDockWidgets-qt6
|
||||
%{_libdir}/libkddockwidgets-qt6.so.*
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
%dir %{_includedir}/kddockwidgets
|
||||
%{_includedir}/kddockwidgets/*
|
||||
%dir %{_libdir}/cmake/KDDockWidgets
|
||||
%{_libdir}/cmake/KDDockWidgets/*
|
||||
%dir %{_includedir}/kddockwidgets-qt6
|
||||
%{_includedir}/kddockwidgets-qt6/kddockwidgets/*
|
||||
%dir %{_libdir}/cmake/KDDockWidgets-qt6
|
||||
%{_libdir}/cmake/KDDockWidgets-qt6/*
|
||||
%{_libdir}/libkddockwidgets-qt6.so
|
||||
#%{_prefix}/mkspecs/modules/* ECMGeneratePriFile isn't ported to Qt6 yet
|
||||
|
||||
|
||||
@@ -9,17 +9,6 @@
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
# qhelpgenerator
|
||||
find_program(QHELPGEN_EXECUTABLE qhelpgenerator
|
||||
HINTS ${QT_INSTALL_BINS}
|
||||
)
|
||||
if(QHELPGEN_EXECUTABLE)
|
||||
set(HAVE_QHELPGEN "YES")
|
||||
else()
|
||||
set(HAVE_QHELPGEN "NO")
|
||||
message(STATUS "Unable to generate the API documentation in qch format. To fix, install the qthelpgenerator program which comes with Qt5.")
|
||||
endif()
|
||||
|
||||
# Doxygen
|
||||
find_package(Doxygen)
|
||||
set_package_properties(Doxygen PROPERTIES
|
||||
@@ -28,12 +17,6 @@ set_package_properties(Doxygen PROPERTIES
|
||||
URL "https://www.doxygen.org"
|
||||
PURPOSE "Needed to build the API documentation."
|
||||
)
|
||||
if(DOXYGEN_DOT_EXECUTABLE)
|
||||
set(HAVE_DOT "YES")
|
||||
else()
|
||||
set(HAVE_DOT "NO")
|
||||
message(STATUS "Unable to provide inheritance diagrams for the API documentation. To fix, install the graphviz project from https://www.graphviz.org")
|
||||
endif()
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
add_subdirectory(api)
|
||||
|
||||
@@ -9,6 +9,25 @@
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
# dot should come with Doxygen find_package(Doxygen)
|
||||
if(DOXYGEN_DOT_EXECUTABLE)
|
||||
set(HAVE_DOT "YES")
|
||||
else()
|
||||
set(HAVE_DOT "NO")
|
||||
message(STATUS "Unable to provide inheritance diagrams for the API documentation. To fix, install the graphviz project from https://www.graphviz.org")
|
||||
endif()
|
||||
|
||||
# qhelpgenerator
|
||||
find_program(QHELPGEN_EXECUTABLE qhelpgenerator
|
||||
HINTS ${QT_INSTALL_BINS}
|
||||
)
|
||||
if(QHELPGEN_EXECUTABLE)
|
||||
set(HAVE_QHELPGEN "YES")
|
||||
else()
|
||||
set(HAVE_QHELPGEN "NO")
|
||||
message(STATUS "Unable to generate the API documentation in qch format. To fix, install the qthelpgenerator program which comes with Qt.")
|
||||
endif()
|
||||
|
||||
find_file(QDOC_QTCORE_TAG qtcore.tags
|
||||
HINTS ${QT_INSTALL_DOCS}/qtcore
|
||||
HINTS ${QT_INSTALL_DATA}/doc/qtcore
|
||||
@@ -47,4 +66,6 @@ add_custom_command(
|
||||
add_custom_target(kddockwidgets-api.qch ALL DEPENDS ${DOXYGEN_OUTPUT_DIR}/qch/kddockwidgets-api.qch)
|
||||
add_custom_target(docs DEPENDS kddockwidgets-api.qch)
|
||||
|
||||
install(FILES ${DOXYGEN_OUTPUT_DIR}/qch/kddockwidgets-api.qch DESTINATION ${INSTALL_DOC_DIR})
|
||||
set(QCH_INSTALL_DIR ${INSTALL_DOC_DIR} CACHE STRING "Install location of Qt Assistant help files.")
|
||||
install(FILES ${DOXYGEN_OUTPUT_DIR}/qch/kddockwidgets-api.qch DESTINATION ${QCH_INSTALL_DIR})
|
||||
install(FILES ${DOXYGEN_OUTPUT_DIR}/kddockwidgets.tags DESTINATION ${INSTALL_DOC_DIR})
|
||||
|
||||
@@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "KDDockWidgets API Documentation"
|
||||
PROJECT_NAME = "@PROJECT_NAME@ API Documentation"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
@@ -874,7 +874,9 @@ INPUT_ENCODING = UTF-8
|
||||
|
||||
FILE_PATTERNS = *.cpp \
|
||||
*.h \
|
||||
*.md
|
||||
*.dox \
|
||||
*.md \
|
||||
*.gif
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
@@ -1446,7 +1448,7 @@ QCH_FILE = "@DOXYGEN_OUTPUT_DIR@/qch/kddockwidgets-api.qch"
|
||||
# The default value is: org.doxygen.Project.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_NAMESPACE = com.kdab.KDDockWidgets.api.@KDDockWidgets_VERSION@
|
||||
QHP_NAMESPACE = com.kdab.@PROJECT_NAME@.api.@KDDockWidgets_VERSION@
|
||||
|
||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
||||
# Help Project output. For more information please see Qt Help Project / Virtual
|
||||
@@ -1455,7 +1457,7 @@ QHP_NAMESPACE = com.kdab.KDDockWidgets.api.@KDDockWidgets_VERSION@
|
||||
# The default value is: doc.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_VIRTUAL_FOLDER = KDDockWidgets-@KDDockWidgets_VERSION@
|
||||
QHP_VIRTUAL_FOLDER = @PROJECT_NAME@-@KDDockWidgets_VERSION@
|
||||
|
||||
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
||||
# filter to add. For more information please see Qt Help Project / Custom
|
||||
@@ -1758,7 +1760,7 @@ LATEX_OUTPUT = latex
|
||||
# the output language.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_CMD_NAME =
|
||||
LATEX_CMD_NAME = latex
|
||||
|
||||
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
|
||||
# index for LaTeX.
|
||||
@@ -1795,7 +1797,7 @@ COMPACT_LATEX = NO
|
||||
# The default value is: a4.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
PAPER_TYPE = a4wide
|
||||
PAPER_TYPE = a4
|
||||
|
||||
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
|
||||
# that should be included in the LaTeX output. The package can be specified just
|
||||
@@ -1872,7 +1874,7 @@ PDF_HYPERLINKS = YES
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
USE_PDFLATEX = YES
|
||||
USE_PDFLATEX = NO
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep running
|
||||
@@ -2255,7 +2257,7 @@ TAGFILES = "@QDOC_TAG_DIR@/qtcore/qtcore.tags=https://doc.qt.io/qt
|
||||
# tag file that is based on the input files it reads. See section "Linking to
|
||||
# external documentation" for more information about the usage of tag files.
|
||||
|
||||
GENERATE_TAGFILE = kddockwidgets.tag
|
||||
GENERATE_TAGFILE = "@DOXYGEN_OUTPUT_DIR@/kddockwidgets.tags"
|
||||
|
||||
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
|
||||
# the class index. If set to NO, only the inherited external classes will be
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "MyFrameworkWidgetFactory.h"
|
||||
#include "MyTitleBar_CSS.h"
|
||||
|
||||
#include <kddockwidgets/FrameworkWidgetFactory.h>
|
||||
|
||||
@@ -89,11 +90,13 @@ MySeparator::~MySeparator() = default;
|
||||
|
||||
KDDockWidgets::TitleBar * CustomWidgetFactory::createTitleBar(KDDockWidgets::Frame *frame) const
|
||||
{
|
||||
// Feel free to return MyTitleBar_CSS here instead, but just for education purposes!
|
||||
return new MyTitleBar(frame);
|
||||
}
|
||||
|
||||
KDDockWidgets::TitleBar * CustomWidgetFactory::createTitleBar(KDDockWidgets::FloatingWindow *fw) const
|
||||
{
|
||||
// Feel free to return MyTitleBar_CSS here instead, but just for education purposes!
|
||||
return new MyTitleBar(fw);
|
||||
}
|
||||
|
||||
@@ -101,4 +104,3 @@ Layouting::Separator * CustomWidgetFactory::createSeparator(Layouting::Widget *p
|
||||
{
|
||||
return new MySeparator(parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,9 +56,9 @@ MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowO
|
||||
, m_dockwidget5DoesntCloseBeforeRestore(dockwidget5DoesntCloseBeforeRestore)
|
||||
{
|
||||
auto menubar = menuBar();
|
||||
auto fileMenu = new QMenu(QStringLiteral("File"));
|
||||
m_toggleMenu = new QMenu(QStringLiteral("Toggle"));
|
||||
auto miscMenu = new QMenu(QStringLiteral("Misc"));
|
||||
auto fileMenu = new QMenu(QStringLiteral("File"), this);
|
||||
m_toggleMenu = new QMenu(QStringLiteral("Toggle"), this);
|
||||
auto miscMenu = new QMenu(QStringLiteral("Misc"), this);
|
||||
|
||||
menubar->addMenu(fileMenu);
|
||||
menubar->addMenu(m_toggleMenu);
|
||||
@@ -115,6 +115,10 @@ MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowO
|
||||
|
||||
setAffinities({ affinityName });
|
||||
createDockWidgets();
|
||||
|
||||
if (options & KDDockWidgets::MainWindowOption_HasCentralWidget) {
|
||||
setPersistentCentralWidget(new MyWidget1());
|
||||
}
|
||||
}
|
||||
|
||||
MyMainWindow::~MyMainWindow()
|
||||
|
||||
86
examples/dockwidgets/MyTitleBar_CSS.h
Normal file
86
examples/dockwidgets/MyTitleBar_CSS.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
This file is part of KDDockWidgets.
|
||||
|
||||
SPDX-FileCopyrightText: 2019-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Author: Sérgio Martins <sergio.martins@kdab.com>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
*/
|
||||
|
||||
#ifndef EXAMPLETITLEBAR_CSS_H
|
||||
#define EXAMPLETITLEBAR_CSS_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <kddockwidgets/private/widgets/TitleBarWidget_p.h>
|
||||
|
||||
/**
|
||||
* @brief Shows how to implement a custom titlebar which uses "Qt StyleSheets".
|
||||
*
|
||||
* Derive from KDDockWidgets::DefaultWidgetFactory and override the two createTitleBar() methods.
|
||||
*
|
||||
* To try it out, modify examples/dockwidgets/MyFrameworkWidgetFactory.cpp to return a MyTitleBar_CSS instance.
|
||||
* Run the example with: ./bin/kddockwidgets_example -p
|
||||
*
|
||||
* WARNINGS:
|
||||
* - Qt StyleSheets are not recommended for new applications. Often you are able to style 90% of
|
||||
* the application but then hit a road block. QStyle is much more powerful and flexible.
|
||||
* - The Qt maintainers have manifested intention to deprecated stylesheets.
|
||||
* - Stylesheets are supported for built-in QWidgets (QPushButton, QComboBox, etc.), any widget
|
||||
* that's not in Qt needs to be crafted by the user, that includes, for example, having to paint
|
||||
* your background manually. KDDockWidget::TitleBarWidget does this for your convenience though.
|
||||
* - Qt stylesheets don't react to property changes (known old bug in Qt), for example:
|
||||
* QLineEdit[readOnly="true"] { color: gray }
|
||||
* this won't trigger when readOnly changes to false, you need to set/unset. This is QTBUG-51236
|
||||
* - KDDockWidgets::TitleBarWidget::isFocused is a property, there for needs to workaround the
|
||||
* above bug by unsetting the sheet and setting it again.
|
||||
*/
|
||||
class MyTitleBar_CSS : public KDDockWidgets::TitleBarWidget
|
||||
{
|
||||
public:
|
||||
explicit MyTitleBar_CSS(KDDockWidgets::Frame *frame)
|
||||
: KDDockWidgets::TitleBarWidget(frame)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
explicit MyTitleBar_CSS(KDDockWidgets::FloatingWindow *fw)
|
||||
: KDDockWidgets::TitleBarWidget(fw)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
~MyTitleBar_CSS() override;
|
||||
|
||||
void initStyleSheet()
|
||||
{
|
||||
// Or use qApp->setStyleSheet(), as you prefer
|
||||
setStyleSheet(QStringLiteral("KDDockWidgets--TitleBarWidget {"
|
||||
"background: blue"
|
||||
"}"
|
||||
"KDDockWidgets--TitleBarWidget:hover {"
|
||||
"background: red"
|
||||
"}"
|
||||
"KDDockWidgets--TitleBarWidget[isFocused=true] {"
|
||||
"background: green"
|
||||
"}"));
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
initStyleSheet();
|
||||
connect(this, &KDDockWidgets::TitleBar::isFocusedChanged, this, [this] {
|
||||
// Workaround QTBUG-51236, this makes the [isFocused=true] syntax useful
|
||||
setStyleSheet(QString());
|
||||
initStyleSheet();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
MyTitleBar_CSS::~MyTitleBar_CSS()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -120,9 +120,17 @@ int main(int argc, char **argv)
|
||||
parser.addOption(dontCloseBeforeRestore);
|
||||
|
||||
QCommandLineOption showButtonsInTabBarIfTitleBarHidden("show-buttons-in-tabbar-if-titlebar-hidden",
|
||||
QCoreApplication::translate("main", "If we're not using title bars we'll still show the close and float button in the tab bar"));
|
||||
QCoreApplication::translate("main", "If we're not using title bars we'll still show the close and float button in the tab bar"));
|
||||
parser.addOption(showButtonsInTabBarIfTitleBarHidden);
|
||||
|
||||
QCommandLineOption centralWidget("central-widget",
|
||||
QCoreApplication::translate("main", "The main window will have a non-detachable central widget"));
|
||||
parser.addOption(centralWidget);
|
||||
|
||||
QCommandLineOption ctxtMenuOnTabs("allow-switch-tabs-via-menu",
|
||||
QCoreApplication::translate("main", "Allow switching tabs via context menu in tabs area"));
|
||||
parser.addOption(ctxtMenuOnTabs);
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
parser.addOption(centralFrame);
|
||||
|
||||
@@ -164,6 +172,9 @@ int main(int argc, char **argv)
|
||||
options = parser.isSet(centralFrame) ? MainWindowOption_HasCentralFrame
|
||||
: MainWindowOption_None;
|
||||
|
||||
if (parser.isSet(centralWidget))
|
||||
options |= MainWindowOption_HasCentralWidget;
|
||||
|
||||
if (parser.isSet(noQtTool))
|
||||
internalFlags |= KDDockWidgets::Config::InternalFlag_DontUseQtToolWindowsForFloatingWindows;
|
||||
|
||||
@@ -230,6 +241,9 @@ int main(int argc, char **argv)
|
||||
if (parser.isSet(tabsHaveCloseButton))
|
||||
flags |= KDDockWidgets::Config::Flag_TabsHaveCloseButton;
|
||||
|
||||
if (parser.isSet(ctxtMenuOnTabs))
|
||||
flags |= KDDockWidgets::Config::Flag_AllowSwitchingTabsViaMenu;
|
||||
|
||||
|
||||
if (parser.isSet(doubleClickMaximize))
|
||||
flags |= KDDockWidgets::Config::Flag_DoubleClickMaximizes;
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
set(PYTHON_VERSION "3.7" CACHE STRING "Use specific python version to build the project.")
|
||||
find_package(Python3 ${PYTHON_VERSION} REQUIRED COMPONENTS Interpreter Development)
|
||||
set(PYTHON_BINDING_NAMESPACE "PyKDDockWidgets")
|
||||
|
||||
# Just to fix warnings with --warn-uninitialized
|
||||
if(NOT DEFINED SHIBOKEN_CUSTOM_PREFIX) #look for shiboken in a custom location
|
||||
@@ -21,15 +19,24 @@ if(NOT DEFINED PYSIDE_CUSTOM_PREFIX) #look for pyside in a custom location
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_QT6)
|
||||
find_package(Shiboken6 REQUIRED)
|
||||
find_package(PySide6 ${Qt6Widgets_VERSION} EXACT REQUIRED)
|
||||
include(PySide6ModuleBuild)
|
||||
set(PYSIDE_MAJOR_VERSION "6")
|
||||
set(PYTHON_BINDING_NAMESPACE "${PYTHON_BINDING_NAMESPACE}Qt${PYSIDE_MAJOR_VERSION}")
|
||||
set(QtWidgets_VERSION ${Qt6Widgets_VERSION})
|
||||
else()
|
||||
find_package(Shiboken2 REQUIRED)
|
||||
find_package(PySide2 ${Qt5Widgets_VERSION} EXACT REQUIRED)
|
||||
include(PySide2ModuleBuild)
|
||||
set(PYSIDE_MAJOR_VERSION "2")
|
||||
set(QtWidgets_VERSION ${Qt5Widgets_VERSION})
|
||||
endif()
|
||||
|
||||
find_package(Python3 3.7 REQUIRED COMPONENTS Interpreter Development)
|
||||
find_package(Shiboken${PYSIDE_MAJOR_VERSION} REQUIRED)
|
||||
find_package(PySide${PYSIDE_MAJOR_VERSION} ${QtWidgets_VERSION} EXACT REQUIRED)
|
||||
|
||||
if(NOT ${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX)
|
||||
set(${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
set(BINDINGS_DIR "${INSTALL_LIBRARY_DIR}/python${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}/site-packages/${PYTHON_BINDING_NAMESPACE}")
|
||||
set(${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX "${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/${BINDINGS_DIR}")
|
||||
|
||||
include(PySide${PYSIDE_MAJOR_VERSION}ModuleBuild)
|
||||
add_subdirectory(PyKDDockWidgets)
|
||||
add_subdirectory(tests)
|
||||
|
||||
@@ -48,9 +48,10 @@ set(PyKDDockWidgets_target_include_directories
|
||||
# Libraries that will be necessary to link the target, this will used in the command 'target_link_libraries'
|
||||
set(PyKDDockWidgets_target_link_libraries
|
||||
KDAB::kddockwidgets
|
||||
Qt${QT_MAJOR_VERSION}::Core
|
||||
Qt${QT_MAJOR_VERSION}::Gui
|
||||
Qt${QT_MAJOR_VERSION}::Widgets
|
||||
Qt${Qt_VERSION_MAJOR}::Core
|
||||
Qt${Qt_VERSION_MAJOR}::Gui
|
||||
Qt${Qt_VERSION_MAJOR}::Widgets
|
||||
${Python3_LIBRARIES}
|
||||
)
|
||||
|
||||
# changes on these files should trigger a new generation
|
||||
@@ -80,4 +81,19 @@ create_python_bindings(
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.cmake ${CMAKE_CURRENT_BINARY_DIR}/__init__.py @ONLY)
|
||||
|
||||
# install
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/__init__.py DESTINATION ${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}/PyKDDockWidgets)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/__init__.py
|
||||
$<TARGET_FILE:KDAB::kddockwidgets>
|
||||
DESTINATION
|
||||
${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}
|
||||
)
|
||||
if(NOT WIN32)
|
||||
install(
|
||||
FILES
|
||||
$<TARGET_LINKER_FILE:KDAB::kddockwidgets>
|
||||
$<TARGET_SONAME_FILE:KDAB::kddockwidgets>
|
||||
DESTINATION
|
||||
${${PROJECT_NAME}_PYTHON_BINDINGS_INSTALL_PREFIX}
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -10,9 +10,28 @@
|
||||
#
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
__all__ = ['KDDockWidgets']
|
||||
|
||||
def setupLibraryPath():
|
||||
if sys.platform != 'win32':
|
||||
return
|
||||
|
||||
from shiboken2 import shiboken2
|
||||
from PySide@PYSIDE_MAJOR_VERSION@ import QtCore
|
||||
|
||||
extra_dll_dirs = [ os.path.abspath(os.path.dirname(shiboken2.__file__)),
|
||||
os.path.abspath(os.path.dirname(QtCore.__file__)),
|
||||
os.path.abspath(os.path.dirname(__file__)) ]
|
||||
|
||||
if sys.version_info[0] == 3 and sys.version_info[1] >= 8:
|
||||
for dll_dir in extra_dll_dirs:
|
||||
os.add_dll_directory(dll_dir)
|
||||
|
||||
for dll_dir in extra_dll_dirs:
|
||||
os.environ['PATH'] = os.fspath(dll_dir) + os.pathsep + os.environ['PATH']
|
||||
|
||||
# Preload PySide libraries to avoid missing libraries while loading KDDockWidgets
|
||||
try:
|
||||
from PySide@PYSIDE_MAJOR_VERSION@ import QtCore
|
||||
@@ -22,3 +41,5 @@ try:
|
||||
except Exception:
|
||||
print("Failed to load PySide")
|
||||
raise
|
||||
|
||||
setupLibraryPath()
|
||||
|
||||
163
python/examples-qt6/MyMainWindow.py
Normal file
163
python/examples-qt6/MyMainWindow.py
Normal file
@@ -0,0 +1,163 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
from PyKDDockWidgetsQt6 import KDDockWidgets
|
||||
|
||||
from PySide6 import QtCore, QtWidgets, QtGui
|
||||
|
||||
from MyWidget1 import MyWidget1
|
||||
from MyWidget2 import MyWidget2
|
||||
from MyWidget3 import MyWidget3
|
||||
|
||||
def newMyWidget(parent = None):
|
||||
randomNumber = QtCore.QRandomGenerator.global_().bounded(0, 100) + 1
|
||||
if (randomNumber < 50):
|
||||
if (randomNumber < 33):
|
||||
return MyWidget1(parent)
|
||||
else:
|
||||
return MyWidget3(parent)
|
||||
else:
|
||||
return MyWidget2(parent)
|
||||
|
||||
class MyMainWindow(KDDockWidgets.MainWindow):
|
||||
s_count = 0
|
||||
s_menuCount = 0
|
||||
|
||||
def __init__(self, uniqueName, options = KDDockWidgets.MainWindowOption_None, dockWidget0IsNonClosable = False, nonDockableDockWidget9 = False, restoreIsRelative = False, maxSizeForDockWidget8 = False, affinityName = "", parent = None):
|
||||
super().__init__(uniqueName, options, parent)
|
||||
self.m_dockWidget0IsNonClosable = dockWidget0IsNonClosable
|
||||
self.m_dockWidget9IsNonDockable = nonDockableDockWidget9
|
||||
self.m_restoreIsRelative = restoreIsRelative
|
||||
self.m_maxSizeForDockWidget8 = maxSizeForDockWidget8
|
||||
self.m_dockwidgets = []
|
||||
|
||||
menubar = self.menuBar()
|
||||
fileMenu = QtWidgets.QMenu("File")
|
||||
self.m_toggleMenu = QtWidgets.QMenu("Toggle")
|
||||
menubar.addMenu(fileMenu)
|
||||
menubar.addMenu(self.m_toggleMenu)
|
||||
|
||||
newAction = fileMenu.addAction("New DockWidget")
|
||||
newAction.triggered.connect(self._newDockWidget)
|
||||
|
||||
saveLayoutAction = fileMenu.addAction("Save Layout")
|
||||
saveLayoutAction.triggered.connect(self._saveLayout)
|
||||
|
||||
restoreLayoutAction = fileMenu.addAction("Restore Layout")
|
||||
restoreLayoutAction.triggered.connect(self._restoreLayout)
|
||||
|
||||
closeAllAction = fileMenu.addAction("Close All")
|
||||
closeAllAction.triggered.connect(self._closeAll)
|
||||
|
||||
layoutEqually = fileMenu.addAction("Layout Equally")
|
||||
layoutEqually.triggered.connect(self.layoutEqually)
|
||||
|
||||
quitAction = fileMenu.addAction("Quit")
|
||||
quitAction.triggered.connect(QtWidgets.QApplication.instance().quit)
|
||||
|
||||
self.setAffinities([ affinityName ])
|
||||
self.createDockWidgets()
|
||||
|
||||
def _newDockWidget(self):
|
||||
MyMainWindow.s_menuCount += 1
|
||||
w = newMyWidget(self)
|
||||
w.setGeometry(100, 100, 400, 400)
|
||||
dock = KDDockWidgets.DockWidget("new dock %d"%(MyMainWindow.s_menuCount))
|
||||
dock.setWidget(w)
|
||||
dock.resize(600, 600)
|
||||
dock.show()
|
||||
self.m_dockwidgets.append(dock)
|
||||
|
||||
def _saveLayout(self):
|
||||
#saver = KDDockWidgets.LayoutSaver()
|
||||
#result = saver.saveToFile("mylayout.json")
|
||||
#print("Saving layout to disk. Result=", result)
|
||||
print("Not available")
|
||||
|
||||
def _restoreLayout(self):
|
||||
#options = KDDockWidgets.RestoreOption_None
|
||||
#if self.m_restoreIsRelative:
|
||||
# options |= KDDockWidgets.RestoreOption_RelativeToMainWindow
|
||||
#saver = KDDockWidgets.LayoutSaver(options)
|
||||
#saver.restoreFromFile("mylayout.json")
|
||||
print("Not available")
|
||||
|
||||
def _closeAll(self):
|
||||
for dw in self.m_dockwidgets:
|
||||
dw.close()
|
||||
|
||||
def createDockWidgets(self):
|
||||
if self.m_dockWidget9IsNonDockable:
|
||||
numDockWidgets = 10
|
||||
else:
|
||||
numDockWidgets = 9
|
||||
|
||||
# numDockWidgets = 2
|
||||
# Create 9 KDDockWidget::DockWidget and the respective widgets they're hosting (MyWidget instances)
|
||||
for i in range(numDockWidgets):
|
||||
self.m_dockwidgets.append(self.newDockWidget())
|
||||
|
||||
# MainWindow::addDockWidget() attaches a dock widget to the main window:
|
||||
initialOpts = KDDockWidgets.InitialOption(KDDockWidgets.InitialVisibilityOption.StartHidden, QtCore.QSize(500, 500))
|
||||
self.addDockWidget(self.m_dockwidgets[0], KDDockWidgets.Location_OnBottom, None, initialOpts)
|
||||
|
||||
# Here, for finer granularity we specify right of dockwidgets[0]:
|
||||
self.addDockWidget(self.m_dockwidgets[1], KDDockWidgets.Location_OnRight, self.m_dockwidgets[0])
|
||||
|
||||
self.addDockWidget(self.m_dockwidgets[2], KDDockWidgets.Location_OnLeft)
|
||||
self.addDockWidget(self.m_dockwidgets[3], KDDockWidgets.Location_OnBottom)
|
||||
self.addDockWidget(self.m_dockwidgets[4], KDDockWidgets.Location_OnBottom)
|
||||
|
||||
# Tab two dock widgets together
|
||||
self.m_dockwidgets[3].addDockWidgetAsTab(self.m_dockwidgets[5])
|
||||
|
||||
# 6 is floating, as it wasn't added to the main window via MainWindow::addDockWidget().
|
||||
# and we tab 7 with it.
|
||||
self.m_dockwidgets[6].addDockWidgetAsTab(self.m_dockwidgets[7])
|
||||
|
||||
# Floating windows also support nesting, here we add 8 to the bottom of the group
|
||||
self.m_dockwidgets[6].addDockWidgetToContainingWindow(self.m_dockwidgets[8], KDDockWidgets.Location_OnBottom)
|
||||
|
||||
floatingWindow = self.m_dockwidgets[6].window()
|
||||
floatingWindow.move(100, 100)
|
||||
|
||||
def newDockWidget(self):
|
||||
# Passing options is optional, we just want to illustrate Option_NotClosable here
|
||||
options = KDDockWidgets.DockWidget.Option_None
|
||||
if (MyMainWindow.s_count == 0) and self.m_dockWidget0IsNonClosable:
|
||||
options |= KDDockWidgets.DockWidget.Option_NotClosable
|
||||
|
||||
if (MyMainWindow.s_count == 9) and self.m_dockWidget9IsNonDockable:
|
||||
options |= KDDockWidgets.DockWidget.Option_NotDockable
|
||||
|
||||
dock = KDDockWidgets.DockWidget("DockWidget #%d"%(MyMainWindow.s_count), options)
|
||||
dock.setAffinities(self.affinities()); # optional, just to show the feature. Pass -mi to the example to see incompatible dock widgets
|
||||
|
||||
if MyMainWindow.s_count == 1:
|
||||
dock.setIcon(QtGui.QIcon.fromTheme("mail-message"))
|
||||
|
||||
myWidget = newMyWidget(self)
|
||||
if (MyMainWindow.s_count == 8) and self.m_maxSizeForDockWidget8:
|
||||
# Set a maximum size on dock #8
|
||||
myWidget.setMaximumSize(200, 200)
|
||||
|
||||
dock.setWidget(myWidget)
|
||||
|
||||
if dock.options() & KDDockWidgets.DockWidget.Option_NotDockable:
|
||||
dock.setTitle("DockWidget #%d (%s)" %(MyMainWindow.s_count, "non dockable"))
|
||||
else:
|
||||
dock.setTitle("DockWidget #%d"%(MyMainWindow.s_count))
|
||||
|
||||
dock.resize(600, 600)
|
||||
self.m_toggleMenu.addAction(dock.toggleAction())
|
||||
MyMainWindow.s_count += 1
|
||||
return dock
|
||||
|
||||
51
python/examples-qt6/MyWidget.py
Normal file
51
python/examples-qt6/MyWidget.py
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo Oliveira Filho <renato.araujo@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 PyKDDockWidgetsQt6
|
||||
|
||||
from PySide6 import QtWidgets, QtGui, QtCore
|
||||
|
||||
class MyWidget(QtWidgets.QWidget):
|
||||
s_images = {}
|
||||
def __init__(self, backgroundFile, logoFile, parent = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.m_background = self._lookupImage(backgroundFile)
|
||||
self.m_logo = self._lookupImage(logoFile)
|
||||
|
||||
def _lookupImage(self, imageName):
|
||||
if imageName == "":
|
||||
return None
|
||||
|
||||
if imageName not in MyWidget.s_images:
|
||||
MyWidget.s_images[imageName] = QtGui.QImage(imageName)
|
||||
|
||||
return MyWidget.s_images[imageName]
|
||||
|
||||
def drawLogo(self, p):
|
||||
|
||||
if not self.m_logo:
|
||||
return
|
||||
|
||||
ratio = self.m_logo.height() / (self.m_logo.width() * 1.0)
|
||||
maxWidth = int(0.80 * self.size().width())
|
||||
maxHeight = int(0.80 * self.size().height())
|
||||
proposedHeight = int(maxWidth * ratio)
|
||||
if (proposedHeight <= maxHeight):
|
||||
width = maxWidth
|
||||
else:
|
||||
width = int(maxHeight / ratio)
|
||||
|
||||
height = int(width * ratio)
|
||||
targetLogoRect = QtCore.QRect(0,0, width, height)
|
||||
targetLogoRect.moveCenter(self.rect().center() + QtCore.QPoint(0, -int(self.size().height() * 0.00)))
|
||||
p.drawImage(targetLogoRect, self.m_logo, self.m_logo.rect());
|
||||
|
||||
29
python/examples-qt6/MyWidget1.py
Normal file
29
python/examples-qt6/MyWidget1.py
Normal file
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo Oliveira Filho <renato.araujo@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 PyKDDockWidgetsQt6
|
||||
|
||||
from PySide6 import QtWidgets, QtGui
|
||||
|
||||
from MyWidget import MyWidget
|
||||
|
||||
|
||||
class MyWidget1(MyWidget):
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(":/assets/triangles.png", ":/assets/KDAB_bubble_white.png", parent)
|
||||
|
||||
|
||||
def paintEvent(self, ev):
|
||||
p = QtGui.QPainter(self)
|
||||
p.fillRect(self.rect(), QtGui.QColor(0xCC, 0xCC, 0xCC))
|
||||
p.drawImage(self.m_background.rect(), self.m_background, self.m_background.rect())
|
||||
self.drawLogo(p)
|
||||
|
||||
27
python/examples-qt6/MyWidget2.py
Normal file
27
python/examples-qt6/MyWidget2.py
Normal file
@@ -0,0 +1,27 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo Oliveira Filho <renato.araujo@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 PyKDDockWidgetsQt6
|
||||
|
||||
from PySide6 import QtWidgets, QtGui, QtCore
|
||||
|
||||
from MyWidget import MyWidget
|
||||
|
||||
class MyWidget2(MyWidget):
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super().__init__("", ":/assets/KDAB_bubble_blue.png", parent)
|
||||
|
||||
def paintEvent(self, ev):
|
||||
p = QtGui.QPainter(self)
|
||||
p.fillRect(self.rect(), QtCore.Qt.white);
|
||||
self.drawLogo(p)
|
||||
|
||||
32
python/examples-qt6/MyWidget3.py
Normal file
32
python/examples-qt6/MyWidget3.py
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo Oliveira Filho <renato.araujo@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 PyKDDockWidgetsQt6
|
||||
|
||||
from PySide6 import QtWidgets, QtGui, QtCore
|
||||
|
||||
from MyWidget import MyWidget
|
||||
|
||||
class MyWidget3(MyWidget):
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(":/assets/base.png", ":/assets/KDAB_bubble_fulcolor.png", parent)
|
||||
self.m_triangle = QtGui.QImage(":/assets/tri.png")
|
||||
|
||||
def paintEvent(self, ev):
|
||||
p = QtGui.QPainter(self)
|
||||
p.fillRect(self.rect(), QtGui.QColor(0xD5, 0xD5, 0xD5))
|
||||
p.drawImage(self.m_background.rect(), self.m_background, self.m_background.rect())
|
||||
|
||||
targetRect = QtCore.QRect(QtCore.QPoint(self.width() - self.m_triangle.width(), self.height() - self.m_triangle.height()), self.m_triangle.size())
|
||||
|
||||
self.drawLogo(p)
|
||||
|
||||
8
python/examples-qt6/README.txt
Normal file
8
python/examples-qt6/README.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Running python example
|
||||
======================
|
||||
|
||||
Generate resource file with:
|
||||
~# rcc -g python -o rc_assets.py ../../examples/dockwidgets/resources_example.qrc
|
||||
|
||||
Run the app:
|
||||
~# python3 main.py
|
||||
35
python/examples-qt6/main.py
Normal file
35
python/examples-qt6/main.py
Normal file
@@ -0,0 +1,35 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
from PyKDDockWidgetsQt6 import KDDockWidgets
|
||||
from MyMainWindow import MyMainWindow
|
||||
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
|
||||
import sys
|
||||
#import rc_assets
|
||||
|
||||
if __name__ == "__main__":
|
||||
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
|
||||
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
app.setOrganizationName("KDAB")
|
||||
app.setApplicationName("Test app")
|
||||
app.setStyle(QtWidgets.QStyleFactory.create("Fusion"))
|
||||
|
||||
mainWindow = MyMainWindow("MyMainWindow", )
|
||||
mainWindow.setWindowTitle("Main Window 1")
|
||||
mainWindow.resize(1200, 1200)
|
||||
mainWindow.show()
|
||||
|
||||
app.exec_()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
from PyKDDockWidgets import KDDockWidgets
|
||||
|
||||
from PySide import QtCore, QtWidgets, QtGui
|
||||
from PySide2 import QtCore, QtWidgets, QtGui
|
||||
|
||||
from MyWidget1 import MyWidget1
|
||||
from MyWidget2 import MyWidget2
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import PyKDDockWidgets
|
||||
|
||||
from PySide import QtWidgets, QtGui, QtCore
|
||||
from PySide2 import QtWidgets, QtGui, QtCore
|
||||
|
||||
class MyWidget(QtWidgets.QWidget):
|
||||
s_images = {}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import PyKDDockWidgets
|
||||
|
||||
from PySide import QtWidgets, QtGui
|
||||
from PySide2 import QtWidgets, QtGui
|
||||
|
||||
from MyWidget import MyWidget
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import PyKDDockWidgets
|
||||
|
||||
from PySide import QtWidgets, QtGui, QtCore
|
||||
from PySide2 import QtWidgets, QtGui, QtCore
|
||||
|
||||
from MyWidget import MyWidget
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import PyKDDockWidgets
|
||||
|
||||
from PySide import QtWidgets, QtGui, QtCore
|
||||
from PySide2 import QtWidgets, QtGui, QtCore
|
||||
|
||||
from MyWidget import MyWidget
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
from PyKDDockWidgets import KDDockWidgets
|
||||
from MyMainWindow import MyMainWindow
|
||||
|
||||
from PySide import QtWidgets, QtCore
|
||||
from PySide2 import QtWidgets, QtCore
|
||||
|
||||
import sys
|
||||
import rc_assets
|
||||
|
||||
40
python/tests/CMakeLists.txt
Normal file
40
python/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo Oliveira Filho <renato.araujo@kdab.com>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
||||
#
|
||||
# Contact KDAB at <info@kdab.com> for commercial licensing options.
|
||||
#
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.py.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.py @ONLY)
|
||||
|
||||
set(TEST_PYTHONPATH
|
||||
${CMAKE_BINARY_DIR}/python
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
set(TEST_LIBRARYPATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
|
||||
if(WIN32)
|
||||
set(TEST_LIBRARY_VAR "PATH")
|
||||
string(REPLACE "\\" "/" TEST_PYTHONPATH "${TEST_PYTHONPATH}")
|
||||
string(REPLACE "\\" "/" TEST_LIBRARYPATH "${TEST_LIBRARYPATH}")
|
||||
list(JOIN TEST_PYTHONPATH "\\;" TEST_PYTHONPATH)
|
||||
list(JOIN TEST_LIBRARYPATH "\\;" TEST_LIBRARYPATH)
|
||||
else()
|
||||
set(TEST_LIBRARY_VAR "LD_LIBRARY_PATH")
|
||||
list(JOIN TEST_PYTHONPATH ":" TEST_PYTHONPATH)
|
||||
list(JOIN TEST_LIBRARYPATH ":" TEST_LIBRARYPATH)
|
||||
endif()
|
||||
|
||||
set(PYTHON_ENV_COMMON "PYTHONPATH=${TEST_PYTHONPATH};${TEST_LIBRARY_VAR}=${TEST_LIBRARYPATH}")
|
||||
|
||||
file(GLOB TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tst_*.py)
|
||||
foreach(test_file ${TEST_FILES})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
add_test(${test_name} ${Python3_EXECUTABLE} ${test_file})
|
||||
set_tests_properties(${test_name} PROPERTIES ENVIRONMENT "${PYTHON_ENV_COMMON}")
|
||||
endforeach()
|
||||
|
||||
19
python/tests/config.py.cmake
Normal file
19
python/tests/config.py.cmake
Normal file
@@ -0,0 +1,19 @@
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo <renato.araujo@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 os
|
||||
import sys
|
||||
|
||||
class TstConfig(object):
|
||||
bindingsNamespace = "@PYTHON_BINDING_NAMESPACE@"
|
||||
|
||||
def initLibraryPath():
|
||||
if sys.platform == 'win32' and sys.version_info[0] == 3 and sys.version_info[1] >= 8:
|
||||
os.add_dll_directory("@CMAKE_RUNTIME_OUTPUT_DIRECTORY@")
|
||||
30
python/tests/tst_importModule.py
Normal file
30
python/tests/tst_importModule.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# This file is part of KDDockWidgets.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
# Author: Renato Araujo <renato.araujo@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 unittest
|
||||
import importlib
|
||||
import inspect
|
||||
|
||||
from config import TstConfig
|
||||
|
||||
class TestImportModules(unittest.TestCase):
|
||||
def test_importModules(self):
|
||||
m = importlib.import_module(TstConfig.bindingsNamespace + '.KDDockWidgets')
|
||||
moduleSymbols = []
|
||||
for t in inspect.getmembers(m):
|
||||
moduleSymbols.append(t[0])
|
||||
|
||||
symbols = ['MainWindow', 'DockWidget']
|
||||
for symbol in symbols:
|
||||
self.assertIn(symbol, moduleSymbols)
|
||||
|
||||
if __name__ == '__main__':
|
||||
TstConfig.initLibraryPath()
|
||||
unittest.main()
|
||||
@@ -245,9 +245,16 @@ add_library(KDAB::kddockwidgets ALIAS kddockwidgets)
|
||||
set_target_properties(kddockwidgets PROPERTIES OUTPUT_NAME "kddockwidgets${KDDockWidgets_LIBRARY_QTID}")
|
||||
set_compiler_flags(kddockwidgets)
|
||||
|
||||
if(${PROJECT_NAME}_QT6)
|
||||
set(DOCKS_INCLUDES_INSTALL_PATH "include/kddockwidgets-qt6")
|
||||
else()
|
||||
set(DOCKS_INCLUDES_INSTALL_PATH "include/")
|
||||
endif()
|
||||
|
||||
|
||||
target_include_directories(kddockwidgets
|
||||
PUBLIC
|
||||
$<INSTALL_INTERFACE:include>
|
||||
$<INSTALL_INTERFACE:${DOCKS_INCLUDES_INSTALL_PATH}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/fwd_headers>
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
@@ -287,16 +294,16 @@ if(CMAKE_COMPILER_IS_GNUCXX OR IS_CLANG_BUILD)
|
||||
endif()
|
||||
|
||||
if(${PROJECT_NAME}_QTQUICK)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${QT_MAJOR_VERSION}::Widgets Qt${QT_MAJOR_VERSION}::Quick Qt${QT_MAJOR_VERSION}::QuickControls2)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${Qt_VERSION_MAJOR}::Widgets Qt${Qt_VERSION_MAJOR}::Quick Qt${Qt_VERSION_MAJOR}::QuickControls2)
|
||||
else()
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${QT_MAJOR_VERSION}::Widgets)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${Qt_VERSION_MAJOR}::Widgets PRIVATE Qt${Qt_VERSION_MAJOR}::WidgetsPrivate)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(kddockwidgets PRIVATE Qt${QT_MAJOR_VERSION}::GuiPrivate dwmapi)
|
||||
elseif(NOT APPLE AND NOT EMSCRIPTEN AND NOT ${PROJECT_NAME}_QT6)
|
||||
find_package(Qt${QT_MAJOR_VERSION}X11Extras)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${QT_MAJOR_VERSION}::X11Extras)
|
||||
target_link_libraries(kddockwidgets PRIVATE Qt${Qt_VERSION_MAJOR}::GuiPrivate dwmapi)
|
||||
elseif(NOT APPLE AND NOT EMSCRIPTEN AND NOT ${PROJECT_NAME}_QT6 AND ${PROJECT_NAME}_X11EXTRAS)
|
||||
find_package(Qt${Qt_VERSION_MAJOR}X11Extras)
|
||||
target_link_libraries(kddockwidgets PUBLIC Qt${Qt_VERSION_MAJOR}::X11Extras)
|
||||
endif()
|
||||
|
||||
set_target_properties(kddockwidgets PROPERTIES
|
||||
@@ -331,23 +338,23 @@ if(MSVC AND NOT ${PROJECT_NAME}_STATIC)
|
||||
install(FILES "$<TARGET_PDB_FILE_DIR:kddockwidgets>/$<TARGET_PDB_FILE_NAME:kddockwidgets>" DESTINATION ${INSTALL_LIBRARY_DIR} CONFIGURATIONS Debug RelWithDebInfo)
|
||||
endif()
|
||||
|
||||
install(FILES ${camelcase_HEADERS} DESTINATION include/kddockwidgets)
|
||||
install(FILES ${DOCKS_INSTALLABLE_INCLUDES} DESTINATION include/kddockwidgets)
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_INCLUDES} DESTINATION include/kddockwidgets/private)
|
||||
install(FILES private/multisplitter/Item_p.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Widget.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Separator_p.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/indicators/ClassicIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
|
||||
install(FILES private/indicators/SegmentedIndicators_p.h DESTINATION include/kddockwidgets/private/indicators)
|
||||
install(FILES ${camelcase_HEADERS} DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets)
|
||||
install(FILES ${DOCKS_INSTALLABLE_INCLUDES} DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets)
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_INCLUDES} DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private)
|
||||
install(FILES private/multisplitter/Item_p.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Widget.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Separator_p.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/indicators/ClassicIndicators_p.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/indicators)
|
||||
install(FILES private/indicators/SegmentedIndicators_p.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/indicators)
|
||||
|
||||
if(KDDockWidgets_QTQUICK)
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_QUICK_INCLUDES} DESTINATION include/kddockwidgets/private/quick)
|
||||
install(FILES private/multisplitter/Separator_quick.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Widget_quick.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_QUICK_INCLUDES} DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/quick)
|
||||
install(FILES private/multisplitter/Separator_quick.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Widget_quick.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/multisplitter)
|
||||
else()
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES} DESTINATION include/kddockwidgets/private/widgets)
|
||||
install(FILES private/multisplitter/Separator_qwidget.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Widget_qwidget.h DESTINATION include/kddockwidgets/private/multisplitter)
|
||||
install(FILES ${DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES} DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/widgets)
|
||||
install(FILES private/multisplitter/Separator_qwidget.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/multisplitter)
|
||||
install(FILES private/multisplitter/Widget_qwidget.h DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets/private/multisplitter)
|
||||
endif()
|
||||
|
||||
# Generate library version files
|
||||
@@ -356,21 +363,21 @@ ecm_setup_version(
|
||||
${${PROJECT_NAME}_VERSION}
|
||||
VARIABLE_PREFIX KDDOCKWIDGETS
|
||||
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kddockwidgets_version.h"
|
||||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgetsConfigVersion.cmake"
|
||||
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets${KDDockWidgets_LIBRARY_QTID}ConfigVersion.cmake"
|
||||
SOVERSION ${${PROJECT_NAME}_SOVERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kddockwidgets_version.h" DESTINATION include/kddockwidgets)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kddockwidgets_version.h" DESTINATION ${DOCKS_INCLUDES_INSTALL_PATH}/kddockwidgets)
|
||||
|
||||
install(EXPORT kddockwidgetsTargets
|
||||
FILE KDDockWidgetsTargets.cmake
|
||||
FILE KDDockWidgets${KDDockWidgets_LIBRARY_QTID}Targets.cmake
|
||||
NAMESPACE KDAB::
|
||||
DESTINATION ${INSTALL_LIBRARY_DIR}/cmake/KDDockWidgets
|
||||
DESTINATION ${INSTALL_LIBRARY_DIR}/cmake/KDDockWidgets${KDDockWidgets_LIBRARY_QTID}
|
||||
)
|
||||
configure_file(KDDockWidgetsConfig.cmake.in KDDockWidgetsConfig.cmake @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgetsConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgetsConfigVersion.cmake"
|
||||
DESTINATION ${INSTALL_LIBRARY_DIR}/cmake/KDDockWidgets
|
||||
configure_file(KDDockWidgetsConfig.cmake.in KDDockWidgets${KDDockWidgets_LIBRARY_QTID}Config.cmake @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets${KDDockWidgets_LIBRARY_QTID}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets${KDDockWidgets_LIBRARY_QTID}ConfigVersion.cmake"
|
||||
DESTINATION ${INSTALL_LIBRARY_DIR}/cmake/KDDockWidgets${KDDockWidgets_LIBRARY_QTID}
|
||||
)
|
||||
|
||||
if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
@@ -381,7 +388,7 @@ if(${PROJECT_NAME}_DEVELOPER_MODE)
|
||||
|
||||
if(NOT ${PROJECT_NAME}_QTQUICK AND KDDockWidgets_LINTER) # TODO: We can support it
|
||||
add_executable(kddockwidgets_linter layoutlinter_main.cpp)
|
||||
target_link_libraries(kddockwidgets_linter kddockwidgets Qt${QT_MAJOR_VERSION}::Widgets)
|
||||
target_link_libraries(kddockwidgets_linter kddockwidgets Qt${Qt_VERSION_MAJOR}::Widgets)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
Flag_KeepAboveIfNotUtilityWindow = 0x10000, ///< Only meaningful if Flag_DontUseUtilityFloatingWindows is set. If floating windows are normal windows, you might still want them to keep above and not minimize when you focus the main window.
|
||||
Flag_CloseOnlyCurrentTab = 0x20000, ///< The TitleBar's close button will only close the current tab, instead of all of them
|
||||
Flag_ShowButtonsOnTabBarIfTitleBarHidden = 0x40000, ///< When using Flag_HideTitleBarWhenTabsVisible the close/float buttons disappear with the title bar. With Flag_ShowButtonsOnTabBarIfHidden they'll be shown in the tab bar.
|
||||
Flag_AllowSwitchingTabsViaMenu = 0x80000, ///< Allow switching tabs via a context menu when right clicking on the tab area
|
||||
Flag_Default = Flag_AeroSnapWithClientDecos ///< The defaults
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
||||
@@ -83,6 +83,13 @@ void DockWidgetBase::addDockWidgetAsTab(DockWidgetBase *other, InitialOption opt
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPersistentCentralDockWidget()) {
|
||||
qWarning() << Q_FUNC_INFO << "Not supported with MainWindowOption_HasCentralWidget."
|
||||
<< "MainWindowOption_HasCentralWidget can only have 1 widget in the center."
|
||||
<< "Use MainWindowOption_HasCentralFrame instead, which is similar but supports tabbing.";
|
||||
return;
|
||||
}
|
||||
|
||||
Frame *frame = d->frame();
|
||||
|
||||
if (frame) {
|
||||
@@ -182,6 +189,9 @@ bool DockWidgetBase::setFloating(bool floats)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (floats && isPersistentCentralDockWidget())
|
||||
return false;
|
||||
|
||||
if (floats) {
|
||||
d->saveTabIndex();
|
||||
if (isTabbed()) {
|
||||
@@ -620,6 +630,9 @@ void DockWidgetBase::Private::close()
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_isPersistentCentralDockWidget)
|
||||
return;
|
||||
|
||||
// If it's overlayed and we're closing, we need to close the overlay
|
||||
if (SideBar *sb = DockRegistry::self()->sideBarForDockWidget(q)) {
|
||||
auto mainWindow = sb->mainWindow();
|
||||
@@ -837,6 +850,11 @@ void DockWidgetBase::setMDIZ(int z)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DockWidgetBase::isPersistentCentralDockWidget() const
|
||||
{
|
||||
return d->m_isPersistentCentralDockWidget;
|
||||
}
|
||||
|
||||
LayoutSaver::DockWidget::Ptr DockWidgetBase::Private::serialize() const
|
||||
{
|
||||
auto ptr = LayoutSaver::DockWidget::dockWidgetForName(q->uniqueName());
|
||||
|
||||
@@ -450,6 +450,10 @@ public:
|
||||
/// only implemented for QtQuick
|
||||
void setMDIZ(int z);
|
||||
|
||||
///@brief Returns whether this dock widget is the main window persistent central widget
|
||||
///This only applies when using MainWindowOption_HasCentralWidget
|
||||
bool isPersistentCentralDockWidget() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
///@brief signal emitted when the parent changed
|
||||
|
||||
@@ -55,7 +55,9 @@ enum MainWindowOption
|
||||
{
|
||||
MainWindowOption_None = 0, ///> No option set
|
||||
MainWindowOption_HasCentralFrame = 1, ///> Makes the MainWindow always have a central frame, for tabbing documents
|
||||
MainWindowOption_MDI = 2 ///> EXPERIMENTAL!!1 The layout will be MDI. DockWidgets can have arbitrary positions, not restricted by any layout
|
||||
MainWindowOption_MDI = 2, ///> The layout will be MDI. DockWidgets can have arbitrary positions, not restricted by any layout
|
||||
MainWindowOption_HasCentralWidget = 4 | MainWindowOption_HasCentralFrame, ///> Similar to MainWindowOption_HasCentralFrame but
|
||||
///> you'll have a central widget which can't be detached (Similar to regular QMainWindow).
|
||||
};
|
||||
Q_DECLARE_FLAGS(MainWindowOptions, MainWindowOption)
|
||||
Q_ENUM_NS(MainWindowOptions)
|
||||
@@ -258,7 +260,8 @@ enum FrameOption
|
||||
FrameOption_None = 0,
|
||||
FrameOption_AlwaysShowsTabs = 1,
|
||||
FrameOption_IsCentralFrame = 2,
|
||||
FrameOption_IsOverlayed = 4
|
||||
FrameOption_IsOverlayed = 4,
|
||||
FrameOption_NonDockable = 8 ///> You can't DND and tab things into this Frame
|
||||
};
|
||||
Q_DECLARE_FLAGS(FrameOptions, FrameOption)
|
||||
Q_ENUM_NS(FrameOptions)
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(Qt5Widgets REQUIRED)
|
||||
find_dependency(Qt@Qt_VERSION_MAJOR@Widgets REQUIRED)
|
||||
if (@KDDockWidgets_QTQUICK@)
|
||||
find_dependency(Qt5Quick REQUIRED)
|
||||
find_dependency(Qt@Qt_VERSION_MAJOR@Quick REQUIRED)
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN)
|
||||
if (NOT WIN32 AND NOT APPLE AND NOT EMSCRIPTEN AND NOT @KDDockWidgets_QT6@)
|
||||
find_dependency(Qt5X11Extras REQUIRED)
|
||||
endif()
|
||||
|
||||
# Add the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/KDDockWidgetsTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/KDDockWidgets@KDDockWidgets_LIBRARY_QTID@Targets.cmake")
|
||||
|
||||
@@ -608,11 +608,6 @@ bool LayoutSaver::Frame::isValid() const
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options > 3) {
|
||||
qWarning() << Q_FUNC_INFO << "Invalid options" << options;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dockWidgets.isEmpty()) {
|
||||
if (currentTabIndex >= dockWidgets.size() || currentTabIndex < 0) {
|
||||
qWarning() << Q_FUNC_INFO << "Invalid tab index" << currentTabIndex << dockWidgets.size();
|
||||
@@ -657,7 +652,7 @@ QVariantMap LayoutSaver::Frame::toVariantMap() const
|
||||
map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry));
|
||||
map.insert(QStringLiteral("options"), options);
|
||||
map.insert(QStringLiteral("currentTabIndex"), currentTabIndex);
|
||||
|
||||
map.insert(QStringLiteral("mainWindowUniqueName"), mainWindowUniqueName);
|
||||
map.insert(QStringLiteral("dockWidgets"), dockWidgetNames(dockWidgets));
|
||||
|
||||
return map;
|
||||
@@ -674,6 +669,7 @@ void LayoutSaver::Frame::fromVariantMap(const QVariantMap &map)
|
||||
id = map.value(QStringLiteral("id")).toString();
|
||||
isNull = map.value(QStringLiteral("isNull")).toBool();
|
||||
objectName = map.value(QStringLiteral("objectName")).toString();
|
||||
mainWindowUniqueName = map.value(QStringLiteral("mainWindowUniqueName")).toString();
|
||||
geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap());
|
||||
options = static_cast<QFlags<FrameOption>::Int>(map.value(QStringLiteral("options")).toUInt());
|
||||
currentTabIndex = map.value(QStringLiteral("currentTabIndex")).toInt();
|
||||
@@ -770,9 +766,11 @@ QVariantMap LayoutSaver::FloatingWindow::toVariantMap() const
|
||||
map.insert(QStringLiteral("multiSplitterLayout"), multiSplitterLayout.toVariantMap());
|
||||
map.insert(QStringLiteral("parentIndex"), parentIndex);
|
||||
map.insert(QStringLiteral("geometry"), Layouting::rectToMap(geometry));
|
||||
map.insert(QStringLiteral("normalGeometry"), Layouting::rectToMap(normalGeometry));
|
||||
map.insert(QStringLiteral("screenIndex"), screenIndex);
|
||||
map.insert(QStringLiteral("screenSize"), Layouting::sizeToMap(screenSize));
|
||||
map.insert(QStringLiteral("isVisible"), isVisible);
|
||||
map.insert(QStringLiteral("windowState"), windowState);
|
||||
|
||||
if (!affinities.isEmpty())
|
||||
map.insert(QStringLiteral("affinities"), stringListToVariant(affinities));
|
||||
@@ -785,10 +783,12 @@ void LayoutSaver::FloatingWindow::fromVariantMap(const QVariantMap &map)
|
||||
multiSplitterLayout.fromVariantMap(map.value(QStringLiteral("multiSplitterLayout")).toMap());
|
||||
parentIndex = map.value(QStringLiteral("parentIndex")).toInt();
|
||||
geometry = Layouting::mapToRect(map.value(QStringLiteral("geometry")).toMap());
|
||||
normalGeometry = Layouting::mapToRect(map.value(QStringLiteral("normalGeometry")).toMap());
|
||||
screenIndex = map.value(QStringLiteral("screenIndex")).toInt();
|
||||
screenSize = Layouting::mapToSize(map.value(QStringLiteral("screenSize")).toMap());
|
||||
isVisible = map.value(QStringLiteral("isVisible")).toBool();
|
||||
affinities = variantToStringList(map.value(QStringLiteral("affinities")).toList());
|
||||
windowState = Qt::WindowState(map.value(QStringLiteral("windowState"), Qt::WindowNoState).toInt());
|
||||
|
||||
// Compatibility hack. Old json format had a single "affinityName" instead of an "affinities" list:
|
||||
const QString affinityName = map.value(QStringLiteral("affinityName")).toString();
|
||||
@@ -802,11 +802,6 @@ bool LayoutSaver::MainWindow::isValid() const
|
||||
if (!multiSplitterLayout.isValid())
|
||||
return false;
|
||||
|
||||
if (options != MainWindowOption_None && options != MainWindowOption_HasCentralFrame) {
|
||||
qWarning() << Q_FUNC_INFO << "Invalid option" << options;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,13 @@
|
||||
#include "private/LayoutSaver_p.h"
|
||||
#include "private/DockWidgetBase_p.h"
|
||||
|
||||
// Or we can have a createDockWidget() in the factory
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
# include "DockWidgetQuick.h"
|
||||
#else
|
||||
# include "DockWidget.h"
|
||||
#endif
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
static LayoutWidget *createLayoutWidget(MainWindowBase *mainWindow, MainWindowOptions options)
|
||||
@@ -44,10 +51,11 @@ static LayoutWidget *createLayoutWidget(MainWindowBase *mainWindow, MainWindowOp
|
||||
class MainWindowBase::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(MainWindowBase *mainWindow, MainWindowOptions options)
|
||||
explicit Private(MainWindowBase *mainWindow, const QString &uniqueName, MainWindowOptions options)
|
||||
: m_options(options)
|
||||
, q(mainWindow)
|
||||
, m_layoutWidget(createLayoutWidget(mainWindow, options))
|
||||
, m_persistentCentralDockWidget(createPersistentCentralDockWidget(uniqueName))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,6 +64,38 @@ public:
|
||||
return m_options & MainWindowOption_HasCentralFrame;
|
||||
}
|
||||
|
||||
bool supportsPersistentCentralWidget() const
|
||||
{
|
||||
if (!dropArea()) {
|
||||
// This is the MDI case
|
||||
return false;
|
||||
}
|
||||
|
||||
return (m_options & MainWindowOption_HasCentralWidget) == MainWindowOption_HasCentralWidget;
|
||||
}
|
||||
|
||||
DockWidgetBase* createPersistentCentralDockWidget(const QString &uniqueName) const
|
||||
{
|
||||
if (!supportsPersistentCentralWidget())
|
||||
return nullptr;
|
||||
|
||||
auto dw = new DockWidgetType(QStringLiteral("%1-persistentCentralDockWidget").arg(uniqueName));
|
||||
dw->dptr()->m_isPersistentCentralDockWidget = true;
|
||||
Frame *frame = dropArea()->m_centralFrame;
|
||||
if (!frame) {
|
||||
qWarning() << Q_FUNC_INFO << "Expected central frame";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
frame->addWidget(dw);
|
||||
return dw;
|
||||
}
|
||||
|
||||
DropAreaWithCentralFrame *dropArea() const
|
||||
{
|
||||
return qobject_cast<DropAreaWithCentralFrame *>(m_layoutWidget);
|
||||
}
|
||||
|
||||
CursorPositions allowedResizeSides(SideBarLocation loc) const;
|
||||
|
||||
QRect rectForOverlay(Frame *, SideBarLocation) const;
|
||||
@@ -69,12 +109,13 @@ public:
|
||||
MainWindowBase *const q;
|
||||
QPointer<DockWidgetBase> m_overlayedDockWidget;
|
||||
LayoutWidget *const m_layoutWidget;
|
||||
DockWidgetBase *const m_persistentCentralDockWidget;
|
||||
};
|
||||
|
||||
MainWindowBase::MainWindowBase(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
|
||||
WidgetType *parent, Qt::WindowFlags flags)
|
||||
: QMainWindowOrQuick(parent, flags)
|
||||
, d(new Private(this, options))
|
||||
, d(new Private(this, uniqueName, options))
|
||||
{
|
||||
setUniqueName(uniqueName);
|
||||
|
||||
@@ -109,7 +150,11 @@ void MainWindowBase::addDockWidgetAsTab(DockWidgetBase *widget)
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->supportsCentralFrame()) {
|
||||
if (d->supportsPersistentCentralWidget()) {
|
||||
qWarning() << Q_FUNC_INFO << "Not supported with MainWindowOption_HasCentralWidget."
|
||||
<< "MainWindowOption_HasCentralWidget can only have 1 widget in the center."
|
||||
<< "Use MainWindowOption_HasCentralFrame instead, which is similar but supports tabbing";
|
||||
} else if (d->supportsCentralFrame()) {
|
||||
dropArea()->m_centralFrame->addWidget(widget);
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Not supported without MainWindowOption_HasCentralFrame";
|
||||
@@ -327,7 +372,7 @@ SideBarLocation MainWindowBase::Private::preferredSideBar(DockWidgetBase *dw) co
|
||||
}
|
||||
|
||||
const Layouting::LayoutBorderLocations borders = item->adjacentLayoutBorders();
|
||||
const qreal aspectRatio = dw->width() / (dw->height() * 1.0);
|
||||
const qreal aspectRatio = dw->width() / (std::max(1, dw->height()) * 1.0);
|
||||
|
||||
/// 1. It's touching all borders
|
||||
if (borders == Layouting::LayoutBorderLocation_All) {
|
||||
@@ -450,6 +495,9 @@ void MainWindowBase::moveToSideBar(DockWidgetBase *dw)
|
||||
|
||||
void MainWindowBase::moveToSideBar(DockWidgetBase *dw, SideBarLocation location)
|
||||
{
|
||||
if (dw->isPersistentCentralDockWidget())
|
||||
return;
|
||||
|
||||
if (SideBar *sb = sideBar(location)) {
|
||||
QScopedValueRollback<bool> rollback(dw->d->m_isMovingToSideBar, true);
|
||||
dw->forceClose();
|
||||
@@ -479,7 +527,7 @@ void MainWindowBase::restoreFromSideBar(DockWidgetBase *dw)
|
||||
|
||||
void MainWindowBase::overlayOnSideBar(DockWidgetBase *dw)
|
||||
{
|
||||
if (!dw)
|
||||
if (!dw || dw->isPersistentCentralDockWidget())
|
||||
return;
|
||||
|
||||
const SideBar *sb = sideBarForDockWidget(dw);
|
||||
@@ -718,3 +766,26 @@ QRect MainWindowBase::windowGeometry() const
|
||||
|
||||
return window()->geometry();
|
||||
}
|
||||
|
||||
void MainWindowBase::setPersistentCentralWidget(QWidgetOrQuick *widget)
|
||||
{
|
||||
if (!d->supportsPersistentCentralWidget()) {
|
||||
qWarning() << "MainWindow::setPersistentCentralWidget() requires MainWindowOption_HasCentralWidget";
|
||||
return;
|
||||
}
|
||||
|
||||
auto dw = d->m_persistentCentralDockWidget;
|
||||
if (dw) {
|
||||
dw->setWidget(widget);
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected null central dock widget";
|
||||
}
|
||||
}
|
||||
|
||||
QWidgetOrQuick *MainWindowBase::persistentCentralWidget() const
|
||||
{
|
||||
if (auto dw = d->m_persistentCentralDockWidget)
|
||||
return dw->widget();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,21 @@ public:
|
||||
KDDockWidgets::DockWidgetBase *relativeTo = nullptr,
|
||||
KDDockWidgets::InitialOption initialOption = {});
|
||||
|
||||
/**
|
||||
* @brief Sets a persistent central widget. It can't be detached.
|
||||
*
|
||||
* Requires passing MainWindowOption_HasCentralWidget in the CTOR.
|
||||
* This is similar to the central frame concept of MainWindowOption_HasCentralFrame,
|
||||
* with the difference that it won't show a tabs.
|
||||
*
|
||||
* @param widget The QWidget (or QQuickItem if built with QtQuick support) that you
|
||||
* want to set.
|
||||
*
|
||||
* Example: kddockwidgets_example --central-widget
|
||||
*/
|
||||
Q_INVOKABLE void setPersistentCentralWidget(QWidgetOrQuick *widget);
|
||||
QWidgetOrQuick *persistentCentralWidget() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the unique name that was passed via constructor.
|
||||
* Used internally by the save/restore mechanism.
|
||||
|
||||
@@ -148,6 +148,7 @@ public:
|
||||
QAction *const toggleAction;
|
||||
QAction *const floatAction;
|
||||
LastPositions m_lastPositions;
|
||||
bool m_isPersistentCentralDockWidget = false;
|
||||
bool m_processingToggleAction = false;
|
||||
bool m_updatingToggleAction = false;
|
||||
bool m_updatingFloatAction = false;
|
||||
|
||||
@@ -31,7 +31,16 @@ Frame *DropAreaWithCentralFrame::createCentralFrame(MainWindowOptions options)
|
||||
{
|
||||
Frame *frame = nullptr;
|
||||
if (options & MainWindowOption_HasCentralFrame) {
|
||||
frame = Config::self().frameworkWidgetFactory()->createFrame(nullptr, FrameOptions() | FrameOption_IsCentralFrame | FrameOption_AlwaysShowsTabs);
|
||||
FrameOptions frameOptions = FrameOption_IsCentralFrame;
|
||||
const bool hasPersistentCentralWidget = (options & MainWindowOption_HasCentralWidget) == MainWindowOption_HasCentralWidget;
|
||||
if (hasPersistentCentralWidget) {
|
||||
frameOptions |= FrameOption_NonDockable;
|
||||
} else {
|
||||
// With a persistent central widget we don't allow detaching it
|
||||
frameOptions |= FrameOption_AlwaysShowsTabs;
|
||||
}
|
||||
|
||||
frame = Config::self().frameworkWidgetFactory()->createFrame(nullptr, frameOptions);
|
||||
frame->setObjectName(QStringLiteral("central frame"));
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
|
||||
private:
|
||||
friend class MainWindowBase;
|
||||
friend class Frame;
|
||||
Frame *const m_centralFrame = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -369,6 +369,18 @@ void FloatingWindow::onVisibleFrameCountChanged(int count)
|
||||
setVisible(count > 0);
|
||||
}
|
||||
|
||||
Qt::WindowState FloatingWindow::windowStateOverride() const
|
||||
{
|
||||
Qt::WindowState state = Qt::WindowNoState;
|
||||
|
||||
if (isMaximizedOverride())
|
||||
state = Qt::WindowMaximized;
|
||||
else if (isMinimizedOverride())
|
||||
state = Qt::WindowMinimized;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void FloatingWindow::updateTitleBarVisibility()
|
||||
{
|
||||
if (m_updatingTitleBarVisibility)
|
||||
@@ -446,7 +458,21 @@ bool FloatingWindow::deserialize(const LayoutSaver::FloatingWindow &fw)
|
||||
{
|
||||
if (dropArea()->deserialize(fw.multiSplitterLayout)) {
|
||||
updateTitleBarVisibility();
|
||||
show();
|
||||
|
||||
if (fw.normalGeometry.isValid() && !isNormalWindowState(fw.windowState)) {
|
||||
// Restore QWidgetPrivate's normalGeometry (no public API in QWidget)
|
||||
setNormalGeometry(fw.normalGeometry);
|
||||
}
|
||||
|
||||
// And show it:
|
||||
if (fw.windowState & Qt::WindowMaximized) {
|
||||
showMaximized();
|
||||
} else if (fw.windowState & Qt::WindowMinimized) {
|
||||
showMinimized();
|
||||
} else {
|
||||
showNormal();
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -458,11 +484,13 @@ LayoutSaver::FloatingWindow FloatingWindow::serialize() const
|
||||
LayoutSaver::FloatingWindow fw;
|
||||
|
||||
fw.geometry = geometry();
|
||||
fw.normalGeometry = normalGeometry();
|
||||
fw.isVisible = isVisible();
|
||||
fw.multiSplitterLayout = dropArea()->serialize();
|
||||
fw.screenIndex = screenNumberForWidget(this);
|
||||
fw.screenSize = screenSizeForWidget(this);
|
||||
fw.affinities = affinities();
|
||||
fw.windowState = windowStateOverride();
|
||||
|
||||
auto mainWindow = qobject_cast<MainWindowBase *>(parentWidget());
|
||||
fw.parentIndex = mainWindow ? DockRegistry::self()->mainwindows().indexOf(mainWindow)
|
||||
@@ -559,6 +587,36 @@ QMargins FloatingWindow::contentMargins() const
|
||||
return { 4, 4, 4, 4 };
|
||||
}
|
||||
|
||||
bool FloatingWindow::isMaximizedOverride() const
|
||||
{
|
||||
return QWidgetAdapter::isMaximized();
|
||||
}
|
||||
|
||||
bool FloatingWindow::isMinimizedOverride() const
|
||||
{
|
||||
return QWidgetAdapter::isMinimized();
|
||||
}
|
||||
|
||||
void FloatingWindow::showMaximized()
|
||||
{
|
||||
QWidgetAdapter::showMaximized();
|
||||
}
|
||||
|
||||
void FloatingWindow::showNormal()
|
||||
{
|
||||
QWidgetAdapter::showNormal();
|
||||
}
|
||||
|
||||
void FloatingWindow::showMinimized()
|
||||
{
|
||||
QWidgetAdapter::showMinimized();
|
||||
}
|
||||
|
||||
QRect FloatingWindow::normalGeometry() const
|
||||
{
|
||||
return QWidgetAdapter::normalGeometry();
|
||||
}
|
||||
|
||||
int FloatingWindow::userType() const
|
||||
{
|
||||
if (Frame *f = singleFrame())
|
||||
|
||||
@@ -176,6 +176,40 @@ public:
|
||||
///@brief Returns the contents margins
|
||||
QMargins contentMargins() const;
|
||||
|
||||
///@brief Allows the user to override QWindow::isMaximized()
|
||||
/// Needed to workaround window managers that don't support maximizing/minimizing Qt::Tool windows.
|
||||
/// By default this just calls QWindow::isMaximized()
|
||||
/// @sa QTBUG-95478
|
||||
virtual bool isMaximizedOverride() const;
|
||||
|
||||
///@brief Allows the user to override QWindow::isMinimized()
|
||||
/// Needed to workaround window managers that don't support maximizing/minimizing Qt::Tool windows.
|
||||
/// By default this just calls QWindow::isMinimized()
|
||||
/// @sa QTBUG-95478
|
||||
virtual bool isMinimizedOverride() const;
|
||||
|
||||
///@brief By default equivalent to QWindow::showMaximized()
|
||||
/// But allows the user to override it and workaround exotic window manager bugs
|
||||
/// @sa QTBUG-95478
|
||||
virtual void showMaximized();
|
||||
|
||||
///@brief By default equivalent to QWindow::showNormal()
|
||||
/// But allows the user to override it and workaround exotic window manager bugs
|
||||
/// @sa QTBUG-95478
|
||||
virtual void showNormal();
|
||||
|
||||
///@brief By default equivalent to QWindow::showMinimized()
|
||||
/// But allows the user to override it and workaround exotic window manager bugs
|
||||
/// @sa QTBUG-95478
|
||||
virtual void showMinimized();
|
||||
|
||||
///@brief By default equivalent to QWidget::normalGeometry()
|
||||
/// Derived classes can implement something different here, to workaround window manager issues with Qt::Tool
|
||||
/// Also useful for QtQuick to eventually preserve normal geometry upon save/restore of a maximized window. As
|
||||
/// QWindow has no notion of normal geometry, so we need to implement it here.
|
||||
/// @sa QTBUG-95478
|
||||
virtual QRect normalGeometry() const;
|
||||
|
||||
///@brief Allows the user app to specify which window flags to use, instead of KDDWs default ones
|
||||
///Bugs caused by this won't be supported, as the amount of combinations that could go wrong can
|
||||
///be open ended
|
||||
@@ -211,6 +245,7 @@ private:
|
||||
bool m_updatingTitleBarVisibility = false;
|
||||
QMetaObject::Connection m_layoutDestroyedConnection;
|
||||
QAbstractNativeEventFilter *m_nchittestFilter = nullptr;
|
||||
Qt::WindowState windowStateOverride() const;
|
||||
#ifdef Q_OS_WIN
|
||||
int m_lastHitTest = 0;
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Utils_p.h"
|
||||
#include "WidgetResizeHandler_p.h"
|
||||
#include "MDILayoutWidget_p.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QTimer>
|
||||
@@ -147,7 +148,8 @@ void Frame::insertWidget(DockWidgetBase *dockWidget, int index, InitialOption ad
|
||||
{
|
||||
Q_ASSERT(dockWidget);
|
||||
if (containsDockWidget(dockWidget)) {
|
||||
qWarning() << "Frame::addWidget dockWidget already exists. this=" << this << "; dockWidget=" << dockWidget;
|
||||
if (!dockWidget->isPersistentCentralDockWidget())
|
||||
qWarning() << "Frame::addWidget dockWidget already exists. this=" << this << "; dockWidget=" << dockWidget;
|
||||
return;
|
||||
}
|
||||
if (m_layoutItem)
|
||||
@@ -652,7 +654,37 @@ Frame *Frame::deserialize(const LayoutSaver::Frame &f)
|
||||
if (!f.isValid())
|
||||
return nullptr;
|
||||
|
||||
auto frame = Config::self().frameworkWidgetFactory()->createFrame(/*parent=*/nullptr, FrameOptions(f.options));
|
||||
const FrameOptions options = FrameOptions(f.options);
|
||||
Frame *frame = nullptr;
|
||||
const bool isPersistentCentralFrame = options & FrameOption::FrameOption_IsCentralFrame;
|
||||
auto widgetFactory = Config::self().frameworkWidgetFactory();
|
||||
|
||||
if (isPersistentCentralFrame) {
|
||||
// Don't create a new Frame if we're restoring the Persistent Central frame (the one created
|
||||
// by MainWindowOption_HasCentralFrame). It already exists.
|
||||
|
||||
if (f.mainWindowUniqueName.isEmpty()) {
|
||||
// Can happen with older serialization formats
|
||||
qWarning() << Q_FUNC_INFO << "Frame is the persistent central frame but doesn't have"
|
||||
<< "an associated window name";
|
||||
} else {
|
||||
if (MainWindowBase *mw = DockRegistry::self()->mainWindowByName(f.mainWindowUniqueName)) {
|
||||
frame = mw->dropArea()->m_centralFrame;
|
||||
if (!frame) {
|
||||
// Doesn't happen...
|
||||
qWarning() << "Main window" << f.mainWindowUniqueName << "doesn't have central frame";
|
||||
}
|
||||
} else {
|
||||
// Doesn't happen...
|
||||
qWarning() << Q_FUNC_INFO << "Couldn't find main window"
|
||||
<< f.mainWindowUniqueName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!frame)
|
||||
frame = widgetFactory->createFrame(/*parent=*/nullptr, options);
|
||||
|
||||
frame->setObjectName(f.objectName);
|
||||
|
||||
for (const auto &savedDock : qAsConst(f.dockWidgets)) {
|
||||
@@ -680,6 +712,9 @@ LayoutSaver::Frame Frame::serialize() const
|
||||
frame.currentTabIndex = currentTabIndex();
|
||||
frame.id = id(); // for coorelation purposes
|
||||
|
||||
if (MainWindowBase *mw = mainWindow())
|
||||
frame.mainWindowUniqueName = mw->uniqueName();
|
||||
|
||||
for (DockWidgetBase *dock : docks)
|
||||
frame.dockWidgets.push_back(dock->d->serialize());
|
||||
|
||||
|
||||
@@ -166,6 +166,12 @@ public:
|
||||
return m_options & FrameOption_IsCentralFrame;
|
||||
}
|
||||
|
||||
/// @brief Returns whether you can DND dock widgets over this frame and tab into it
|
||||
bool isDockable() const
|
||||
{
|
||||
return !(m_options & FrameOption_NonDockable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief whether the tab widget will always show tabs, even if there's only 1 dock widget
|
||||
*
|
||||
|
||||
@@ -212,6 +212,10 @@ struct LayoutSaver::Frame
|
||||
int currentTabIndex;
|
||||
QString id; // for coorelation purposes
|
||||
|
||||
/// Might be empty if not in a main window. Used so we don't create a frame when restoring
|
||||
/// the persistent central frame, that's never deleted when restoring
|
||||
QString mainWindowUniqueName;
|
||||
|
||||
LayoutSaver::DockWidget::List dockWidgets;
|
||||
};
|
||||
|
||||
@@ -250,12 +254,14 @@ struct LayoutSaver::FloatingWindow
|
||||
QStringList affinities;
|
||||
int parentIndex = -1;
|
||||
QRect geometry;
|
||||
QRect normalGeometry;
|
||||
int screenIndex;
|
||||
QSize screenSize; // for relative-size restoring
|
||||
bool isVisible = true;
|
||||
|
||||
// The instance that was created during a restore:
|
||||
KDDockWidgets::FloatingWindow *floatingWindowInstance = nullptr;
|
||||
Qt::WindowState windowState = Qt::WindowNoState;
|
||||
};
|
||||
|
||||
struct LayoutSaver::MainWindow
|
||||
|
||||
@@ -130,7 +130,7 @@ void TitleBar::toggleMaximized()
|
||||
if (!m_floatingWindow)
|
||||
return;
|
||||
|
||||
if (m_floatingWindow->isMaximized())
|
||||
if (m_floatingWindow->isMaximizedOverride())
|
||||
m_floatingWindow->showNormal();
|
||||
else
|
||||
m_floatingWindow->showMaximized();
|
||||
|
||||
@@ -43,6 +43,7 @@ class DOCKS_EXPORT TitleBar : public QWidgetAdapter, public Draggable
|
||||
Q_PROPERTY(bool closeButtonEnabled READ closeButtonEnabled WRITE setCloseButtonEnabled NOTIFY closeButtonEnabledChanged)
|
||||
Q_PROPERTY(bool floatButtonVisible READ floatButtonVisible WRITE setFloatButtonVisible NOTIFY floatButtonVisibleChanged)
|
||||
Q_PROPERTY(QString floatButtonToolTip READ floatButtonToolTip NOTIFY floatButtonToolTipChanged)
|
||||
Q_PROPERTY(bool isFocused READ isFocused NOTIFY isFocusedChanged)
|
||||
public:
|
||||
typedef QVector<TitleBar *> List;
|
||||
|
||||
|
||||
@@ -110,6 +110,11 @@ inline bool usesUtilityWindows()
|
||||
return !dontUse;
|
||||
}
|
||||
|
||||
inline bool isNormalWindowState(Qt::WindowStates states)
|
||||
{
|
||||
return !(states & Qt::WindowMaximized) && !(states & Qt::WindowFullScreen);
|
||||
}
|
||||
|
||||
inline bool usesFallbackMouseGrabber()
|
||||
{
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
|
||||
@@ -108,7 +108,7 @@ void ClassicIndicators::updateIndicatorsVisibility(bool visible)
|
||||
|
||||
// Only allow to dock to center if the affinities match
|
||||
auto tabbingAllowedFunc = Config::self().tabbingAllowedFunc();
|
||||
m_tabIndicatorVisible = m_innerIndicatorsVisible && windowBeingDragged && DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities());
|
||||
m_tabIndicatorVisible = m_innerIndicatorsVisible && windowBeingDragged && DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities()) && m_hoveredFrame->isDockable();
|
||||
if (m_tabIndicatorVisible && tabbingAllowedFunc) {
|
||||
const DockWidgetBase::List source = windowBeingDragged->dockWidgets();
|
||||
const DockWidgetBase::List target = m_hoveredFrame->dockWidgets();
|
||||
|
||||
@@ -257,7 +257,6 @@ QSize QWidgetAdapter::minimumSize() const
|
||||
|
||||
QSize QWidgetAdapter::maximumSize() const
|
||||
{
|
||||
|
||||
if (m_isWrapper) {
|
||||
const auto children = childItems();
|
||||
if (!children.isEmpty()) {
|
||||
@@ -299,6 +298,27 @@ QRect QWidgetAdapter::geometry() const
|
||||
return KDDockWidgets::Private::geometry(this);
|
||||
}
|
||||
|
||||
QRect QWidgetAdapter::normalGeometry() const
|
||||
{
|
||||
// TODO: There's no such concept in QWindow, do we need to workaround for QtQuick ?
|
||||
return QWidgetAdapter::geometry();
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setNormalGeometry(QRect geo)
|
||||
{
|
||||
if (!isTopLevel())
|
||||
return;
|
||||
|
||||
if (QWindow *w = windowHandle()) {
|
||||
if (isNormalWindowState(w->windowStates())) {
|
||||
w->setGeometry(geo);
|
||||
} else {
|
||||
// Nothing better at this point, as QWindow doesn't have this concept
|
||||
qDebug() << Q_FUNC_INFO << "TODO";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QRect QWidgetAdapter::rect() const
|
||||
{
|
||||
return QRectF(0, 0, width(), height()).toRect();
|
||||
@@ -418,6 +438,14 @@ bool QWidgetAdapter::isMaximized() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QWidgetAdapter::isMinimized() const
|
||||
{
|
||||
if (QWindow *w = windowHandle())
|
||||
return w->windowStates() & Qt::WindowMinimized;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KDDockWidgets::QWidgetAdapter::isActiveWindow() const
|
||||
{
|
||||
if (QWindow *w = windowHandle())
|
||||
|
||||
@@ -122,6 +122,8 @@ public:
|
||||
virtual void setGeometry(QRect);
|
||||
QRect frameGeometry() const;
|
||||
QRect geometry() const;
|
||||
QRect normalGeometry() const;
|
||||
void setNormalGeometry(QRect);
|
||||
QRect rect() const;
|
||||
QPoint pos() const;
|
||||
void show();
|
||||
@@ -184,6 +186,7 @@ public:
|
||||
return isWindow();
|
||||
}
|
||||
bool isMaximized() const;
|
||||
bool isMinimized() const;
|
||||
bool isActiveWindow() const;
|
||||
Q_INVOKABLE void showMaximized();
|
||||
Q_INVOKABLE void showMinimized();
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QWindow>
|
||||
|
||||
#include <QtWidgets/private/qwidget_p.h>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
QWidgetAdapter::QWidgetAdapter(QWidget *parent, Qt::WindowFlags f)
|
||||
@@ -129,4 +131,18 @@ QWidget *KDDockWidgets::Private::widgetForWindow(QWindow *window)
|
||||
return window->property("kddockwidgets_qwidget").value<QWidget *>();
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setNormalGeometry(QRect geo)
|
||||
{
|
||||
if (isNormalWindowState(windowState())) {
|
||||
setGeometry(geo);
|
||||
} else {
|
||||
QWidgetPrivate *priv = QWidgetPrivate::get(this);
|
||||
if (priv->extra && priv->extra->topextra) {
|
||||
priv->topData()->normalGeometry = geo;
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Failing to set normal geometry";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LayoutGuestWidget::~LayoutGuestWidget() = default;
|
||||
|
||||
@@ -103,6 +103,7 @@ protected:
|
||||
void mouseMoveEvent(QMouseEvent *) override;
|
||||
void mouseReleaseEvent(QMouseEvent *) override;
|
||||
void closeEvent(QCloseEvent *) override;
|
||||
virtual void setNormalGeometry(QRect);
|
||||
|
||||
virtual bool onResize(QSize newSize);
|
||||
virtual void onLayoutRequest();
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <QTabBar>
|
||||
#include <QHBoxLayout>
|
||||
#include <QAbstractButton>
|
||||
#include <QMenu>
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
@@ -38,6 +39,9 @@ TabWidgetWidget::TabWidgetWidget(Frame *parent)
|
||||
setTabBar(static_cast<QTabBar *>(m_tabBar->asWidget()));
|
||||
setTabsClosable(Config::self().flags() & Config::Flag_TabsHaveCloseButton);
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, &QTabWidget::customContextMenuRequested, this, &TabWidgetWidget::showContextMenu);
|
||||
|
||||
// In case tabs closable is set by the factory, a tabClosedRequested() is emitted when the user presses [x]
|
||||
connect(this, &QTabWidget::tabCloseRequested, this, [this](int index) {
|
||||
if (DockWidgetBase *dw = dockwidgetAt(index)) {
|
||||
@@ -201,3 +205,34 @@ void TabWidgetWidget::updateMargins()
|
||||
m_cornerWidgetLayout->setContentsMargins(QMargins(0, 0, 2, 0) * factor);
|
||||
m_cornerWidgetLayout->setSpacing(int(2 * factor));
|
||||
}
|
||||
|
||||
void TabWidgetWidget::showContextMenu(QPoint pos)
|
||||
{
|
||||
if (!(Config::self().flags() & Config::Flag_AllowSwitchingTabsViaMenu))
|
||||
return;
|
||||
|
||||
QTabBar *tabBar = QTabWidget::tabBar();
|
||||
// We don't want context menu if there is only one tab
|
||||
if (tabBar->count() <= 1)
|
||||
return;
|
||||
|
||||
// Click on a tab => No menu
|
||||
if (tabBar->tabAt(pos) >= 0)
|
||||
return;
|
||||
|
||||
// Right click is allowed only on the tabs area
|
||||
QRect tabAreaRect = tabBar->rect();
|
||||
tabAreaRect.setWidth(this->width());
|
||||
if (!tabAreaRect.contains(pos))
|
||||
return;
|
||||
|
||||
QMenu menu(this);
|
||||
for (int i = 0; i < tabBar->count(); ++i) {
|
||||
QAction *action = menu.addAction(tabText(i), this, [this, i] {
|
||||
setCurrentIndex(i);
|
||||
});
|
||||
if (i == currentIndex())
|
||||
action->setDisabled(true);
|
||||
}
|
||||
menu.exec(mapToGlobal(pos));
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ protected:
|
||||
DockWidgetBase *dockwidgetAt(int index) const override;
|
||||
int currentIndex() const override;
|
||||
|
||||
/// @brief Shows the context menu. Override to implement your own context menu.
|
||||
/// By default it's used to honour Config::Flag_AllowSwitchingTabsViaMenu
|
||||
virtual void showContextMenu(QPoint pos);
|
||||
|
||||
private:
|
||||
void updateMargins();
|
||||
void setupTabBarButtons();
|
||||
|
||||
@@ -236,6 +236,8 @@ void TitleBarWidget::paintEvent(QPaintEvent *)
|
||||
QPainter p(this);
|
||||
|
||||
QStyleOptionDockWidget titleOpt;
|
||||
titleOpt.initFrom(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &titleOpt, &p, this);
|
||||
titleOpt.title = title();
|
||||
titleOpt.rect = iconRect().isEmpty() ? rect().adjusted(2, 0, -buttonAreaWidth(), 0)
|
||||
: rect().adjusted(iconRect().right(), 0, -buttonAreaWidth(), 0);
|
||||
@@ -275,12 +277,12 @@ void TitleBarWidget::updateMaximizeButton()
|
||||
{
|
||||
if (auto fw = floatingWindow()) {
|
||||
auto factory = Config::self().frameworkWidgetFactory();
|
||||
const TitleBarButtonType iconType = fw->isMaximized() ? TitleBarButtonType::Normal
|
||||
: TitleBarButtonType::Maximize;
|
||||
const TitleBarButtonType iconType = fw->isMaximizedOverride() ? TitleBarButtonType::Normal
|
||||
: TitleBarButtonType::Maximize;
|
||||
m_maximizeButton->setIcon(factory->iconForButtonType(iconType, devicePixelRatioF()));
|
||||
|
||||
m_maximizeButton->setVisible(supportsMaximizeButton());
|
||||
m_maximizeButton->setToolTip(fw->isMaximized() ? tr("Restore") : tr("Maximize"));
|
||||
m_maximizeButton->setToolTip(fw->isMaximizedOverride() ? tr("Restore") : tr("Maximize"));
|
||||
} else {
|
||||
m_maximizeButton->setVisible(false);
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ option(KDDockWidgets_FUZZER "Builds the fuzzer" ON)
|
||||
# tst_docks
|
||||
set(TESTING_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_resources.qrc)
|
||||
add_executable(tst_docks tst_docks.cpp ${TESTING_SRCS} ${TESTING_RESOURCES})
|
||||
target_link_libraries(tst_docks kddockwidgets Qt${QT_MAJOR_VERSION}::Test)
|
||||
target_link_libraries(tst_docks kddockwidgets Qt${Qt_VERSION_MAJOR}::Test)
|
||||
set_compiler_flags(tst_docks)
|
||||
|
||||
if(NOT ${PROJECT_NAME}_QTQUICK)
|
||||
add_executable(tst_multisplitter tst_multisplitter.cpp)
|
||||
target_link_libraries(tst_multisplitter kddockwidgets Qt${QT_MAJOR_VERSION}::Test)
|
||||
target_link_libraries(tst_multisplitter kddockwidgets Qt${Qt_VERSION_MAJOR}::Test)
|
||||
set_compiler_flags(tst_multisplitter)
|
||||
if(KDDockWidgets_FUZZER)
|
||||
add_subdirectory(fuzzer)
|
||||
@@ -47,4 +47,4 @@ endif()
|
||||
|
||||
# tests_launcher
|
||||
add_executable(tests_launcher tests_launcher.cpp)
|
||||
target_link_libraries(tests_launcher Qt${QT_MAJOR_VERSION}::Core)
|
||||
target_link_libraries(tests_launcher Qt${Qt_VERSION_MAJOR}::Core)
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
add_executable(fuzzer main.cpp Fuzzer.cpp Operations.cpp ../Testing.cpp)
|
||||
|
||||
set_property(TARGET fuzzer PROPERTY CXX_STANDARD 17)
|
||||
target_link_libraries(fuzzer kddockwidgets Qt${QT_MAJOR_VERSION}::Widgets Qt${QT_MAJOR_VERSION}::Test)
|
||||
target_link_libraries(fuzzer kddockwidgets Qt${Qt_VERSION_MAJOR}::Widgets Qt${Qt_VERSION_MAJOR}::Test)
|
||||
set_compiler_flags(fuzzer)
|
||||
|
||||
@@ -27,9 +27,9 @@ using namespace KDDockWidgets;
|
||||
using namespace KDDockWidgets::Testing;
|
||||
using namespace KDDockWidgets::Testing::Operations;
|
||||
|
||||
static QString operationTypeStr(OperationType ot)
|
||||
static QString operationTypeStr(OperationType optype)
|
||||
{
|
||||
return QMetaEnum::fromType<OperationType>().valueToKey(ot);
|
||||
return QMetaEnum::fromType<OperationType>().valueToKey(optype);
|
||||
}
|
||||
|
||||
OperationBase::OperationBase(KDDockWidgets::Testing::Operations::OperationType type, Fuzzer *fuzzer)
|
||||
|
||||
@@ -619,6 +619,43 @@ void TestDocks::tst_restoreMaximizedState()
|
||||
QCOMPARE(m->windowHandle()->windowState(), Qt::WindowMaximized);
|
||||
}
|
||||
|
||||
void TestDocks::tst_restoreFloatingMaximizedState()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_TitleBarHasMaximizeButton);
|
||||
auto dock1 = createDockWidget("dock1", new MyWidget("one"));
|
||||
const QRect originalNormalGeometry = dock1->floatingWindow()->normalGeometry();
|
||||
dock1->floatingWindow()->showMaximized();
|
||||
qDebug() << originalNormalGeometry;
|
||||
|
||||
QCOMPARE(dock1->floatingWindow()->windowHandle()->windowState(), Qt::WindowMaximized);
|
||||
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
|
||||
saver.restoreLayout(saved);
|
||||
QCOMPARE(dock1->floatingWindow()->windowHandle()->windowState(), Qt::WindowMaximized);
|
||||
QCOMPARE(dock1->floatingWindow()->normalGeometry(), originalNormalGeometry);
|
||||
|
||||
dock1->floatingWindow()->showNormal();
|
||||
QCOMPARE(dock1->floatingWindow()->normalGeometry(), originalNormalGeometry);
|
||||
}
|
||||
|
||||
void TestDocks::tst_restoreFloatingMinimizedState()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto dock1 = createDockWidget("dock1", new MyWidget("one"));
|
||||
dock1->floatingWindow()->showMinimized();
|
||||
|
||||
QCOMPARE(dock1->floatingWindow()->windowHandle()->windowState(), Qt::WindowMinimized);
|
||||
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
|
||||
saver.restoreLayout(saved);
|
||||
QCOMPARE(dock1->floatingWindow()->windowHandle()->windowState(), Qt::WindowMinimized);
|
||||
}
|
||||
|
||||
void TestDocks::tst_setFloatingSimple()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
@@ -3709,6 +3746,23 @@ void TestDocks::tst_restoreSideBySide()
|
||||
}
|
||||
}
|
||||
|
||||
void TestDocks::tst_restoreWithCentralFrameWithTabs()
|
||||
{
|
||||
auto m = createMainWindow(QSize(500, 500), MainWindowOption_HasCentralFrame, "tst_restoreTwice");
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
||||
auto dock2 = createDockWidget("2", new QPushButton("2"));
|
||||
m->addDockWidgetAsTab(dock1);
|
||||
m->addDockWidgetAsTab(dock2);
|
||||
|
||||
QCOMPARE(DockRegistry::self()->frames().size(), 1);
|
||||
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
QVERIFY(saver.restoreLayout(saved));
|
||||
|
||||
QCOMPARE(DockRegistry::self()->frames().size(), 1);
|
||||
}
|
||||
|
||||
void TestDocks::tst_restoreWithPlaceholder()
|
||||
{
|
||||
// Float dock1, save and restore, then unfloat and see if dock2 goes back to where it was
|
||||
@@ -5083,6 +5137,7 @@ void TestDocks::tst_restoreSideBar()
|
||||
|
||||
serialized = saver.serializeLayout();
|
||||
|
||||
m1.reset();
|
||||
delete fw1;
|
||||
}
|
||||
|
||||
@@ -5199,6 +5254,7 @@ void TestDocks::tst_sidebarOverlayGetsHiddenOnClick()
|
||||
Tests::clickOn(widget2->mapToGlobal(widget2->rect().bottomLeft() + QPoint(5, -5)), widget2);
|
||||
QVERIFY(!dw1->isOverlayed());
|
||||
|
||||
m1.reset();
|
||||
delete dw1;
|
||||
}
|
||||
|
||||
@@ -5218,8 +5274,6 @@ void TestDocks::tst_sidebarOverlayGetsHiddenOnClick()
|
||||
const QPoint localPt(100, 250);
|
||||
Tests::clickOn(m1->mapToGlobal(m1->rect().topLeft() + localPt), m1->childAt(localPt));
|
||||
QVERIFY(!dw1->isOverlayed());
|
||||
|
||||
delete dw1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7322,3 +7376,25 @@ void TestDocks::tst_closeTabOfCentralFrame()
|
||||
dock1->close();
|
||||
QVERIFY(frame->QWidgetAdapter::isVisible());
|
||||
}
|
||||
|
||||
void TestDocks::tst_persistentCentralWidget()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(500, 500), MainWindowOption_HasCentralWidget);
|
||||
auto dockwidgets = m->dropArea()->dockWidgets();
|
||||
QCOMPARE(dockwidgets.size(), 1);
|
||||
|
||||
auto dw = dockwidgets.constFirst();
|
||||
dw->close();
|
||||
QVERIFY(dw->isOpen());
|
||||
QVERIFY(dw->isPersistentCentralDockWidget());
|
||||
dw->setFloating(true);
|
||||
QVERIFY(!dw->isFloating());
|
||||
|
||||
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
QVERIFY(!saved.isEmpty());
|
||||
|
||||
QVERIFY(saver.restoreLayout(saved));
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ private Q_SLOTS:
|
||||
void tst_restoreEmpty();
|
||||
void tst_restoreCentralFrame();
|
||||
void tst_restoreMaximizedState();
|
||||
void tst_restoreFloatingMaximizedState();
|
||||
void tst_restoreFloatingMinimizedState();
|
||||
void tst_shutdown();
|
||||
void tst_closeDockWidgets();
|
||||
void tst_layoutEqually();
|
||||
@@ -104,6 +106,7 @@ private Q_SLOTS:
|
||||
void tst_restoreNestedAndTabbed();
|
||||
void tst_restoreCrash();
|
||||
void tst_restoreSideBySide();
|
||||
void tst_restoreWithCentralFrameWithTabs();
|
||||
void tst_restoreWithPlaceholder();
|
||||
void tst_restoreWithAffinity();
|
||||
void tst_marginsAfterRestore();
|
||||
@@ -238,6 +241,7 @@ private Q_SLOTS:
|
||||
|
||||
void tst_addMDIDockWidget();
|
||||
void tst_redockToMDIRestoresPosition();
|
||||
void tst_persistentCentralWidget();
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTWIDGETS
|
||||
// TODO: Port these to QtQuick
|
||||
|
||||
Reference in New Issue
Block a user