commit 14a6b7756872e3719fd400b70c4f460e60aed9df
Author: duanshengchao <519970194@qq.com>
Date: Thu Oct 10 16:59:51 2024 +0800
第一次提交
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..0c38d0a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,143 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(PowerMaster VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
+find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
+
+set(ADS_VERSION 4.3.1)
+add_subdirectory(QtADS)
+
+#默认ui文件要和.h头文件在一个目录,若不在一个目录,需要指定其所在目录
+set(CMAKE_AUTOUIC_SEARCH_PATHS "ui")
+
+set(H_HEADER_FILES
+ include/global.h
+ include/mainWindow.h
+ include/customBorderContainer.h
+ include/customMenu.h
+ include/functionNavigationBar.h
+ include/dvieMainWindow.h
+ include/tccMainWindow.h
+ include/tccToolBox.h
+ include/transparentMask.h
+ include/messageDialog.h
+ include/dashboard.h
+ include/dashboardNamingDialog.h
+ include/dataPanel.h
+ include/panelSelectionDialog.h
+ include/panelConfigurationWidget.h
+ include/dateTimeWidget.h
+ include/customCalendarWidget.h
+ include/dateTimeSelectionPanel.h
+)
+
+set(CPP_SOURCE_FILES
+ source/global.cpp
+ source/main.cpp
+ source/mainWindow.cpp
+ source/customBorderContainer.cpp
+ source/customMenu.cpp
+ source/functionNavigationBar.cpp
+ source/dvieMainWindow.cpp
+ source/tccMainWindow.cpp
+ source/tccToolBox.cpp
+ source/transparentMask.cpp
+ source/messageDialog.cpp
+ source/dashboard.cpp
+ source/dashboardNamingDialog.cpp
+ source/dataPanel.cpp
+ source/panelSelectionDialog.cpp
+ source/panelConfigurationWidget.cpp
+ source/dateTimeWidget.cpp
+ source/customCalendarWidget.cpp
+ source/dateTimeSelectionPanel.cpp
+)
+
+set(UI_FILES
+ ui/mainWindow.ui
+ ui/functionNavigationBar.ui
+ ui/dvieMainWindow.ui
+ ui/tccToolBox.ui
+ ui/transparentMask.ui
+ ui/messageDialog.ui
+ ui/dashboardNamingDialog.ui
+ ui/panelSelectionDialog.ui
+ ui/panelConfigurationWidget.ui
+ ui/panelToolWidget.ui
+ ui/dateTimeWidget.ui
+ ui/dateTimeSelectionPanel.ui
+)
+
+# 包含源文件目录
+INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})
+
+if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
+ qt_add_executable(PowerMaster
+ MANUAL_FINALIZATION
+ ${H_HEADER_FILES}
+ ${CPP_SOURCE_FILES}
+ ${UI_FILES}
+ resource/PowerMaster.qrc
+ )
+# Define target properties for Android with Qt 6 as:
+# set_property(TARGET PowerMaster APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
+# ${CMAKE_CURRENT_SOURCE_DIR}/android)
+# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
+else()
+ if(ANDROID)
+ add_library(PowerMaster SHARED
+ ${H_HEADER_FILES}
+ ${CPP_SOURCE_FILES}
+ ${UI_FILES}
+ resource/PowerMaster.qrc
+ )
+# Define properties for Android with Qt 5 after find_package() calls as:
+# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
+ else()
+ add_executable(PowerMaster
+ ${H_HEADER_FILES}
+ ${CPP_SOURCE_FILES}
+ ${UI_FILES}
+ resource/PowerMaster.qrc
+ )
+ endif()
+endif()
+
+target_include_directories(PowerMaster PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
+target_link_libraries(PowerMaster PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(PowerMaster PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+
+# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
+# If you are developing for iOS or macOS you should consider setting an
+# explicit, fixed bundle identifier manually though.
+if(${QT_VERSION} VERSION_LESS 6.1.0)
+ set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.PowerMaster)
+endif()
+set_target_properties(PowerMaster PROPERTIES
+ ${BUNDLE_ID_OPTION}
+ MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
+ MACOSX_BUNDLE TRUE
+ WIN32_EXECUTABLE TRUE
+)
+
+include(GNUInstallDirs)
+install(TARGETS PowerMaster
+ BUNDLE DESTINATION .
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
+
+if(QT_VERSION_MAJOR EQUAL 6)
+ qt_finalize_executable(PowerMaster)
+endif()
diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user
new file mode 100644
index 0000000..0119730
--- /dev/null
+++ b/CMakeLists.txt.user
@@ -0,0 +1,899 @@
+
+
+
+
+
+ EnvironmentId
+ {fc4d1d3a-7b80-444f-b9ff-f47f1a79a8f5}
+
+
+ ProjectExplorer.Project.ActiveTarget
+ 0
+
+
+ ProjectExplorer.Project.EditorSettings
+
+ true
+ false
+ true
+
+ Cpp
+
+ CppGlobal
+
+
+
+ QmlJS
+
+ QmlJSGlobal
+
+
+ 2
+ UTF-8
+ false
+ 4
+ false
+ 80
+ true
+ true
+ 1
+ 0
+ false
+ true
+ false
+ 2
+ true
+ true
+ 0
+ 8
+ true
+ false
+ 1
+ true
+ true
+ true
+ *.md, *.MD, Makefile
+ false
+ true
+ true
+
+
+
+ ProjectExplorer.Project.PluginSettings
+
+
+ true
+ false
+ true
+ true
+ true
+ true
+
+
+ 0
+ true
+
+ true
+ true
+ Builtin.DefaultTidyAndClazy
+ 12
+ true
+
+
+
+ true
+
+
+
+
+ ProjectExplorer.Project.Target.0
+
+ Desktop
+ Desktop Qt 6.7.2 MinGW 64-bit
+ Desktop Qt 6.7.2 MinGW 64-bit
+ qt.qt6.672.win64_mingw_kit
+ 0
+ 0
+ 7
+
+ Debug
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=Debug
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ 0
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Desktop_Qt_6_7_2_MinGW_64_bit-Debug
+
+
+
+
+ all
+
+ false
+
+ true
+ 构建
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ 构建
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ Release
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=Release
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Desktop_Qt_6_7_2_MinGW_64_bit-Release
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ RelWithDebInfo
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Desktop_Qt_6_7_2_MinGW_64_bit-RelWithDebInfo
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release with Debug Information
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ RelWithDebInfo
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ 0
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Desktop_Qt_6_7_2_MinGW_64_bit-Profile
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Profile
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ MinSizeRel
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=MinSizeRel
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Desktop_Qt_6_7_2_MinGW_64_bit-MinSizeRel
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Minimum Size Release
+ CMakeProjectManager.CMakeBuildConfiguration
+
+ 5
+
+
+ 0
+ 部署
+ 部署
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ AdvancedDockingSystemDemo
+ CMakeProjectManager.CMakeRunConfiguration.AdvancedDockingSystemDemo
+ AdvancedDockingSystemDemo
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ AutoHideExample
+ CMakeProjectManager.CMakeRunConfiguration.AutoHideExample
+ AutoHideExample
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ CentralWidgetExample
+ CMakeProjectManager.CMakeRunConfiguration.CentralWidgetExample
+ CentralWidgetExample
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ DeleteOnCloseTest
+ CMakeProjectManager.CMakeRunConfiguration.DeleteOnCloseTest
+ DeleteOnCloseTest
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ DockInDockExample
+ CMakeProjectManager.CMakeRunConfiguration.DockInDockExample
+ DockInDockExample
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ EmptyDockAreaExample
+ CMakeProjectManager.CMakeRunConfiguration.EmptyDockAreaExample
+ EmptyDockAreaExample
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ HideShowExample
+ CMakeProjectManager.CMakeRunConfiguration.HideShowExample
+ HideShowExample
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ PowerMaster
+ CMakeProjectManager.CMakeRunConfiguration.PowerMaster
+ PowerMaster
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ SidebarExample
+ CMakeProjectManager.CMakeRunConfiguration.SidebarExample
+ SidebarExample
+ false
+ true
+ true
+ true
+
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+ SimpleExample
+ CMakeProjectManager.CMakeRunConfiguration.SimpleExample
+ SimpleExample
+ false
+ true
+ true
+ true
+
+ 10
+
+
+
+ ProjectExplorer.Project.Target.1
+
+ Desktop
+ Qt MinGW 64-bit
+ Qt MinGW 64-bit
+ {62abeb34-dcf2-4122-9f5b-6264babd3f00}
+ 0
+ 0
+ 0
+
+ Debug
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=Debug
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ 0
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Qt_MinGW_64_bit-Debug
+
+
+
+
+ all
+
+ false
+
+ true
+ 构建
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ 构建
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Debug
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ Release
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=Release
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Qt_MinGW_64_bit-Release
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ RelWithDebInfo
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Qt_MinGW_64_bit-RelWithDebInfo
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Release with Debug Information
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ RelWithDebInfo
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ 0
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Qt_MinGW_64_bit-Profile
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Profile
+ CMakeProjectManager.CMakeBuildConfiguration
+
+
+ MinSizeRel
+ 2
+ false
+
+ -DCMAKE_GENERATOR:STRING=Ninja
+-DCMAKE_BUILD_TYPE:STRING=MinSizeRel
+-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake
+-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable}
+-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX}
+-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C}
+-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx}
+-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}
+ E:\Code\CL-Softwares\Git\PowerMaster\build\Qt_MinGW_64_bit-MinSizeRel
+
+
+
+
+ all
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 构建
+ 构建
+ ProjectExplorer.BuildSteps.Build
+
+
+
+
+
+ clean
+
+ false
+
+ true
+ CMakeProjectManager.MakeStep
+
+ 1
+ 清除
+ 清除
+ ProjectExplorer.BuildSteps.Clean
+
+ 2
+ false
+
+ false
+
+ Minimum Size Release
+ CMakeProjectManager.CMakeBuildConfiguration
+
+ 5
+
+
+ 0
+ 部署
+ 部署
+ ProjectExplorer.BuildSteps.Deploy
+
+ 1
+
+ false
+ ProjectExplorer.DefaultDeployConfiguration
+
+ 1
+
+ true
+ true
+ 0
+ true
+
+ 2
+
+ false
+ -e cpu-cycles --call-graph "dwarf,4096" -F 250
+
+ ProjectExplorer.CustomExecutableRunConfiguration
+
+ false
+ true
+ true
+
+ 1
+
+
+
+ ProjectExplorer.Project.TargetCount
+ 2
+
+
+ ProjectExplorer.Project.Updater.FileVersion
+ 22
+
+
+ Version
+ 22
+
+
diff --git a/QtADS/.appveyor.yml b/QtADS/.appveyor.yml
new file mode 100644
index 0000000..9771255
--- /dev/null
+++ b/QtADS/.appveyor.yml
@@ -0,0 +1,151 @@
+version: '{build}'
+branches:
+ only:
+ - master
+
+image: Visual Studio 2017
+
+environment:
+ global:
+ # Appveyor doesn't have Qt 12 yet
+ LatestQtVersion: 5.13
+ matrix:
+# 32 bit builds
+# MSVC 2015 builds
+# Dynamic Library builds
+ # LTS version of Qt, dll, 32bit, MSVC 2015, qmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: x86
+ use_mingw: "false"
+ use_static: "false"
+ use_cmake: "false"
+ # LTS version of Qt, dll, 32bit, MSVC 2015, cmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: x86
+ use_mingw: "false"
+ use_static: "false"
+ use_cmake: "true"
+# end Dynamic Library builds
+# Static Library builds
+ # LTS version of Qt, static, 32bit, MSVC 2015, qmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: x86
+ use_mingw: "false"
+ use_static: "true"
+ use_cmake: "false"
+ # LTS version of Qt, static, 32bit, MSVC 2015, cmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: x86
+ use_mingw: "false"
+ use_static: "true"
+ use_cmake: "true"
+# end Static Library builds
+# end MSVC 2015 builds
+# MinGW builds
+# Dynamic Library builds
+ # LTS version of Qt, dll, 32bit, MinGW, qmake
+ - QT5: C:\Qt\%LatestQtVersion%\mingw73_32
+ COMPILER: C:\Qt\Tools\mingw730_32
+ targetPlatform: x86
+ use_mingw: "true"
+ use_static: "false"
+ use_cmake: "false"
+ # LTS version of Qt, dll, 32bit, MinGW, cmake
+ - QT5: C:\Qt\%LatestQtVersion%\mingw73_32
+ COMPILER: C:\Qt\Tools\mingw730_32
+ targetPlatform: x86
+ use_mingw: "true"
+ use_static: "false"
+ use_cmake: "true"
+# end Dynamic Library builds
+# Static Library builds
+ # LTS version of Qt, static, 32bit, MinGW, qmake
+ - QT5: C:\Qt\%LatestQtVersion%\mingw73_32
+ COMPILER: C:\Qt\Tools\mingw730_32
+ targetPlatform: x86
+ use_mingw: "true"
+ use_static: "true"
+ use_cmake: "false"
+ # LTS version of Qt, static, 32bit, MinGW, cmake
+ - QT5: C:\Qt\%LatestQtVersion%\mingw73_32
+ COMPILER: C:\Qt\Tools\mingw730_32
+ targetPlatform: x86
+ use_mingw: "true"
+ use_static: "true"
+ use_cmake: "true"
+# end Static Library builds
+# end MinGW builds
+# end 32 bit builds
+# 64 bit builds
+# MSVC 2015 builds
+# Dynamic Library builds
+ # LTS version of Qt, dll, 64bit, MSVC 2015, qmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017_64
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: amd64
+ use_mingw: "false"
+ use_static: "false"
+ use_cmake: "false"
+ # LTS version of Qt, dll, 64bit, MSVC 2015, cmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017_64
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: amd64
+ use_mingw: "false"
+ use_static: "false"
+ use_cmake: "true"
+# end Dynamic Library builds
+# Static Library builds
+ # LTS version of Qt, static, 64bit, MSVC 2015, qmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017_64
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: amd64
+ use_mingw: "false"
+ use_static: "true"
+ use_cmake: "false"
+ # LTS version of Qt, static, 64bit, MSVC 2015, cmake
+ - QT5: C:\Qt\%LatestQtVersion%\msvc2017_64
+ COMPILER: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build
+ targetPlatform: amd64
+ use_mingw: "false"
+ use_static: "true"
+ use_cmake: "true"
+# end Static Library builds
+# end MSVC 2015 builds
+# end 64 bit builds
+
+matrix:
+ fast_finish: true
+
+before_build:
+- set originalWD=%CD%
+- call "%QT5%\bin\qtenv2.bat"
+- cd /D %originalWD%
+- if %use_mingw%==false call "%COMPILER%\vcvarsall.bat" %targetPlatform%
+- if %use_static%==true (set USESTATIC=ON) else (set USESTATIC=OFF)
+- if %use_mingw%==true (set CMAKEGENERATOR="MinGW Makefiles") else (set CMAKEGENERATOR="NMake Makefiles")
+- if %use_mingw%==true (set MAKEENGINE=mingw32-make) else (set MAKEENGINE=nmake)
+- if %use_mingw%==true set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
+
+build_script:
+- if %use_cmake%==true mkdir build
+- if %use_cmake%==true cd build
+- if %use_cmake%==true cmake --version
+- if %use_cmake%==true cmake -G %CMAKEGENERATOR% -DCMAKE_BUILD_TYPE=DEBUG -DBUILD_EXAMPLES=ON -DCMAKE_DEBUG_POSTFIX=d -DBUILD_STATIC=%USESTATIC% -DCMAKE_INSTALL_PREFIX="./installed" ../
+- if %use_cmake%==true cmake --build .
+- if %use_cmake%==true cmake --build . --target install
+- if %use_cmake%==true cmake -G %CMAKEGENERATOR% -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=ON -DBUILD_STATIC=%USESTATIC% -DCMAKE_INSTALL_PREFIX="./installed" ../
+- if %use_cmake%==true cmake --build .
+- if %use_cmake%==true cmake --build . --target install
+- if %use_cmake%==false if %use_static%==true qmake "CONFIG+=adsBuildStatic"
+- if %use_cmake%==false if %use_static%==false qmake
+- if %use_cmake%==false %MAKEENGINE% debug
+- if %use_cmake%==false %MAKEENGINE% install
+- if %use_cmake%==false %MAKEENGINE% release
+- if %use_cmake%==false %MAKEENGINE% install
+
+after_build:
+- if %use_mingw%==true set PATH=C:\Program Files\Git\usr\bin;%PATH%
diff --git a/QtADS/.clang-format b/QtADS/.clang-format
new file mode 100644
index 0000000..f044fe5
--- /dev/null
+++ b/QtADS/.clang-format
@@ -0,0 +1,146 @@
+---
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignConsecutiveMacros: None
+AlignConsecutiveAssignments: None
+AlignConsecutiveDeclarations: None
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments: true
+
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: InlineOnly
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLambdasOnASingleLine: Inline
+AllowShortLoopsOnASingleLine: false
+
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+
+BinPackArguments: true
+BinPackParameters: true
+
+BraceWrapping:
+ AfterCaseLabel: true
+ AfterClass: true
+ AfterControlStatement: Always
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterStruct: true
+ AfterUnion: true
+ AfterExternBlock: true
+ BeforeCatch: true
+ BeforeElse: true
+ BeforeLambdaBody: false
+ IndentBraces: false
+ SplitEmptyFunction: false
+ SplitEmptyRecord: false
+ SplitEmptyNamespace: false
+
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializers: BeforeColon
+BreakInheritanceList: AfterColon
+BreakStringLiterals: true
+
+ColumnLimit: 82
+CommentPragmas: '^(!.*|@c)'
+
+CompactNamespaces: false
+
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+
+FixNamespaceComments: true
+
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^' # windows headers
+ Priority: -1
+ - Regex: '^' # Qt headers
+ Priority: 3
+ - Regex: '^' # other headers
+ Priority: 5
+ - Regex: '<[[:alnum:]._/]+>' # system headers
+ Priority: 6
+ - Regex: '.*'
+ Priority: 7
+
+IncludeIsMainRegex: '(_p)?$'
+
+IndentCaseBlocks: false
+IndentCaseLabels: false
+IndentPPDirectives: AfterHash
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+
+KeepEmptyLinesAtTheStartOfBlocks: false
+MaxEmptyLinesToKeep: 1
+
+NamespaceIndentation: None
+
+PenaltyBreakAssignment: 20
+PenaltyBreakBeforeFirstCallParameter: 15
+PenaltyBreakComment: 10
+PenaltyBreakFirstLessLess: 5
+# PenaltyBreakOpenParenthesis: 30
+PenaltyBreakString: 150
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 100
+PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 150
+
+PointerAlignment: Left
+ReflowComments: true
+
+SortIncludes: CaseSensitive
+SortUsingDeclarations: true
+
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: Never
+SpacesInCStyleCastParentheses: false
+SpacesInConditionalStatement: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+
+Standard: c++17
+
+StatementMacros: [ 'Q_UNUSED', 'PIMPL_D', 'PIMPL_Q', 'OD_ENTRY', 'OD_ENTRY_PROCIMG' ]
+
+TabWidth: 4
+UseTab: Never
diff --git a/QtADS/.gitattributes b/QtADS/.gitattributes
new file mode 100644
index 0000000..f75bc5b
--- /dev/null
+++ b/QtADS/.gitattributes
@@ -0,0 +1 @@
+PyQtAds/_version.py export-subst
diff --git a/QtADS/.gitignore b/QtADS/.gitignore
new file mode 100644
index 0000000..7881b10
--- /dev/null
+++ b/QtADS/.gitignore
@@ -0,0 +1,389 @@
+*.pro.user*
+/build
+*.o
+*.dylib
+*.app
+qrc_*
+moc_*
+ui_*
+Makefile
+*.dll
+*.a
+build-*
+
+# IDEs
+.idea
+
+# Python
+.eggs
+*.pyc
+*.pyd
+__pycache__
+PyQtAds/rc.py
+/.cproject
+
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*[.json, .xml, .info]
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+/ build
+/Settings.ini
+.vscode/settings.json
+/.settings
diff --git a/QtADS/.project b/QtADS/.project
new file mode 100644
index 0000000..b847252
--- /dev/null
+++ b/QtADS/.project
@@ -0,0 +1,27 @@
+
+
+ QtAdvancedDockingSystem
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/QtADS/.travis.yml b/QtADS/.travis.yml
new file mode 100644
index 0000000..38db61f
--- /dev/null
+++ b/QtADS/.travis.yml
@@ -0,0 +1,233 @@
+language: cpp
+# gcc is clang on mac
+compiler: gcc
+
+matrix:
+ fast_finish: true
+ include:
+ - name: Ubuntu qmake Qt5.5.1
+ os: linux
+ dist: trusty
+ group: stable
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - sourceline: 'ppa:beineri/opt-qt551-trusty'
+ update: true
+ packages:
+ - qt55base
+ - qt55tools
+ - gcc-9
+ - g++-9
+ script:
+ - PATH="/opt/qt55/bin:$PATH"
+ - CXX="g++-9"
+ - CC="gcc-9"
+ - qt55-env.sh
+ - qmake
+ - make
+ - make install
+ - name: Ubuntu qmake dll
+ os: linux
+ dist: bionic
+ group: stable
+ services:
+ - xvfb
+ compiler: gcc
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - sourceline: 'ppa:beineri/opt-qt-5.14.2-bionic'
+ update: true
+ packages:
+ - qt514base
+ - qt514tools
+ - gcc-9
+ - g++-9
+ - libc6-i386
+ - libgl-dev
+ - libgl1-mesa-dev
+ - mesa-common-dev
+ script:
+ - PATH="/opt/qt514/bin:$PATH"
+ - CXX="g++-9"
+ - CC="gcc-9"
+ - qt514-env.sh
+ - qmake
+ - make
+ - make install
+ - name: Ubuntu qmake static
+ os: linux
+ dist: bionic
+ group: stable
+ services:
+ - xvfb
+ compiler: gcc
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - sourceline: 'ppa:beineri/opt-qt-5.14.2-bionic'
+ update: true
+ packages:
+ - qt514base
+ - qt514tools
+ - gcc-9
+ - g++-9
+ - libc6-i386
+ - libgl-dev
+ - libgl1-mesa-dev
+ - mesa-common-dev
+ script:
+ - PATH="/opt/qt514/bin:$PATH"
+ - CXX="g++-9"
+ - CC="gcc-9"
+ - qt514-env.sh
+ - qmake "CONFIG+=adsBuildStatic"
+ - make
+ - make install
+ - name: Ubuntu CMake dll
+ os: linux
+ dist: bionic
+ group: stable
+ services:
+ - xvfb
+ compiler: gcc
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - sourceline: 'ppa:beineri/opt-qt-5.14.2-bionic'
+ update: true
+ packages:
+ - qt514base
+ - qt514tools
+ - gcc-9
+ - g++-9
+ - libc6-i386
+ - libgl-dev
+ - libgl1-mesa-dev
+ - mesa-common-dev
+ script:
+ - PATH="/opt/qt514/bin:$PATH"
+ - CXX="g++-9"
+ - CC="gcc-9"
+ - qt514-env.sh
+ - mkdir ./build
+ - cd ./build
+ - cmake --version
+ - cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_STATIC=OFF -DBUILD_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=DEBUG -DBUILD_STATIC=OFF -DBUILD_EXAMPLES=ON -DCMAKE_DEBUG_POSTFIX=d -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - name: Ubuntu CMake Static
+ os: linux
+ dist: bionic
+ group: stable
+ services:
+ - xvfb
+ compiler: gcc
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - sourceline: 'ppa:beineri/opt-qt-5.14.2-bionic'
+ update: true
+ packages:
+ - qt514base
+ - qt514tools
+ - gcc-9
+ - g++-9
+ - libc6-i386
+ - libgl-dev
+ - libgl1-mesa-dev
+ - mesa-common-dev
+ script:
+ - PATH="/opt/qt514/bin:$PATH"
+ - CXX="g++-9"
+ - CC="gcc-9"
+ - qt514-env.sh
+ - mkdir ./build
+ - cd ./build
+ - cmake --version
+ - cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_STATIC=ON -DBUILD_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=DEBUG -DBUILD_STATIC=ON -DBUILD_EXAMPLES=ON -DCMAKE_DEBUG_POSTFIX=d -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - name: macOS CMake dll
+ os: osx
+ osx_image: xcode11.3
+ compiler: clang
+ addons:
+ homebrew:
+ packages:
+ - qt
+ update: true
+ script:
+ - PATH="/usr/local/opt/qt5/bin:$PATH"
+ - mkdir -p build
+ - cd build
+ - cmake --version
+ - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_DEBUG_POSTFIX=_debug -DBUILD_EXAMPLES=ON -DBUILD_STATIC=OFF -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=ON -DBUILD_STATIC=OFF -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - name: macOS CMake static
+ os: osx
+ osx_image: xcode11.3
+ compiler: clang
+ addons:
+ homebrew:
+ packages:
+ - qt
+ update: true
+ script:
+ - PATH="/usr/local/opt/qt5/bin:$PATH"
+ - mkdir -p build
+ - cd build
+ - cmake --version
+ - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_DEBUG_POSTFIX=_debug -DBUILD_EXAMPLES=ON -DBUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_EXAMPLES=ON -DBUILD_STATIC=ON -DCMAKE_INSTALL_PREFIX="./installed" ../
+ - cmake --build .
+ - cmake --build . --target install
+ - name: macOS qmake dll
+ os: osx
+ osx_image: xcode11.3
+ compiler: clang
+ addons:
+ homebrew:
+ packages:
+ - qt
+ update: true
+ script:
+ - PATH="/usr/local/opt/qt5/bin:$PATH"
+ - qmake
+ - make
+ - make install
+ - name: macOS qmake static
+ os: osx
+ osx_image: xcode11.3
+ compiler: clang
+ addons:
+ homebrew:
+ packages:
+ - qt
+ update: true
+ script:
+ - PATH="/usr/local/opt/qt5/bin:$PATH"
+ - qmake "CONFIG+=adsBuildStatic"
+ - make
+ - make install
+notifications:
+ email: false
+
diff --git a/QtADS/CMakeLists.txt b/QtADS/CMakeLists.txt
new file mode 100644
index 0000000..6985490
--- /dev/null
+++ b/QtADS/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.5)
+
+if (POLICY CMP0091)
+ cmake_policy(SET CMP0091 NEW)
+endif (POLICY CMP0091)
+
+# By default, the version information is extracted from the git index. However,
+# we can override this behavior by explicitly setting ADS_VERSION and
+# skipping the git checks. This is useful for cases where this project is being
+# used independently of its original git repo (e.g. vendored in another project)
+if(NOT ADS_VERSION)
+ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
+ include(GetGitRevisionDescription)
+ git_describe(GitTagVersion --tags)
+ string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GitTagVersion}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${GitTagVersion}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${GitTagVersion}")
+ set(VERSION_SHORT "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
+else()
+ string(REGEX MATCHALL "[\.]" VERSION_DOT_MATCHES ${ADS_VERSION})
+ list(LENGTH VERSION_DOT_MATCHES VERSION_DOT_COUNT)
+ if(VERSION_DOT_COUNT EQUAL 2)
+ set(VERSION_SHORT ${ADS_VERSION})
+ else()
+ message(FATAL_ERROR "ADS_VERSION must be in major.minor.patch format, e.g. 3.8.1. Got ${ADS_VERSION}")
+ endif()
+endif()
+
+project(QtADS LANGUAGES CXX VERSION ${VERSION_SHORT})
+
+option(BUILD_STATIC "Build the static library" OFF)
+option(BUILD_EXAMPLES "Build the examples" ON)
+
+if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
+ set(ads_PlatformDir "x86")
+else()
+ if(DEFINED CMAKE_SYSTEM_PROCESSOR)
+ if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
+ set(ads_PlatformDir "x64")
+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64")
+ set(ads_PlatformDir "aarch64")
+ else()
+ set(ads_PlatformDir "x64")
+ endif()
+ else()
+ set(ads_PlatformDir "x64")
+ endif()
+endif()
+
+add_subdirectory(src)
+
+if(BUILD_EXAMPLES)
+ add_subdirectory(examples)
+ add_subdirectory(demo)
+endif()
+
diff --git a/QtADS/LICENSE b/QtADS/LICENSE
new file mode 100644
index 0000000..8000a6f
--- /dev/null
+++ b/QtADS/LICENSE
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random
+ Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/QtADS/MANIFEST.in b/QtADS/MANIFEST.in
new file mode 100644
index 0000000..adc4e4d
--- /dev/null
+++ b/QtADS/MANIFEST.in
@@ -0,0 +1,2 @@
+include versioneer.py
+include PyQtAds/_version.py
diff --git a/QtADS/README.md b/QtADS/README.md
new file mode 100644
index 0000000..ca76dba
--- /dev/null
+++ b/QtADS/README.md
@@ -0,0 +1,717 @@
+
+
+
+
+------------------
+
+[](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest)
+[](gnu-lgpl-v2.1.md)
+[](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/actions?query=workflow%3Alinux-builds)
+[](https://ci.appveyor.com/project/githubuser0xFFFF/qt-advanced-docking-system/branch/master)
+[](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/graphs/contributors)
+
+Qt Advanced Docking System lets you create customizable layouts using a full
+featured window docking system similar to what is found in many popular
+integrated development environments (IDEs) such as Visual Studio.
+
+- [What's new...](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest)
+- [Documentation](doc/user-guide.md)
+- Original Repository: https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System
+
+[](https://www.youtube.com/watch?v=7pdNfafg3Qc)
+
+## New and Noteworthy
+
+Release [4.1](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest) significantly improves the Auto-Hide functionality and also brings improvements
+for Drag and Drop of dock widgets into dock area tabs. These are the highlights of the new version:
+
+#### Drag & Drop to Auto-Hide
+
+Now you can easily drag any dock widget or any floating widget to the
+borders of a window to pin it as a auto-hide tab in one of the 4 sidebars.
+If you drag a dock widget close the one of the four window borders, special
+drop overlays will be shown to indicate the drop area for auto-hide widgets:
+
+
+
+Of course, this also works with dock areas:
+
+
+
+If you drag a dock widget or dock area into a sidebar, then you even have
+control over where tabs are inserted. Simply drag your mouse over a specific
+auto-hide tab, and your dragged dock widget will be inserted before this tab.
+Drag to the sidebar area behind the last tab, and the dragged widget will be
+appended as last tab. In the following screen capture, the **Image Viewer 1** will
+be inserted before the **Table 0** Auto-Hide tab and the **Image Viewer 2**
+is appende behind the last tab:
+
+
+
+#### Auto-Hide Tab Insertion Order
+
+It is also possible to drag Auto-Hide tabs to a new auto-hide position.
+That means, you can drag them to a different border or sidebar:
+
+
+
+#### Auto-Hide Tab Sorting
+
+You can drag Auto-Hide tabs to a new position in the current sidebar
+to sort them:
+
+
+
+#### Auto-Hide Drag to Float / Dock
+
+But that is not all. You can also simply move Auto-Hide tabs to another
+floating widget or dock them via drag and drop:
+
+
+
+#### Auto-Hide Context Menu
+
+All Auto-Hide tabs now have a context menu, that provides all the functionality
+that you know from Dock widget tabs. With the **Pin To...** item from the
+context menu it is very easy to move an Auto-Hide tab to a different Auto-Hide
+sidebar:
+
+
+
+#### Dock Area Tab Insert Order
+
+And last but not least the new version also improves the docking of widgets
+into the tabs of a Dock area. Just as with Auto-Hide tabs, you can now determine the position at which a tab is inserted by moving the mouse over an already existing tab (insertion before the tab) or behind the last tab
+(appending):
+
+
+
+The [release 4.0](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest)
+adds the following features:
+
+- Auto-Hide functionality ([read more...](#auto-hide-functionality))
+
+
+
+- improved demo application with new image viewer dock widgets
+
+
+
+- Visual Studio like CSS theme in demo application
+
+The [release 3.8](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/3.8.3)
+adds the following features:
+
+- option to close tabs with the middle mouse button
+- `DeleteContentOnClose` flag for dynamic deletion and creation of dock widget
+ content
+- improved focus highlighting functionality
+
+The [release 3.7](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.7.2)
+adds the following features:
+
+- support for **Qt6.**
+- support for [empty dock area](doc/user-guide.md#empty-dock-area)
+
+The [release 3.6](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.6.3)
+adds some nice new features:
+
+- support for [central widget](doc/user-guide.md#central-widget) concept
+
+
+
+- support for [native floating widgets](doc/user-guide.md#floatingcontainerforcenativetitlebar-linux-only) on Linux
+
+
+
+Both features are contributions from ADS users. Read the [documentation](doc/user-guide.md)
+to learn more about both new features.
+
+The [release 3.5](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.5.0)
+adds the new [focus highlighting](doc/user-guide.md#focushighlighting) feature.
+This optional feature enables highlighting of the focused dock widget like you
+know it from Visual Studio.
+
+
+
+ [learn more...](doc/user-guide.md#focushighlighting)
+
+## Features
+
+### Overview
+
+- [New and Noteworthy](#new-and-noteworthy)
+ - [Drag \& Drop to Auto-Hide](#drag--drop-to-auto-hide)
+ - [Auto-Hide Tab Insertion Order](#auto-hide-tab-insertion-order)
+ - [Auto-Hide Tab Sorting](#auto-hide-tab-sorting)
+ - [Auto-Hide Drag to Float / Dock](#auto-hide-drag-to-float--dock)
+ - [Auto-Hide Context Menu](#auto-hide-context-menu)
+ - [Dock Area Tab Insert Order](#dock-area-tab-insert-order)
+- [Features](#features)
+ - [Overview](#overview)
+ - [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)
+ - [Docking inside floating windows](#docking-inside-floating-windows)
+ - [Grouped dragging](#grouped-dragging)
+ - [Perspectives for fast switching of the complete main window layout](#perspectives-for-fast-switching-of-the-complete-main-window-layout)
+ - [Opaque and non-opaque splitter resizing](#opaque-and-non-opaque-splitter-resizing)
+ - [Cancelable docking process](#cancelable-docking-process)
+ - [Tab-menu for easy handling of many tabbed dock widgets](#tab-menu-for-easy-handling-of-many-tabbed-dock-widgets)
+ - [Many different ways to detach dock widgets](#many-different-ways-to-detach-dock-widgets)
+ - [Supports deletion of dynamically created dock widgets](#supports-deletion-of-dynamically-created-dock-widgets)
+ - [Auto-Hide Functionality](#auto-hide-functionality)
+- [Python Bindings](#python-bindings)
+ - [PySide6](#pyside6)
+ - [PyQt5](#pyqt5)
+- [Tested Compatible Environments](#tested-compatible-environments)
+ - [Supported Qt Versions](#supported-qt-versions)
+ - [Windows](#windows)
+ - [macOS](#macos)
+ - [Linux](#linux)
+- [Build](#build)
+ - [Qt5 on Ubuntu 18.04 or 20.04](#qt5-on-ubuntu-1804-or-2004)
+ - [Qt5 on Ubuntu 22.04](#qt5-on-ubuntu-2204)
+ - [Qt6 on Ubuntu 22.04](#qt6-on-ubuntu-2204)
+- [Getting started / Example](#getting-started--example)
+- [License information](#license-information)
+- [Donation](#donation)
+- [Showcase](#showcase)
+ - [Qt Creator IDE](#qt-creator-ide)
+ - [Qt Design Studio](#qt-design-studio)
+ - [CETONI Elements](#cetoni-elements)
+ - [ezEditor](#ezeditor)
+ - [D-Tect X](#d-tect-x)
+ - [HiveWE](#hivewe)
+ - [Ramses Composer](#ramses-composer)
+ - [Plot Juggler](#plot-juggler)
+ - [Notepad Next](#notepad-next)
+ - [MetGem](#metgem)
+ - [PRE Workbench](#pre-workbench)
+ - [RDE – Robox Development Environment](#rde--robox-development-environment)
+ - [ResInsight](#resinsight)
+ - [ADTF 3](#adtf-3)
+ - [DREAM.3D NX](#dream3d-nx)
+ - [LabPlot](#labplot)
+- [Alternative Docking System Implementations](#alternative-docking-system-implementations)
+ - [KDDockWidgets](#kddockwidgets)
+ - [QtitanDocking](#qtitandocking)
+ - [DockingPanes](#dockingpanes)
+
+### Docking everywhere - no central widget
+
+There is no central widget like in the Qt docking system. You can dock on every
+border of the main window or you can dock into each dock area - so you are
+free to dock almost everywhere.
+
+
+
+
+
+### Docking inside floating windows
+
+There is no difference between the main window and a floating window. Docking
+into floating windows is supported.
+
+
+
+
+
+### Grouped dragging
+
+When dragging the titlebar of a dock, all the tabs that are tabbed with it are
+going to be dragged. So you can move complete groups of tabbed widgets into
+a floating widget or from one dock area to another one.
+
+
+
+
+
+### Perspectives for fast switching of the complete main window layout
+
+A perspective defines the set and layout of dock windows in the main
+window. You can save the current layout of the dockmanager into a named
+perspective to make your own custom perspective. Later you can simply
+select a perspective from the perspective list to quickly switch the complete
+main window layout.
+
+
+
+
+
+### Opaque and non-opaque splitter resizing
+
+The advanced docking system uses standard QSplitters as resize separators and thus supports opaque and non-opaque resizing functionality of QSplitter. In some rare cases, for very complex widgets or on slow machines resizing via separator on the fly may cause flicking and glaring of rendered content inside a widget. The global dock manager flag `OpaqueSplitterResize` configures the resizing behaviour of the splitters. If this flag is set, then widgets are resized dynamically (opaquely) while interactively moving the splitters.
+
+
+
+If this flag is cleared, the widget resizing is deferred until the mouse button is released - this is some kind of lazy resizing separator.
+
+
+
+### Cancelable docking process
+
+In contrast to the standard Qt docking system, docking with the ADS works more like a drag & drop operation. That means, the dragged dock widget or dock area is not undocked immediately. Instead, a drag preview widget is created and dragged around to indicate the future position of the dock widget or dock area. The actual dock operation is only executed when the mouse button is released. That makes it possible, to cancel an active drag operation with the escape key.
+
+The drag preview widget can be configured by a number of global dock manager flags:
+- `DragPreviewIsDynamic`: if this flag is enabled, the preview will be adjusted dynamically to the drop area
+- `DragPreviewShowsContentPixmap`: the created drag preview window shows a static copy of the content of the dock widget / dock are that is dragged
+- `DragPreviewHasWindowFrame`: this flag configures if the drag preview is frameless like a QRubberBand or looks like a real window
+
+### Tab-menu for easy handling of many tabbed dock widgets
+
+Tabs are a good way to quickly switch between dockwidgets in a dockarea. However, if the number of dockwidgets in a dockarea is too large, this may affect the usability of the tab bar. To keep track in this situation, you can use the tab menu. The menu allows you to quickly select the dockwidget you want to activate from a drop down menu.
+
+
+
+### Many different ways to detach dock widgets
+
+You can detach dock widgets and also dock areas in the following ways:
+
+- by dragging the dock widget tab or the dock area title bar
+- by double clicking the tab or title bar
+- by using the detach menu entry from the tab and title bar drop down menu
+
+### Supports deletion of dynamically created dock widgets
+
+Normally clicking the close button of a dock widget will just hide the widget and the user can show it again using the toggleView() action of the dock widget. This is meant for user interfaces with a static amount of widgets. But the advanced docking system also supports dynamic dock widgets that will get deleted on close. If you set the dock widget flag `DockWidgetDeleteOnClose` for a certain dock widget, then it will be deleted as soon as you close this dock widget. This enables the implementation of user interfaces with dynamically created editors, like in word processing applications or source code development tools.
+
+### Auto-Hide Functionality
+
+The 4.0 release of ADS added the new **Auto-Hide** feature. Thanks to the
+[initial contribution](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/pull/452) by [Ahmad Syarifuddin](https://github.com/SyarifFakhri) it was
+possible to close this long standing [feature request](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/147). The "Auto Hide" feature
+allows to display more information using less screen space by hiding or showing
+windows pinned to one of the four dock container borders.
+
+
+
+The Advanced Docking
+System supports "Auto-Hide" functionality for **all** dock containers - that means,
+for the main window and for each floating widget. Here is short list of all
+auto hide features:
+
+- supported for the main window and all floating dock containers
+- supports showing and hiding via mouse click or mouse hover
+- respects opaque / non opaque splitter resizing flag
+- context menu for pinning a dock widget or a complete dock area to a certain border
+- configuration option to configure if the pin button should pin the current
+ dock widget tab or a complete dock area
+- click the pin button holding the Ctrl key to pin a complete dock area
+- fully CSS styleable
+- backward compatible state file format - is is possible to load older dock manager
+ state files without auto hide support and older versions can load the new state
+ files with Auto-Hide state information
+
+More about the auto hide configuration options in the [online documentation...](doc/user-guide.md#auto-hide-configuration-flags)
+
+## Python Bindings
+
+
+
+Thanks to the contribution of several users, the Advanced Docking System comes
+with a complete Python integration. Python bindings are available for **PyQt5** and
+**PySide6**.
+
+### PySide6
+
+A PySide6 ADS package is available via PyPi and can be installed on Windows,
+macOS, and Linux with:
+
+```bash
+pip install PySide6-QtAds
+```
+
+Sample code is available [here](https://github.com/mborgerson/Qt-Advanced-Docking-System/tree/pyside6/examples). To run the samples, you'll also need to install latest qtpy
+from source (pip install https://github.com/spyder-ide/qtpy/archive/refs/heads/master.zip).
+The PySide6 bindings were contributed by:
+
+- [mborgerson](https://github.com/mborgerson)
+
+Please file PySide6-QtAds-specific issues on its [pyside6_qtads](https://github.com/mborgerson/pyside6_qtads) fork for tracking. For more information about the PySide6 bindings read [this](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/298) issue.
+
+### PyQt5
+
+A package is available via [conda-forge](https://github.com/conda-forge/pyqtads-feedstock).
+The python integration has been contributed to this project by the following people:
+
+- [n-elie](https://github.com/n-elie)
+- [Hugo Slepicka](https://github.com/hhslepicka)
+- [K Lauer](https://github.com/klauer)
+
+A Python integration is also available via PyPi. You can install the
+[PyQtAds](https://pypi.org/project/PyQtAds/) package via pip. This feature has been
+contributed to this project by:
+
+- [Mira Weller](https://github.com/luelista)
+
+## Tested Compatible Environments
+
+### Supported Qt Versions
+
+The library supports **Qt5** and **Qt6**.
+
+### Windows
+
+Windows 10 [](https://ci.appveyor.com/project/githubuser0xFFFF/qt-advanced-docking-system/branch/master)
+
+The library was developed on and for Windows. It is used in a commercial Windows application and is therefore constantly tested.
+
+### macOS
+
+macOS [](https://travis-ci.org/githubuser0xFFFF/Qt-Advanced-Docking-System)
+
+The application can be compiled for macOS. A user reported, that the library works on macOS. If have not tested it.
+
+
+
+### Linux
+
+[](https://travis-ci.org/githubuser0xFFFF/Qt-Advanced-Docking-System)
+[](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/actions?query=workflow%3Alinux-builds)
+
+Unfortunately, there is no such thing as a Linux operating system. Linux is a heterogeneous environment with a variety of different distributions. So it is not possible to support "Linux" like it is possible for Windows. It is only possible to support and test a small subset of Linux distributions. The library can be compiled for and has been developed and tested with some Linux distributions. Depending on the used window manager or compositor, dock widgets
+with native title bars are supported or not. If native title bars are not supported,
+the library switches to `QWidget` based title bars.
+
+- **Kubuntu 18.04 and 19.10** - uses KWin - no native title bars
+- **Ubuntu 18.04, 19.10 and 20.04** - native title bars are supported
+- **Ubuntu 22.04** - uses Wayland -> no native title bars
+
+There are some requirements for the Linux distribution that have to be met:
+
+- an X server that supports ARGB visuals and a compositing window manager. This is required to display the translucent dock overlays ([https://doc.qt.io/qt-5/qwidget.html#creating-translucent-windows](https://doc.qt.io/qt-5/qwidget.html#creating-translucent-windows)). If your Linux distribution does not support this, or if you disable this feature, you will very likely see issue [#95](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/95).
+- Wayland is not properly supported by Qt yet. If you use Wayland, then you should set the session type to x11: `XDG_SESSION_TYPE=x11 ./AdvancedDockingSystemDemo`. You will find more details about this in issue [#288](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/288).
+
+Screenshot Kubuntu:
+
+
+Screenshot Ubuntu:
+
+
+## Build
+
+The Linux build requires private header files. Make sure that they are installed.
+The library uses SVG icons, so ensure that Qt SVG support is installed. The demo
+application creates a `QQuickWidget` for testing, so ensure that the required
+libraries are installed.
+
+### Qt5 on Ubuntu 18.04 or 20.04
+
+```bash
+sudo apt install qt5-default qtbase5-private-dev
+```
+
+### Qt5 on Ubuntu 22.04
+
+```bash
+sudo apt install qtbase5-dev qtbase5-private-dev qtbase5-dev-tools libqt5svg5 libqt5qml5 qtdeclarative5-dev
+```
+
+### Qt6 on Ubuntu 22.04
+
+```bash
+sudo apt install qt6-default qt6-base-dev qt6-base-private-dev qt6-tools-dev libqt6svg6 qt6-qtdeclarative
+```
+
+Open the `ads.pro` file with QtCreator and start the build, that's it.
+You can run the demo project and test it yourself.
+
+## Getting started / Example
+
+The following example shows the minimum code required to use the advanced Qt docking system.
+
+*MainWindow.h*
+
+```cpp
+#include
+#include "DockManager.h"
+
+namespace Ui {
+class MainWindow;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+private:
+ Ui::MainWindow *ui;
+
+ // The main container for docking
+ ads::CDockManager* m_DockManager;
+};
+```
+
+*MainWindow.cpp*
+
+```cpp
+#include "MainWindow.h"
+#include "ui_MainWindow.h"
+
+#include
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ // Create the dock manager after the ui is setup. Because the
+ // parent parameter is a QMainWindow the dock manager registers
+ // itself as the central widget as such the ui must be set up first.
+ m_DockManager = new ads::CDockManager(this);
+
+ // Create example content label - this can be any application specific
+ // widget
+ QLabel* l = new QLabel();
+ l->setWordWrap(true);
+ l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
+
+ // Create a dock widget with the title Label 1 and set the created label
+ // as the dock widget content
+ ads::CDockWidget* DockWidget = new ads::CDockWidget("Label 1");
+ DockWidget->setWidget(l);
+
+ // Add the toggleViewAction of the dock widget to the menu to give
+ // the user the possibility to show the dock widget if it has been closed
+ ui->menuView->addAction(DockWidget->toggleViewAction());
+
+ // Add the dock widget to the top dock widget area
+ m_DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+```
+
+## License information
+
+[](gnu-lgpl-v2.1.md)
+This project uses the [LGPLv2.1 license](gnu-lgpl-v2.1.md)
+
+## Donation
+
+If this project help you reduce time to develop or if you just like it, you can give me a cup of coffee :coffee::wink:.
+
+
+
+
+
+## Showcase
+
+### [Qt Creator IDE](https://www.qt.io/development-tools)
+
+From version 4.12 on, Qt Creator uses the Advanced Docking Framework for its
+Qt Quick Designer. This improves the usability when using multiple screens.
+
+
+
+### [Qt Design Studio](https://www.qt.io/ui-design-tools)
+
+Taken from the [Qt Blog](https://www.qt.io/blog/qt-design-studio-1.5-beta-released):
+
+> The most obvious change in [Qt Design Studio 1.5](https://www.qt.io/blog/qt-design-studio-1.5-beta-released) is the integration of dock widgets using the Qt Advanced Docking System. This allows the user to fully customize the workspace and also to undock any view into its own top level window. This especially improves the usability when using multiple screens.
+
+[](https://youtu.be/za9KBWcFXEw?t=84)
+
+### [CETONI Elements](https://cetoni.com/cetoni-elements/)
+
+The CETONI Elements software from [CETONI](https://www.cetoni.com) is a comprehensive,
+plugin-based and modular laboratory automation software for controlling CETONI devices using a joint graphical user interface. The software features a powerful script system to automate processes. The software uses the advanced docking system to give the user the freedom to arrange all the views and windows that are provided by the various plugins.
+
+[learn more...](https://cetoni.com/cetoni-elements/)
+
+[](https://www.youtube.com/watch?v=7pdNfafg3Qc)
+
+### [ezEditor](https://github.com/ezEngine/ezEngine)
+
+The ezEditor is a full blown graphical editor used for editing scenes and
+importing and authoring assets for the [ezEngine](https://github.com/ezEngine/ezEngine) -
+an open source C++ game engine in active development.
+
+
+
+### [D-Tect X](https://www.duerr-ndt.com/products/ndt-software/d-tect-xray-inspection-software.html)
+
+D-Tect X is a X-ray inspection software for industrial radiography. It is a state-of-the-art 64-bit application which supports GPU (Graphics Processing Unit) acceleration and takes full advantage of computers with multiple CPU cores. A large set of tools assist the user in image analysis and evaluation. Thanks to the Qt Advanced Docking System the flexible and intuitive user interface can be completely customized to each user’s preference.
+
+[learn more...](https://www.duerr-ndt.com/products/ndt-software/d-tect-xray-inspection-software.html)
+
+[](https://youtu.be/mOor7GmmIJo?t=13)
+
+### [HiveWE](https://github.com/stijnherfst/HiveWE)
+
+HiveWE is a Warcraft III world editor. It focusses on speed and ease of use,
+especially for large maps where the regular World Editor is often too slow and clunky.
+It has a JASS editor with syntax highlighting, tabs, code completion and more.
+The JASS editor uses the Qt Advanced Docking System for the management and layout
+of the open editor windows.
+
+[learn more...](https://github.com/stijnherfst/HiveWE)
+
+
+
+### [Ramses Composer](https://github.com/GENIVI/ramses-composer)
+
+Ramses Composer is the authoring tool for the open source [RAMSES](https://github.com/GENIVI/ramses)
+rendering ecosystem.
+
+Ramses is a low-level rendering engine which is optimized for embedded hardware
+mobile devices, automotive ECUs, IoT electronics. Ramses was initially developed
+at the BMW Group and open-sourced in 2018 as part of a collaboration initiative
+with the Genivi Alliance. It is an important part of the BMW infotainment cluster
+and digital portfolio.
+
+[learn more...](https://github.com/GENIVI/ramses-composer)
+
+
+
+### [Plot Juggler](https://github.com/facontidavide/PlotJuggler)
+
+PlotJuggler is a fast, powerful and intuitive tool to visualize time series.
+It makes it easy to visualize data but also to analyze it. You can manipulate
+your time series using a simple and extendable Transform Editor. Some of the
+highlights are:
+
+- Simple Drag & Drop user interface.
+- Load data from file.
+- Connect to live streaming of data.
+- Save the visualization layout and configurations to re-use them later.
+- Fast OpenGL visualization.
+- Can handle thousands of timeseries and millions of data points.
+- Transform your data using a simple editor: derivative, moving average, integral, etc…
+- PlotJuggler can be easily extended using plugins.
+
+[read more...](https://github.com/facontidavide/PlotJuggler)
+
+[](https://vimeo.com/480588113#t=46s)
+
+### [Notepad Next](https://github.com/dail8859/NotepadNext)
+
+Notepad Next is a cross-platform reimplementation of Notepad++ that uses the
+Advanced Docking System to arrange the open source files on the screen.
+
+[read more...](https://github.com/dail8859/NotepadNext)
+
+
+
+### [MetGem](https://metgem.github.io/)
+
+MetGem is an open-source software for tandem mass-spectrometry data visualization.
+It's key features are standalone molecular networking and t-SNE based projections.
+MetGem uses the Qt-Advanced-Docking-System to manage docks and to create independent
+molecular network views.
+
+[read more...](https://metgem.github.io/)
+
+
+
+### [PRE Workbench](https://luelista.github.io/pre_workbench/)
+
+Protocol Reverse Engineering Workbench is a software to support researchers in reverse engineering protocols and documenting the results. It supports various sources to import protocol traffic from, helps the discovery process by displaying different views and heuristic-based highlighting on data, and aids in documenting and sharing findings.
+
+PRE Workbench is a Python software and uses the ADS PyQt integration.
+
+[read more...](https://luelista.github.io/pre_workbench/)
+
+[](https://youtu.be/U3op5UreV1Q)
+
+### [RDE – Robox Development Environment](https://www.robox.it/en/product/rde-robox-development-environment/)
+
+This software is a development environment for PAC (Programmable Automation Controllers)
+from ROBOX. It offers a lot of tools to write, compile and debug machine control
+and application software. The Advanced Docking System helps to organize all the tools and
+windows (Project window, Shell window, Monitor windows, Oscilloscope window...)
+on the screen to provide a easy to use, highly configurable and visual pleasing
+development experience.
+
+[read more...](https://www.robox.it/en/product/rde-robox-development-environment/)
+
+
+
+### [ResInsight](https://www.ceetronsolutions.com/projects/resinsight)
+
+ResInsight as a software from Ceetron Solutions for visualization of oil and
+gas reservoir simulation data. It allows reservoir models, simulation results,
+and measurements to be visualized with very high performance. Optimized use of
+graphics technology and simultaneous processing on multiple CPU cores have been
+vital to enhance the performance and capacity of ResInsight for large data sets.
+The Advanced Docking System has empowered Ceetron to build a much more intuitive
+user interface for its ResInsight users.
+
+[read more...](https://resinsight.org/)
+
+[](https://www.youtube.com/watch?v=HzLaQ1p6AUc)
+
+### [ADTF 3](https://www.digitalwerk.net/adtf/)
+
+The Automotive Data and Time-Triggered Framework was designed as a Rapid Prototyping Toolset, Simulation Framework and Test- and Measurement Tool. It is meant for:
+
+- Developing and testing ADAS and HAD components
+- Recording of vehicle data for visualisation
+- Simulation of complex scenarios in SIL/HIL test environments
+
+The software features time-based processing of multiple data streams and graphical editing of dynamic filter graphs. It also includes an SDK for custom plug-ins and reusable components, as well as components for data visualization in both 2D and 3D. This is was the
+[manual](https://support.digitalwerk.net/adtf/v3/adtf_html/page_adtf_xsystem_plugin.html)
+says about the switch to Qt Advanced Docking:
+
+> After several minor improvements the Qt5 ADTF XSystem uses the Advanced Docking System for Qt since ADTF 3.10.0 for more convenience and usability regarding layouting, docking and embedding several widgets.
+
+[read more...](https://support.digitalwerk.net/adtf/v3/adtf_html/index.html)
+
+
+
+### [DREAM.3D NX](https://github.com/BlueQuartzSoftware/DREAM3D)
+
+DREAM.3D *(Digital Representation Environment for Analysis of Materials in 3D)* is an open source, cross-platform and modular, software suite that allows users to prepare, reconstruct, quantify, instantiate, and mesh, multidimensional, multimodal microstructural data, as well as many other applications.
+
+[BlueQuartz Software](http://www.bluequartz.net/) is currently completely rewriting the DREAM.3D application. For the upcoming version **[DREAM3D NX](http://www.dream3d.io/)** they improved the UI by using the Advanced Docking System. An [early version](http://www.dream3d.io/) of **DREAM3D NX** with ADS is already available to any user who would like to take the brand new version out for a spin.
+
+
+
+[read more...](http://dream3d.bluequartz.net/)
+
+### [LabPlot](https://labplot.kde.org/)
+
+KDE LabPlot is the ultimate free, open source and cross-platform tool for scientists, engineers, and students who need to analyze and visualize data. With its intuitive interface and powerful features, you can create stunning plots and diagrams with ease. Whether you're working with CSV, FITS, or HDF5 data, KDE LabPlot makes it simple to import and analyze your data.
+
+The LabPlot project recently switched to the Qt Advanced Docking System for their user interface. This switch represents a significant improvement to the LabPlot software, allowing users to create and manage complex data visualization layouts with ease.
+
+
+
+[read more...](https://labplot.kde.org/)
+
+## Alternative Docking System Implementations
+
+If this Qt Advanced Docking System does not fit to your needs you may consider some of the alternative docking system solutions for Qt.
+
+### KDDockWidgets
+
+This is an advanced docking framework for Qt from [KDAB](https://www.kdab.com/). The interesting thing is, that they separated GUI code from logic, so they can easily provide a QtQuick backend in the future.
+
+- [Blog post about KDDockWidgets](https://www.kdab.com/kddockwidgets/)
+- [GitHub project](https://github.com/KDAB/KDDockWidgets)
+
+**License:** dual-licensed, available under both commercial and GPL license.
+
+### QtitanDocking
+
+This is a commercial component from [Developer Machines](https://www.devmachines.com/) for Qt Framework that allows to create a Microsoft like dockable user interface. They also offer a lot of other interesting and useful components for Qt. The library is available
+
+- [Product page](https://www.devmachines.com/qtitandocking-overview.html)
+
+**License:** Commercial license
+
+### DockingPanes
+
+DockingPanes is a library for Qt Widgets that implements docking windows that have the look and feel of Visual Studio. It provides a simple API which allows an application to make use of docking windows with a few calls.
+
+- [GitHub project](https://github.com/KestrelRadarSensors/dockingpanes)
+
+**License:** GPL
diff --git a/QtADS/ads.pri b/QtADS/ads.pri
new file mode 100644
index 0000000..ddfb8a1
--- /dev/null
+++ b/QtADS/ads.pri
@@ -0,0 +1,28 @@
+
+CONFIG(debug, debug|release){
+ win32-g++ {
+ versionAtLeast(QT_VERSION, 5.15.0) {
+ LIBS += -lqtadvanceddocking
+ }
+ else {
+ LIBS += -lqtadvanceddockingd
+ }
+ }
+ else:msvc {
+ LIBS += -lqtadvanceddockingd
+ }
+ else:mac {
+ LIBS += -lqtadvanceddocking_debug
+ }
+ else {
+ LIBS += -lqtadvanceddocking
+ }
+}
+else{
+ LIBS += -lqtadvanceddocking
+}
+
+
+unix:!macx {
+ LIBS += -lxcb
+}
diff --git a/QtADS/ads.pro b/QtADS/ads.pro
new file mode 100644
index 0000000..c532407
--- /dev/null
+++ b/QtADS/ads.pro
@@ -0,0 +1,9 @@
+TEMPLATE = subdirs
+
+SUBDIRS = \
+ src \
+ demo \
+ examples
+
+demo.depends = src
+examples.depends = src
diff --git a/QtADS/adsConfig.cmake b/QtADS/adsConfig.cmake
new file mode 100644
index 0000000..542e5c9
--- /dev/null
+++ b/QtADS/adsConfig.cmake
@@ -0,0 +1,5 @@
+include(CMakeFindDependencyMacro)
+find_dependency(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
+find_dependency(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
+find_dependency(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
+include("${CMAKE_CURRENT_LIST_DIR}/adsTargets.cmake")
\ No newline at end of file
diff --git a/QtADS/cmake/modules/GetGitRevisionDescription.cmake b/QtADS/cmake/modules/GetGitRevisionDescription.cmake
new file mode 100644
index 0000000..a9ad77b
--- /dev/null
+++ b/QtADS/cmake/modules/GetGitRevisionDescription.cmake
@@ -0,0 +1,172 @@
+# - Returns a version string from Git
+#
+# These functions force a re-configure on each git commit so that you can
+# trust the values of the variables in your build system.
+#
+# get_git_head_revision( [ ...])
+#
+# Returns the refspec and sha hash of the current head revision
+#
+# git_describe( [ ...])
+#
+# Returns the results of git describe on the source tree, and adjusting
+# the output so that it tests false if an error occurs.
+#
+# git_get_exact_tag( [ ...])
+#
+# Returns the results of git describe --exact-match on the source tree,
+# and adjusting the output so that it tests false if there was no exact
+# matching tag.
+#
+# git_local_changes()
+#
+# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
+# Uses the return code of "git diff-index --quiet HEAD --".
+# Does not regard untracked files.
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+if(__get_git_revision_description)
+ return()
+endif()
+set(__get_git_revision_description YES)
+
+# We must run the following at "include" time, not at function call time,
+# to find the path to this module rather than the path to a calling list file
+get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+function(get_git_head_revision _refspecvar _hashvar)
+ set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(GIT_DIR "${GIT_PARENT_DIR}/.git")
+ while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
+ set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
+ get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
+ if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
+ # We have reached the root directory, we are not in git
+ set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
+ set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
+ return()
+ endif()
+ set(GIT_DIR "${GIT_PARENT_DIR}/.git")
+ endwhile()
+ # check if this is a submodule
+ if(NOT IS_DIRECTORY ${GIT_DIR})
+ file(READ ${GIT_DIR} submodule)
+ string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
+ get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
+ get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
+ endif()
+ if(NOT IS_DIRECTORY "${GIT_DIR}")
+ file(READ ${GIT_DIR} worktree)
+ string(REGEX REPLACE "gitdir: (.*)worktrees(.*)\n$" "\\1" GIT_DIR ${worktree})
+ endif()
+ set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
+ if(NOT EXISTS "${GIT_DATA}")
+ file(MAKE_DIRECTORY "${GIT_DATA}")
+ endif()
+
+ if(NOT EXISTS "${GIT_DIR}/HEAD")
+ return()
+ endif()
+ set(HEAD_FILE "${GIT_DATA}/HEAD")
+ configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
+
+ configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
+ "${GIT_DATA}/grabRef.cmake"
+ @ONLY)
+ include("${GIT_DATA}/grabRef.cmake")
+
+ set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
+ set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
+endfunction()
+
+function(git_describe _var)
+ if(NOT GIT_FOUND)
+ find_package(Git QUIET)
+ endif()
+ get_git_head_revision(refspec hash)
+ if(NOT GIT_FOUND)
+ set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
+ return()
+ endif()
+ if(NOT hash)
+ set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
+ return()
+ endif()
+
+ # TODO sanitize
+ #if((${ARGN}" MATCHES "&&") OR
+ # (ARGN MATCHES "||") OR
+ # (ARGN MATCHES "\\;"))
+ # message("Please report the following error to the project!")
+ # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
+ #endif()
+
+ #message(STATUS "Arguments to execute_process: ${ARGN}")
+
+ execute_process(COMMAND
+ "${GIT_EXECUTABLE}"
+ describe
+ ${hash}
+ ${ARGN}
+ WORKING_DIRECTORY
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ RESULT_VARIABLE
+ res
+ OUTPUT_VARIABLE
+ out
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT res EQUAL 0)
+ set(out "${out}-${res}-NOTFOUND")
+ endif()
+
+ set(${_var} "${out}" PARENT_SCOPE)
+endfunction()
+
+function(git_get_exact_tag _var)
+ git_describe(out --exact-match ${ARGN})
+ set(${_var} "${out}" PARENT_SCOPE)
+endfunction()
+
+function(git_local_changes _var)
+ if(NOT GIT_FOUND)
+ find_package(Git QUIET)
+ endif()
+ get_git_head_revision(refspec hash)
+ if(NOT GIT_FOUND)
+ set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
+ return()
+ endif()
+ if(NOT hash)
+ set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
+ return()
+ endif()
+
+ execute_process(COMMAND
+ "${GIT_EXECUTABLE}"
+ diff-index --quiet HEAD --
+ WORKING_DIRECTORY
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ RESULT_VARIABLE
+ res
+ OUTPUT_VARIABLE
+ out
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(res EQUAL 0)
+ set(${_var} "CLEAN" PARENT_SCOPE)
+ else()
+ set(${_var} "DIRTY" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/QtADS/cmake/modules/GetGitRevisionDescription.cmake.in b/QtADS/cmake/modules/GetGitRevisionDescription.cmake.in
new file mode 100644
index 0000000..6d8b708
--- /dev/null
+++ b/QtADS/cmake/modules/GetGitRevisionDescription.cmake.in
@@ -0,0 +1,41 @@
+#
+# Internal file for GetGitRevisionDescription.cmake
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+set(HEAD_HASH)
+
+file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
+
+string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
+if(HEAD_CONTENTS MATCHES "ref")
+ # named branch
+ string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
+ if(EXISTS "@GIT_DIR@/${HEAD_REF}")
+ configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+ else()
+ configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
+ file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
+ if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
+ set(HEAD_HASH "${CMAKE_MATCH_1}")
+ endif()
+ endif()
+else()
+ # detached HEAD
+ configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
+endif()
+
+if(NOT HEAD_HASH)
+ file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
+ string(STRIP "${HEAD_HASH}" HEAD_HASH)
+endif()
diff --git a/QtADS/demo/CMakeLists.txt b/QtADS/demo/CMakeLists.txt
new file mode 100644
index 0000000..f40bfc9
--- /dev/null
+++ b/QtADS/demo/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_demo VERSION ${VERSION_SHORT})
+
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets Quick QuickWidgets REQUIRED)
+if(WIN32 AND QT_VERSION_MAJOR LESS 6)
+ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS AxContainer REQUIRED)
+endif()
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(ads_demo_SRCS
+ main.cpp
+ MainWindow.cpp
+ mainwindow.ui
+ StatusDialog.cpp
+ StatusDialog.ui
+ ImageViewer.cpp
+ RenderWidget.cpp
+ demo.qrc
+)
+add_executable(AdvancedDockingSystemDemo WIN32 ${ads_demo_SRCS})
+target_include_directories(AdvancedDockingSystemDemo PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src")
+target_link_libraries(AdvancedDockingSystemDemo PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets
+ Qt${QT_VERSION_MAJOR}::Quick
+ Qt${QT_VERSION_MAJOR}::QuickWidgets)
+if(WIN32 AND QT_VERSION_MAJOR LESS 6)
+ target_link_libraries(AdvancedDockingSystemDemo PUBLIC Qt${QT_VERSION_MAJOR}::AxContainer)
+endif()
+target_link_libraries(AdvancedDockingSystemDemo PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+set_target_properties(AdvancedDockingSystemDemo PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Demo"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
+#if(BUILD_STATIC)
+# target_compile_definitions(AdvancedDockingSystemDemo PRIVATE ADS_STATIC)
+#endif()
+
diff --git a/QtADS/demo/ImageViewer.cpp b/QtADS/demo/ImageViewer.cpp
new file mode 100644
index 0000000..073be1f
--- /dev/null
+++ b/QtADS/demo/ImageViewer.cpp
@@ -0,0 +1,280 @@
+//============================================================================
+/// \file ImageViewer.cpp
+/// \author Uwe Kindler
+/// \date 04.11.2022
+/// \brief Implementation of CImageViewer
+//============================================================================
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include "ImageViewer.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "RenderWidget.h"
+
+/**
+ * Private image viewer data
+ */
+struct ImageViewerPrivate
+{
+ CImageViewer* _this;
+ CRenderWidget* RenderWidget;///< renders the image to screen
+ bool AutoFit;///< automatically fit image to window size on resize events
+ QSize ImageSize;///< stores the image size to detect image size changes
+ QPoint MouseMoveStartPos;///< for calculation of mouse move vector
+ QLabel* ScalingLabel;///< label displays scaling factor
+ QList OverlayTools;///< list of tool widget to overlay
+
+ ImageViewerPrivate(CImageViewer* _public) : _this(_public) {}
+};
+
+
+
+//============================================================================
+CImageViewer::CImageViewer(QWidget *parent)
+ : Super(parent),
+ d(new ImageViewerPrivate(this))
+{
+ d->AutoFit = true;
+ d->RenderWidget = new CRenderWidget(this);
+
+ this->setBackgroundRole(QPalette::Light);
+ this->setAlignment(Qt::AlignCenter);
+ this->setWidget(d->RenderWidget);
+ this->createActions();
+ this->setMouseTracking(false); // only produce mouse move events if mouse button pressed
+}
+
+
+//============================================================================
+CImageViewer::~CImageViewer()
+{
+ delete d;
+}
+
+
+//============================================================================
+bool CImageViewer::loadFile(const QString& fileName)
+{
+ QImageReader reader(fileName);
+ reader.setAutoTransform(true);
+ const QImage newImage = reader.read();
+ if (newImage.isNull())
+ {
+ QMessageBox::information(this, QGuiApplication::applicationDisplayName(),
+ tr("Cannot load %1: %2")
+ .arg(QDir::toNativeSeparators(fileName), reader.errorString()));
+ return false;
+ }
+
+ setImage(newImage);
+ setWindowFilePath(fileName);
+ return true;
+}
+
+
+//===========================================================================
+void CImageViewer::setImage(const QImage &newImage)
+{
+ d->RenderWidget->showImage(newImage);
+ this->adjustDisplaySize(newImage);
+}
+
+
+//============================================================================
+void CImageViewer::adjustDisplaySize(const QImage& Image)
+{
+ if (d->ImageSize == Image.size())
+ {
+ return;
+ }
+ d->ImageSize = Image.size();
+ if (d->AutoFit)
+ {
+ this->fitToWindow();
+ }
+}
+
+
+//===========================================================================
+static void initializeImageFileDialog(QFileDialog &dialog, QFileDialog::AcceptMode acceptMode)
+{
+ static bool firstDialog = true;
+
+ if (firstDialog) {
+ firstDialog = false;
+ const QStringList picturesLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
+ dialog.setDirectory(picturesLocations.isEmpty() ? QDir::currentPath() : picturesLocations.last());
+ }
+
+ QStringList mimeTypeFilters;
+ const QByteArrayList supportedMimeTypes = acceptMode == QFileDialog::AcceptOpen
+ ? QImageReader::supportedMimeTypes() : QImageWriter::supportedMimeTypes();
+ for (const QByteArray &mimeTypeName : supportedMimeTypes)
+ mimeTypeFilters.append(mimeTypeName);
+ mimeTypeFilters.sort();
+ dialog.setMimeTypeFilters(mimeTypeFilters);
+ dialog.selectMimeTypeFilter("image/jpeg");
+ if (acceptMode == QFileDialog::AcceptSave)
+ dialog.setDefaultSuffix("jpg");
+}
+
+
+//===========================================================================
+void CImageViewer::open()
+{
+ QFileDialog dialog(this, tr("Open File"));
+ initializeImageFileDialog(dialog, QFileDialog::AcceptOpen);
+
+ while (dialog.exec() == QDialog::Accepted && !loadFile(dialog.selectedFiles().first())) {}
+}
+
+
+//===========================================================================
+void CImageViewer::createActions()
+{
+ QAction* a;
+ a = new QAction(tr("&Open..."));
+ a->setIcon(QIcon(":/adsdemo/images/perm_media.svg"));
+ connect(a, &QAction::triggered, this, &CImageViewer::open);
+ a->setShortcut(QKeySequence::Open);;
+ this->addAction(a);
+
+ a = new QAction(tr("Fit on Screen"));
+ a->setIcon(QIcon(":/adsdemo/images/zoom_out_map.svg"));
+ connect(a, &QAction::triggered, this, &CImageViewer::fitToWindow);
+ this->addAction(a);
+
+ a = new QAction(tr("Actual Pixels"));
+ a->setIcon(QIcon(":/adsdemo/images/find_in_page.svg"));
+ connect(a, &QAction::triggered, this, &CImageViewer::normalSize);
+ this->addAction(a);
+
+ a = new QAction(this);
+ a->setSeparator(true);
+ this->addAction(a);
+
+ a = new QAction(tr("Zoom In (25%)"));
+ a->setIcon(QIcon(":/adsdemo/images/zoom_in.svg"));
+ connect(a, &QAction::triggered, this, &CImageViewer::zoomIn);
+ this->addAction(a);
+
+ a = new QAction(tr("Zoom Out (25%)"));
+ a->setIcon(QIcon(":/adsdemo/images/zoom_out.svg"));
+ connect(a, &QAction::triggered, this, &CImageViewer::zoomOut);
+ this->addAction(a);
+
+ this->setContextMenuPolicy(Qt::ActionsContextMenu);
+}
+
+
+//===========================================================================
+void CImageViewer::zoomIn()
+{
+ d->AutoFit = false;
+ d->RenderWidget->zoomIn();
+}
+
+
+//===========================================================================
+void CImageViewer::zoomOut()
+{
+ d->AutoFit = false;
+ d->RenderWidget->zoomOut();
+}
+
+
+//===========================================================================
+void CImageViewer::normalSize()
+{
+ d->AutoFit = false;
+ d->RenderWidget->normalSize();
+}
+
+
+//===========================================================================
+void CImageViewer::fitToWindow()
+{
+ d->AutoFit = true;
+ d->RenderWidget->scaleToSize(this->maximumViewportSize());
+}
+
+
+//============================================================================
+void CImageViewer::resizeEvent(QResizeEvent* ResizeEvent)
+{
+ Super::resizeEvent(ResizeEvent);
+ if (d->AutoFit)
+ {
+ this->fitToWindow();
+ }
+}
+
+
+//============================================================================
+void CImageViewer::mousePressEvent(QMouseEvent* Event)
+{
+ d->RenderWidget->setCursor(Qt::ClosedHandCursor);
+ d->MouseMoveStartPos = Event->pos();
+ Super::mousePressEvent(Event);
+}
+
+
+//============================================================================
+void CImageViewer::mouseReleaseEvent(QMouseEvent* Event)
+{
+ d->RenderWidget->setCursor(Qt::OpenHandCursor);
+ Super::mouseReleaseEvent(Event);
+}
+
+
+//============================================================================
+void CImageViewer::mouseMoveEvent(QMouseEvent* Event)
+{
+ QPoint MoveVector = Event->pos() - d->MouseMoveStartPos;
+ d->MouseMoveStartPos = Event->pos();
+ horizontalScrollBar()->setValue(horizontalScrollBar()->value()
+ - MoveVector.x());
+ verticalScrollBar()->setValue(verticalScrollBar()->value() - MoveVector.y());
+}
+
+
+//============================================================================
+void CImageViewer::wheelEvent(QWheelEvent* Event)
+{
+ double numDegrees = Event->angleDelta().y() / 8;
+ double numSteps = numDegrees / 15;
+ d->AutoFit = false;
+ double Zoom;
+ if (numSteps < 0)
+ {
+ Zoom = pow(0.9, 0 - numSteps);
+ }
+ else
+ {
+ Zoom = pow(1.10, numSteps);
+ }
+ d->RenderWidget->zoomByValue(Zoom);
+}
+
+#include "moc_ImageViewer.cpp"
+//---------------------------------------------------------------------------
+// EOF ImageViewer.cpp
diff --git a/QtADS/demo/ImageViewer.h b/QtADS/demo/ImageViewer.h
new file mode 100644
index 0000000..37bc8cb
--- /dev/null
+++ b/QtADS/demo/ImageViewer.h
@@ -0,0 +1,88 @@
+#ifndef ImageViewerH
+#define ImageViewerH
+//============================================================================
+/// \file ImageViewer.h
+/// \author Uwe Kindler
+/// \date 04.11.2022
+/// \brief Declaration of CImageViewer
+//============================================================================
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+QT_END_NAMESPACE
+
+
+struct ImageViewerPrivate;
+
+/**
+ * Tiny simple image viewer for showing images in demo
+ */
+class CImageViewer : public QScrollArea
+{
+ Q_OBJECT
+public:
+ using Super = QScrollArea;
+
+ explicit CImageViewer(QWidget *parent = nullptr);
+ virtual ~CImageViewer();
+
+ bool loadFile(const QString& Filename);
+ void setImage(const QImage &newImage);
+
+public Q_SLOTS:
+ void open();
+ void zoomIn();
+ void zoomOut();
+ void normalSize();
+ void fitToWindow();
+
+protected:
+ /**
+ * @brief Reimplemented from QScrollArea to adjust image scaling if m_AutoFit is
+ * true.
+ */
+ virtual void resizeEvent(QResizeEvent* ResizeEvent);
+
+ /**
+ * @brief Handle mouse press events.
+ */
+ virtual void mousePressEvent(QMouseEvent* Event);
+
+ /**
+ * @brief Handles mouse release events.
+ */
+ virtual void mouseReleaseEvent(QMouseEvent* Event);
+
+ /**
+ * @brief Handle mouse move events.
+ */
+ virtual void mouseMoveEvent(QMouseEvent* Event);
+
+ /**
+ * @brief Use mouse wheel to change scaling of the image.
+ */
+ virtual void wheelEvent(QWheelEvent* Event);
+
+private:
+ /**
+ * @brief Create the wiget actions.
+ */
+ void createActions();
+
+ /**
+ * @brief Adjust size of render widget in case of image size change.
+ * @param[in] Image The new image that may have a different image size.
+ */
+ void adjustDisplaySize(const QImage& Image);
+
+ ImageViewerPrivate* d;
+ friend ImageViewerPrivate;
+};
+
+//---------------------------------------------------------------------------
+#endif // ImageViewerH
diff --git a/QtADS/demo/MainWindow.cpp b/QtADS/demo/MainWindow.cpp
new file mode 100644
index 0000000..cde5492
--- /dev/null
+++ b/QtADS/demo/MainWindow.cpp
@@ -0,0 +1,1057 @@
+
+/*******************************************************************************
+** Qt Advanced Docking System
+** Copyright (C) 2017 Uwe Kindler
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License as published by the Free Software Foundation; either
+** version 2.1 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public
+** License along with this library; If not, see .
+******************************************************************************/
+
+
+//============================================================================
+/// \file MainWindow.cpp
+/// \author Uwe Kindler
+/// \date 13.02.2018
+/// \brief Implementation of CMainWindow demo class
+//============================================================================
+
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include
+#include "ui_mainwindow.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+#include
+#endif
+
+#ifdef Q_OS_WIN
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#include
+#endif
+#endif
+
+#include "DockManager.h"
+#include "DockWidget.h"
+#include "DockAreaWidget.h"
+#include "DockAreaTitleBar.h"
+#include "DockAreaTabBar.h"
+#include "FloatingDockContainer.h"
+#include "DockComponentsFactory.h"
+#include "StatusDialog.h"
+#include "DockSplitter.h"
+#include "ImageViewer.h"
+
+
+
+/**
+ * Returns a random number from 0 to highest - 1
+ */
+int randomNumberBounded(int highest)
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
+ return QRandomGenerator::global()->bounded(highest);
+#else
+ qsrand(QTime::currentTime().msec());
+ return qrand() % highest;
+#endif
+}
+
+
+/**
+ * Function returns a features string with closable (c), movable (m) and floatable (f)
+ * features. i.e. The following string is for a not closable but movable and floatable
+ * widget: c- m+ f+
+ */
+static QString featuresString(ads::CDockWidget* DockWidget)
+{
+ auto f = DockWidget->features();
+ return QString("c%1 m%2 f%3")
+ .arg(f.testFlag(ads::CDockWidget::DockWidgetClosable) ? "+" : "-")
+ .arg(f.testFlag(ads::CDockWidget::DockWidgetMovable) ? "+" : "-")
+ .arg(f.testFlag(ads::CDockWidget::DockWidgetFloatable) ? "+" : "-");
+}
+
+
+/**
+ * Appends the string returned by featuresString() to the window title of
+ * the given DockWidget
+ */
+static void appendFeaturStringToWindowTitle(ads::CDockWidget* DockWidget)
+{
+ DockWidget->setWindowTitle(DockWidget->windowTitle()
+ + QString(" (%1)").arg(featuresString(DockWidget)));
+}
+
+/**
+ * Helper function to create an SVG icon
+ */
+static QIcon svgIcon(const QString& File)
+{
+ // This is a workaround, because in item views SVG icons are not
+ // properly scaled and look blurry or pixelate
+ QIcon SvgIcon(File);
+ SvgIcon.addPixmap(SvgIcon.pixmap(92));
+ return SvgIcon;
+}
+
+
+//============================================================================
+class CCustomComponentsFactory : public ads::CDockComponentsFactory
+{
+public:
+ using Super = ads::CDockComponentsFactory;
+ ads::CDockAreaTitleBar* createDockAreaTitleBar(ads::CDockAreaWidget* DockArea) const override
+ {
+ auto TitleBar = new ads::CDockAreaTitleBar(DockArea);
+ auto CustomButton = new QToolButton(DockArea);
+ CustomButton->setToolTip(QObject::tr("Help"));
+ CustomButton->setIcon(svgIcon(":/adsdemo/images/help_outline.svg"));
+ CustomButton->setAutoRaise(true);
+ int Index = TitleBar->indexOf(TitleBar->button(ads::TitleBarButtonTabsMenu));
+ TitleBar->insertWidget(Index + 1, CustomButton);
+ return TitleBar;
+ }
+};
+
+
+
+//===========================================================================
+/**
+ * Custom QTableWidget with a minimum size hint to test CDockWidget
+ * setMinimumSizeHintMode() function of CDockWidget
+ */
+class CMinSizeTableWidget : public QTableWidget
+{
+public:
+ using QTableWidget::QTableWidget;
+ virtual QSize minimumSizeHint() const override
+ {
+ return QSize(300, 100);
+ }
+};
+
+
+
+//============================================================================
+/**
+ * Private data class pimpl
+ */
+struct MainWindowPrivate
+{
+ CMainWindow* _this;
+ Ui::MainWindow ui;
+ QAction* SavePerspectiveAction = nullptr;
+ QWidgetAction* PerspectiveListAction = nullptr;
+ QComboBox* PerspectiveComboBox = nullptr;
+ ads::CDockManager* DockManager = nullptr;
+ ads::CDockWidget* WindowTitleTestDockWidget = nullptr;
+ QPointer LastDockedEditor;
+ QPointer LastCreatedFloatingEditor;
+
+ MainWindowPrivate(CMainWindow* _public) : _this(_public) {}
+
+ /**
+ * Creates the toolbar actions
+ */
+ void createActions();
+
+ /**
+ * Fill the dock manager with dock widgets
+ */
+ void createContent();
+
+ /**
+ * Saves the dock manager state and the main window geometry
+ */
+ void saveState();
+
+ /**
+ * Save the list of perspectives
+ */
+ void savePerspectives();
+
+ /**
+ * Restores the dock manager state
+ */
+ void restoreState();
+
+ /**
+ * Restore the perspective listo of the dock manager
+ */
+ void restorePerspectives();
+
+ /**
+ * Creates a dock widget with a file system tree view
+ */
+ ads::CDockWidget* createFileSystemTreeDockWidget()
+ {
+ static int FileSystemCount = 0;
+ QTreeView* w = new QTreeView();
+ w->setFrameShape(QFrame::NoFrame);
+ QFileSystemModel* m = new QFileSystemModel(w);
+ m->setRootPath(QDir::currentPath());
+ w->setModel(m);
+ w->setRootIndex(m->index(QDir::currentPath()));
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1")
+ .arg(FileSystemCount++));
+ DockWidget->setWidget(w);
+ DockWidget->setIcon(svgIcon(":/adsdemo/images/folder_open.svg"));
+ ui.menuView->addAction(DockWidget->toggleViewAction());
+ // We disable focus to test focus highlighting if the dock widget content
+ // does not support focus
+ w->setFocusPolicy(Qt::NoFocus);
+ auto ToolBar = DockWidget->createDefaultToolBar();
+ ToolBar->addAction(ui.actionSaveState);
+ ToolBar->addAction(ui.actionRestoreState);
+ return DockWidget;
+ }
+
+ /**
+ * Create a dock widget with a QCalendarWidget
+ */
+ ads::CDockWidget* createCalendarDockWidget()
+ {
+ static int CalendarCount = 0;
+ QCalendarWidget* w = new QCalendarWidget();
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
+ // The following lines are for testing the setWidget() and takeWidget()
+ // functionality
+ DockWidget->setWidget(w);
+ DockWidget->setWidget(w); // what happens if we set a widget if a widget is already set
+ DockWidget->takeWidget(); // we remove the widget
+ DockWidget->setWidget(w); // and set the widget again - there should be no error
+ DockWidget->setToggleViewActionMode(ads::CDockWidget::ActionModeShow);
+ DockWidget->setIcon(svgIcon(":/adsdemo/images/date_range.svg"));
+ ui.menuView->addAction(DockWidget->toggleViewAction());
+ auto ToolBar = DockWidget->createDefaultToolBar();
+ ToolBar->addAction(ui.actionSaveState);
+ ToolBar->addAction(ui.actionRestoreState);
+ // For testing all calendar dock widgets have a the tool button style
+ // Qt::ToolButtonTextUnderIcon
+ DockWidget->setToolBarStyleSource(ads::CDockWidget::ToolBarStyleFromDockWidget);
+ DockWidget->setToolBarStyle(Qt::ToolButtonTextUnderIcon, ads::CDockWidget::StateFloating);
+ return DockWidget;
+ }
+
+
+ /**
+ * Create dock widget with a text label
+ */
+ ads::CDockWidget* createLongTextLabelDockWidget()
+ {
+ static int LabelCount = 0;
+ QLabel* l = new QLabel();
+ l->setWordWrap(true);
+ l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l->setText(QString("Label %1 %2 - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "
+ "Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque "
+ "penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
+ "Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. "
+ "Nulla consequat massa quis enim. Donec pede justo, fringilla vel, "
+ "aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, "
+ "imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede "
+ "mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum "
+ "semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, "
+ "porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, "
+ "dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla "
+ "ut metus varius laoreet.")
+ .arg(LabelCount)
+ .arg(QTime::currentTime().toString("hh:mm:ss:zzz")));
+
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++));
+ DockWidget->setWidget(l);
+ DockWidget->setIcon(svgIcon(":/adsdemo/images/font_download.svg"));
+ ui.menuView->addAction(DockWidget->toggleViewAction());
+ return DockWidget;
+ }
+
+
+ /**
+ * Creates as imple editor widget
+ */
+ ads::CDockWidget* createEditorWidget()
+ {
+ static int EditorCount = 0;
+ QPlainTextEdit* w = new QPlainTextEdit();
+ w->setPlaceholderText("This is an editor. If you close the editor, it will be "
+ "deleted. Enter your text here.");
+ w->setStyleSheet("border: none");
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Editor %1").arg(EditorCount++));
+ DockWidget->setWidget(w);
+ DockWidget->setIcon(svgIcon(":/adsdemo/images/edit.svg"));
+ DockWidget->setFeature(ads::CDockWidget::CustomCloseHandling, true);
+ ui.menuView->addAction(DockWidget->toggleViewAction());
+
+ QMenu* OptionsMenu = new QMenu(DockWidget);
+ OptionsMenu->setTitle(QObject::tr("Options"));
+ OptionsMenu->setToolTip(OptionsMenu->title());
+ OptionsMenu->setIcon(svgIcon(":/adsdemo/images/custom-menu-button.svg"));
+ auto MenuAction = OptionsMenu->menuAction();
+ // The object name of the action will be set for the QToolButton that
+ // is created in the dock area title bar. You can use this name for CSS
+ // styling
+ MenuAction->setObjectName("optionsMenu");
+ DockWidget->setTitleBarActions({OptionsMenu->menuAction()});
+ auto a = OptionsMenu->addAction(QObject::tr("Clear Editor"));
+ w->connect(a, SIGNAL(triggered()), SLOT(clear()));
+
+ return DockWidget;
+ }
+
+ /**
+ * Creates a simply image viewr
+ */
+ ads::CDockWidget* createImageViewer()
+ {
+ static int ImageViewerCount = 0;
+ auto w = new CImageViewer();
+ auto ImageIndex = randomNumberBounded(4);
+ auto FileName = ":adsdemo/images/ads_logo.svg";
+
+ // Pick a random image from a number of images
+ switch (ImageIndex)
+ {
+ case 0: FileName = ":adsdemo/images/ads_tile_blue.svg"; break;
+ case 1: FileName = ":adsdemo/images/ads_tile_blue_light.svg"; break;
+ case 2: FileName = ":adsdemo/images/ads_tile_green.svg"; break;
+ case 3: FileName = ":adsdemo/images/ads_tile_orange.svg"; break;
+ }
+
+ auto Result = w->loadFile(FileName);
+ qDebug() << "loadFile result: " << Result;
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Image Viewer %1").arg(ImageViewerCount++));
+ DockWidget->setIcon(svgIcon(":/adsdemo/images/photo.svg"));
+ DockWidget->setWidget(w,ads:: CDockWidget::ForceNoScrollArea);
+ auto ToolBar = DockWidget->createDefaultToolBar();
+ ToolBar->addActions(w->actions());
+ return DockWidget;
+ }
+
+ /**
+ * Create a table widget
+ */
+ ads::CDockWidget* createTableWidget()
+ {
+ static int TableCount = 0;
+ auto w = new CMinSizeTableWidget();
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Table %1").arg(TableCount++));
+ static int colCount = 5;
+ static int rowCount = 30;
+ w->setColumnCount(colCount);
+ w->setRowCount(rowCount);
+ for (int col = 0; col < colCount; ++col)
+ {
+ w->setHorizontalHeaderItem(col, new QTableWidgetItem(QString("Col %1").arg(col+1)));
+ for (int row = 0; row < rowCount; ++row)
+ {
+ w->setItem(row, col, new QTableWidgetItem(QString("T %1-%2").arg(row + 1).arg(col+1)));
+ }
+ }
+ DockWidget->setWidget(w);
+ DockWidget->setIcon(svgIcon(":/adsdemo/images/grid_on.svg"));
+ DockWidget->setMinimumSizeHintMode(ads::CDockWidget::MinimumSizeHintFromContent);
+ auto ToolBar = DockWidget->createDefaultToolBar();
+ auto Action = ToolBar->addAction(svgIcon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen");
+ QObject::connect(Action, &QAction::triggered, [=]()
+ {
+ if (DockWidget->isFullScreen())
+ {
+ DockWidget->showNormal();
+ }
+ else
+ {
+ DockWidget->showFullScreen();
+ }
+ });
+ ui.menuView->addAction(DockWidget->toggleViewAction());
+ return DockWidget;
+ }
+
+ /**
+ * Create QQuickWidget for test for OpenGL and QQuick
+ */
+ ads::CDockWidget *createQQuickWidget()
+ {
+ QQuickWidget *widget = new QQuickWidget();
+ ads::CDockWidget *dockWidget = new ads::CDockWidget("Quick");
+ dockWidget->setWidget(widget);
+ return dockWidget;
+ }
+
+
+#ifdef Q_OS_WIN
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
+ /**
+ * Creates an ActiveX widget on windows
+ */
+ ads::CDockWidget* createActiveXWidget(QWidget* parent = nullptr)
+ {
+ static int ActiveXCount = 0;
+ QAxWidget* w = new QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent);
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Active X %1").arg(ActiveXCount++));
+ DockWidget->setWidget(w);
+ ui.menuView->addAction(DockWidget->toggleViewAction());
+ return DockWidget;
+ }
+#endif
+#endif
+};
+
+//============================================================================
+void MainWindowPrivate::createContent()
+{
+ // Test container docking
+ auto DockWidget = createCalendarDockWidget();
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
+ auto SpecialDockArea = DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
+
+ // For this Special Dock Area we want to avoid dropping on the center of it (i.e. we don't want this widget to be ever tabbified):
+ {
+ //SpecialDockArea->setAllowedAreas(ads::OuterDockAreas);
+ SpecialDockArea->setAllowedAreas({ads::LeftDockWidgetArea, ads::RightDockWidgetArea, ads::TopDockWidgetArea}); // just for testing
+ }
+
+ DockWidget = createLongTextLabelDockWidget();
+ WindowTitleTestDockWidget = DockWidget;
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetFocusable, false);
+ DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
+ auto FileSystemWidget = createFileSystemTreeDockWidget();
+ FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetFloatable, false);
+ appendFeaturStringToWindowTitle(FileSystemWidget);
+ DockManager->addDockWidget(ads::BottomDockWidgetArea, FileSystemWidget);
+
+ FileSystemWidget = createFileSystemTreeDockWidget();
+ FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetMovable, false);
+ FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetFloatable, false);
+ appendFeaturStringToWindowTitle(FileSystemWidget);
+
+ // Test custom factory - we inject a help button into the title bar
+ ads::CDockComponentsFactory::setFactory(new CCustomComponentsFactory());
+ auto TopDockArea = DockManager->addDockWidget(ads::TopDockWidgetArea, FileSystemWidget);
+ // Uncomment the next line if you would like to test the
+ // HideSingleWidgetTitleBar functionality
+ // TopDockArea->setDockAreaFlag(ads::CDockAreaWidget::HideSingleWidgetTitleBar, true);
+ ads::CDockComponentsFactory::resetDefaultFactory();
+
+ // We create a calendar widget and clear all flags to prevent the dock area
+ // from closing
+ DockWidget = createCalendarDockWidget();
+ DockWidget->setTabToolTip(QString("Tab ToolTip\nHodie est dies magna"));
+ auto DockArea = DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, TopDockArea);
+ // Now we create a action to test resizing of DockArea widget
+ auto Action = ui.menuTests->addAction(QString("Resize %1").arg(DockWidget->windowTitle()));
+ QObject::connect(Action, &QAction::triggered, [DockArea]()
+ {
+ // Resizing only works, if the Splitter is visible and has a valid
+ // sizes
+ auto Splitter = ads::internal::findParent(DockArea);
+ if (!Splitter)
+ {
+ return;
+ }
+ // We change the sizes of the splitter that contains the Calendar 1 widget
+ // to resize the dock widget
+ int Width = Splitter->width();
+ Splitter->setSizes({Width * 2/3, Width * 1/3});
+ });
+ DockWidget->setWindowTitle(QString("My " + DockWidget->windowTitle()));
+
+ // Now we add a custom button to the dock area title bar that will create
+ // new editor widgets when clicked
+ auto CustomButton = new QToolButton(DockArea);
+ CustomButton->setToolTip(QObject::tr("Create Editor"));
+ CustomButton->setIcon(svgIcon(":/adsdemo/images/plus.svg"));
+ CustomButton->setAutoRaise(true);
+
+ auto TitleBar = DockArea->titleBar();
+ int Index = TitleBar->indexOf(TitleBar->tabBar());
+ TitleBar->insertWidget(Index + 1, CustomButton);
+ QObject::connect(CustomButton, &QToolButton::clicked, [=]()
+ {
+ auto DockWidget = createEditorWidget();
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
+ DockManager->addDockWidgetTabToArea(DockWidget, DockArea);
+ _this->connect(DockWidget, SIGNAL(closeRequested()), SLOT(onEditorCloseRequested()));
+ });
+
+ // Test dock area docking
+ auto RighDockArea = DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(), TopDockArea);
+ DockWidget = createLongTextLabelDockWidget();
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetPinnable, false);
+ DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget, RighDockArea);
+ auto BottomDockArea = DockManager->addDockWidget(ads::BottomDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
+ DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
+ auto LabelDockWidget = createLongTextLabelDockWidget();
+ DockManager->addDockWidget(ads::CenterDockWidgetArea, LabelDockWidget, BottomDockArea);
+
+ // Tests CustomCloseHandling without DeleteOnClose
+ LabelDockWidget->setFeature(ads::CDockWidget::CustomCloseHandling, true);
+ LabelDockWidget->setWindowTitle(LabelDockWidget->windowTitle() + " [Custom Close]");
+ QObject::connect(LabelDockWidget, &ads::CDockWidget::closeRequested, [LabelDockWidget, this]()
+ {
+ int Result = QMessageBox::question(_this, "Custom Close Request",
+ "Do you really want to close this dock widget?");
+ if (QMessageBox::Yes == Result)
+ {
+ LabelDockWidget->closeDockWidget();
+ }
+ });
+
+ Action = ui.menuTests->addAction(QString("Set %1 Floating").arg(DockWidget->windowTitle()));
+ DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setFloating()));
+ Action = ui.menuTests->addAction(QString("Set %1 As Current Tab").arg(DockWidget->windowTitle()));
+ DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setAsCurrentTab()));
+ Action = ui.menuTests->addAction(QString("Raise %1").arg(DockWidget->windowTitle()));
+ DockWidget->connect(Action, SIGNAL(triggered()), SLOT(raise()));
+
+ // Test hidden floating dock widget
+ DockWidget = createLongTextLabelDockWidget();
+ DockManager->addDockWidgetFloating(DockWidget);
+ DockWidget->toggleView(false);
+
+ // Test visible floating dock widget
+ DockWidget = createCalendarDockWidget();
+ DockManager->addDockWidgetFloating(DockWidget);
+ DockWidget->setWindowTitle(QString("My " + DockWidget->windowTitle()));
+
+
+#ifdef Q_OS_WIN
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
+ DockManager->addDockWidget(ads::CenterDockWidgetArea, createActiveXWidget(), RighDockArea);
+#endif
+#endif
+
+ for (auto DockWidget : DockManager->dockWidgetsMap())
+ {
+ _this->connect(DockWidget, SIGNAL(viewToggled(bool)), SLOT(onViewToggled(bool)));
+ _this->connect(DockWidget, SIGNAL(visibilityChanged(bool)), SLOT(onViewVisibilityChanged(bool)));
+ }
+
+ // Create image viewer
+ DockWidget = createImageViewer();
+ DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
+
+ // Create quick widget
+ DockWidget = createQQuickWidget();
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, true);
+ DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
+}
+
+
+//============================================================================
+void MainWindowPrivate::createActions()
+{
+ ui.toolBar->addAction(ui.actionSaveState);
+ ui.toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ ui.actionSaveState->setIcon(svgIcon(":/adsdemo/images/save.svg"));
+ ui.toolBar->addAction(ui.actionRestoreState);
+ ui.actionRestoreState->setIcon(svgIcon(":/adsdemo/images/restore.svg"));
+
+ ui.toolBar->addSeparator();
+
+ QAction* a = ui.toolBar->addAction("Lock Workspace");
+ a->setIcon(svgIcon(":/adsdemo/images/lock_outline.svg"));
+ a->setCheckable(true);
+ a->setChecked(false);
+ QObject::connect(a, &QAction::triggered, _this, &CMainWindow::lockWorkspace);
+
+ PerspectiveListAction = new QWidgetAction(_this);
+ PerspectiveComboBox = new QComboBox(_this);
+ PerspectiveComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ PerspectiveComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+ PerspectiveListAction->setDefaultWidget(PerspectiveComboBox);
+ ui.toolBar->addAction(PerspectiveListAction);
+
+ a = SavePerspectiveAction = ui.toolBar->addAction("Create Perspective");
+ a->setIcon(svgIcon(":/adsdemo/images/picture_in_picture.svg"));
+ QObject::connect(a, &QAction::triggered, _this, &CMainWindow::savePerspective);
+ ui.toolBar->addAction(SavePerspectiveAction);
+
+ ui.toolBar->addSeparator();
+
+ a = ui.toolBar->addAction("Create Floating Editor");
+ a->setProperty("Floating", true);
+ a->setToolTip("Creates floating dynamic dockable editor windows that are deleted on close");
+ a->setIcon(svgIcon(":/adsdemo/images/note_add.svg"));
+ _this->connect(a, SIGNAL(triggered()), SLOT(createEditor()));
+ ui.menuTests->addAction(a);
+
+ a = ui.toolBar->addAction("Create Docked Editor");
+ a->setProperty("Floating", false);
+ a->setToolTip("Creates a docked editor windows that are deleted on close");
+ a->setIcon(svgIcon(":/adsdemo/images/docked_editor.svg"));
+ _this->connect(a, SIGNAL(triggered()), SLOT(createEditor()));
+ ui.menuTests->addAction(a);
+
+ a = ui.toolBar->addAction("Create Editor Tab");
+ a->setProperty("Floating", false);
+ a->setToolTip("Creates a editor tab and inserts it as second tab into an area");
+ a->setIcon(svgIcon(":/adsdemo/images/tab.svg"));
+ a->setProperty("Tabbed", true);
+ _this->connect(a, SIGNAL(triggered()), SLOT(createEditor()));
+ ui.menuTests->addAction(a);
+
+ ui.toolBar->addSeparator();
+ a = ui.toolBar->addAction("Create Floating Table");
+ a->setToolTip("Creates floating dynamic dockable table with millions of entries");
+ a->setIcon(svgIcon(":/adsdemo/images/grid_on.svg"));
+ _this->connect(a, SIGNAL(triggered()), SLOT(createTable()));
+ ui.menuTests->addAction(a);
+
+ a = ui.toolBar->addAction("Create Image Viewer");
+ auto ToolButton = qobject_cast(ui.toolBar->widgetForAction(a));
+ ToolButton->setPopupMode(QToolButton::InstantPopup);
+ a->setToolTip("Creates floating, docked or pinned image viewer");
+ a->setIcon(svgIcon(":/adsdemo/images/panorama.svg"));
+ ui.menuTests->addAction(a);
+ auto Menu = new QMenu();
+ ToolButton->setMenu(Menu);
+ a = Menu->addAction("Floating Image Viewer");
+ _this->connect(a, SIGNAL(triggered()), SLOT(createImageViewer()));
+ a = Menu->addAction("Docked Image Viewer");
+ _this->connect(a, SIGNAL(triggered()), SLOT(createImageViewer()));
+ a = Menu->addAction("Pinned Image Viewer");
+ _this->connect(a, SIGNAL(triggered()), SLOT(createImageViewer()));
+
+
+ ui.menuTests->addSeparator();
+ a = ui.menuTests->addAction("Show Status Dialog");
+ _this->connect(a, SIGNAL(triggered()), SLOT(showStatusDialog()));
+
+ a = ui.menuTests->addAction("Toggle Label 0 Window Title");
+ _this->connect(a, SIGNAL(triggered()), SLOT(toggleDockWidgetWindowTitle()));
+ ui.menuTests->addSeparator();
+
+ a = ui.toolBar->addAction("Apply VS Style");
+ a->setToolTip("Applies a Visual Studio light style (visual_studio_light.css)." );
+ a->setIcon(svgIcon(":/adsdemo/images/color_lens.svg"));
+ QObject::connect(a, &QAction::triggered, _this, &CMainWindow::applyVsStyle);
+ ui.menuTests->addAction(a);
+}
+
+
+//============================================================================
+void MainWindowPrivate::saveState()
+{
+ QSettings Settings("Settings.ini", QSettings::IniFormat);
+ Settings.setValue("mainWindow/Geometry", _this->saveGeometry());
+ Settings.setValue("mainWindow/State", _this->saveState());
+ Settings.setValue("mainWindow/DockingState", DockManager->saveState());
+}
+
+
+//============================================================================
+void MainWindowPrivate::restoreState()
+{
+ QSettings Settings("Settings.ini", QSettings::IniFormat);
+ _this->restoreGeometry(Settings.value("mainWindow/Geometry").toByteArray());
+ _this->restoreState(Settings.value("mainWindow/State").toByteArray());
+ DockManager->restoreState(Settings.value("mainWindow/DockingState").toByteArray());
+}
+
+
+
+//============================================================================
+void MainWindowPrivate::savePerspectives()
+{
+ QSettings Settings("Settings.ini", QSettings::IniFormat);
+ DockManager->savePerspectives(Settings);
+}
+
+
+
+//============================================================================
+void MainWindowPrivate::restorePerspectives()
+{
+ QSettings Settings("Settings.ini", QSettings::IniFormat);
+ DockManager->loadPerspectives(Settings);
+ PerspectiveComboBox->clear();
+ PerspectiveComboBox->addItems(DockManager->perspectiveNames());
+}
+
+
+//============================================================================
+CMainWindow::CMainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ d(new MainWindowPrivate(this))
+{
+ using namespace ads;
+ d->ui.setupUi(this);
+ setWindowTitle(QApplication::instance()->applicationName());
+ d->createActions();
+
+ // uncomment the following line if the tab close button should be
+ // a QToolButton instead of a QPushButton
+ // CDockManager::setConfigFlags(CDockManager::configFlags() | CDockManager::TabCloseButtonIsToolButton);
+
+ // uncomment the following line if you want to use opaque undocking and
+ // opaque splitter resizing
+ //CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig);
+
+ // uncomment the following line if you want a fixed tab width that does
+ // not change if the visibility of the close button changes
+ //CDockManager::setConfigFlag(CDockManager::RetainTabSizeWhenCloseButtonHidden, true);
+
+ // uncomment the following line if you don't want close button on DockArea's title bar
+ //CDockManager::setConfigFlag(CDockManager::DockAreaHasCloseButton, false);
+
+ // uncomment the following line if you don't want undock button on DockArea's title bar
+ //CDockManager::setConfigFlag(CDockManager::DockAreaHasUndockButton, false);
+
+ // uncomment the following line if you don't want tabs menu button on DockArea's title bar
+ //CDockManager::setConfigFlag(CDockManager::DockAreaHasTabsMenuButton, false);
+
+ // uncomment the following line if you don't want disabled buttons to appear on DockArea's title bar
+ //CDockManager::setConfigFlag(CDockManager::DockAreaHideDisabledButtons, true);
+
+ // uncomment the following line if you want to show tabs menu button on DockArea's title bar only when there are more than one tab and at least of them has elided title
+ //CDockManager::setConfigFlag(CDockManager::DockAreaDynamicTabsMenuButtonVisibility, true);
+
+ // uncomment the following line if you want floating container to always show application title instead of active dock widget's title
+ //CDockManager::setConfigFlag(CDockManager::FloatingContainerHasWidgetTitle, false);
+
+ // uncomment the following line if you want floating container to show active dock widget's icon instead of always showing application icon
+ //CDockManager::setConfigFlag(CDockManager::FloatingContainerHasWidgetIcon, true);
+
+ // uncomment the following line if you want a central widget in the main dock container (the dock manager) without a titlebar
+ // If you enable this code, you can test it in the demo with the Calendar 0
+ // dock widget.
+ //CDockManager::setConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar, true);
+
+ // uncomment the following line to enable focus highlighting of the dock
+ // widget that has the focus
+ CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
+
+ // uncomment if you would like to enable dock widget auto hiding
+ CDockManager::setAutoHideConfigFlags({CDockManager::DefaultAutoHideConfig});
+
+ // uncomment if you would like to enable an equal distribution of the
+ // available size of a splitter to all contained dock widgets
+ // CDockManager::setConfigFlag(CDockManager::EqualSplitOnInsertion, true);
+
+ // uncomment if you would like to close tabs with the middle mouse button, web browser style
+ // CDockManager::setConfigFlag(CDockManager::MiddleMouseButtonClosesTab, true);
+
+ // Now create the dock manager and its content
+ d->DockManager = new CDockManager(this);
+ d->DockManager->setDockWidgetToolBarStyle(Qt::ToolButtonIconOnly, ads::CDockWidget::StateFloating);
+
+ #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
+ connect(d->PerspectiveComboBox, SIGNAL(activated(QString)),
+ d->DockManager, SLOT(openPerspective(QString)));
+ #else
+ connect(d->PerspectiveComboBox, SIGNAL(textActivated(QString)),
+ d->DockManager, SLOT(openPerspective(QString)));
+ #endif
+
+ d->createContent();
+ // Default window geometry - center on screen
+ resize(1280, 720);
+ setGeometry(QStyle::alignedRect(
+ Qt::LeftToRight, Qt::AlignCenter, frameSize(),
+ QGuiApplication::primaryScreen()->availableGeometry()
+ ));
+
+ //d->restoreState();
+ d->restorePerspectives();
+}
+
+
+//============================================================================
+CMainWindow::~CMainWindow()
+{
+ delete d;
+}
+
+
+//============================================================================
+void CMainWindow::closeEvent(QCloseEvent* event)
+{
+ d->saveState();
+ // Delete dock manager here to delete all floating widgets. This ensures
+ // that all top level windows of the dock manager are properly closed
+ d->DockManager->deleteLater();
+ QMainWindow::closeEvent(event);
+}
+
+
+//============================================================================
+void CMainWindow::on_actionSaveState_triggered(bool)
+{
+ qDebug() << "MainWindow::on_actionSaveState_triggered";
+ d->saveState();
+}
+
+
+//============================================================================
+void CMainWindow::on_actionRestoreState_triggered(bool)
+{
+ qDebug() << "MainWindow::on_actionRestoreState_triggered";
+ d->restoreState();
+}
+
+
+//============================================================================
+void CMainWindow::savePerspective()
+{
+ QString PerspectiveName = QInputDialog::getText(this, "Save Perspective", "Enter unique name:");
+ if (PerspectiveName.isEmpty())
+ {
+ return;
+ }
+
+ d->DockManager->addPerspective(PerspectiveName);
+ QSignalBlocker Blocker(d->PerspectiveComboBox);
+ d->PerspectiveComboBox->clear();
+ d->PerspectiveComboBox->addItems(d->DockManager->perspectiveNames());
+ d->PerspectiveComboBox->setCurrentText(PerspectiveName);
+
+ d->savePerspectives();
+}
+
+
+//============================================================================
+void CMainWindow::onViewToggled(bool Open)
+{
+ Q_UNUSED(Open);
+ auto DockWidget = qobject_cast(sender());
+ if (!DockWidget)
+ {
+ return;
+ }
+
+ //qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")";
+}
+
+
+//============================================================================
+void CMainWindow::onViewVisibilityChanged(bool Visible)
+{
+ Q_UNUSED(Visible);
+ auto DockWidget = qobject_cast(sender());
+ if (!DockWidget)
+ {
+ return;
+ }
+
+ //qDebug() << DockWidget->objectName() << " visibilityChanged(" << Visible << ")";
+}
+
+
+//============================================================================
+void CMainWindow::createEditor()
+{
+ QObject* Sender = sender();
+ QVariant vFloating = Sender->property("Floating");
+ bool Floating = vFloating.isValid() ? vFloating.toBool() : true;
+ QVariant vTabbed = Sender->property("Tabbed");
+ bool Tabbed = vTabbed.isValid() ? vTabbed.toBool() : true;
+ auto DockWidget = d->createEditorWidget();
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetForceCloseWithArea, true);
+ connect(DockWidget, SIGNAL(closeRequested()), SLOT(onEditorCloseRequested()));
+
+ if (Floating)
+ {
+ auto FloatingWidget = d->DockManager->addDockWidgetFloating(DockWidget);
+ FloatingWidget->move(QPoint(20, 20));
+ d->LastCreatedFloatingEditor = DockWidget;
+ d->LastDockedEditor.clear();
+ return;
+ }
+
+
+ ads::CDockAreaWidget* EditorArea = d->LastDockedEditor ? d->LastDockedEditor->dockAreaWidget() : nullptr;
+ if (EditorArea)
+ {
+ if (Tabbed)
+ {
+ // Test inserting the dock widget tab at a given position instead
+ // of appending it. This function inserts the new dock widget as
+ // first tab
+ d->DockManager->addDockWidgetTabToArea(DockWidget, EditorArea, 0);
+ }
+ else
+ {
+ d->DockManager->setConfigFlag(ads::CDockManager::EqualSplitOnInsertion, true);
+ d->DockManager->addDockWidget(ads::RightDockWidgetArea, DockWidget, EditorArea);
+ }
+ }
+ else
+ {
+ if (d->LastCreatedFloatingEditor)
+ {
+ d->DockManager->addDockWidget(ads::RightDockWidgetArea, DockWidget, d->LastCreatedFloatingEditor->dockAreaWidget());
+ }
+ else
+ {
+ d->DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget);
+ }
+ }
+ d->LastDockedEditor = DockWidget;
+}
+
+
+//============================================================================
+void CMainWindow::onEditorCloseRequested()
+{
+ auto DockWidget = qobject_cast(sender());
+ int Result = QMessageBox::question(this, "Close Editor", QString("Editor %1 "
+ "contains unsaved changes? Would you like to close it?")
+ .arg(DockWidget->windowTitle()));
+ if (QMessageBox::Yes == Result)
+ {
+ DockWidget->closeDockWidget();
+ }
+}
+
+
+//============================================================================
+void CMainWindow::onImageViewerCloseRequested()
+{
+ auto DockWidget = qobject_cast(sender());
+ int Result = QMessageBox::question(this, "Close Image Viewer", QString("%1 "
+ "contains unsaved changes? Would you like to close it?")
+ .arg(DockWidget->windowTitle()));
+ if (QMessageBox::Yes == Result)
+ {
+ DockWidget->closeDockWidget();
+ }
+}
+
+
+//============================================================================
+void CMainWindow::createTable()
+{
+ auto DockWidget = d->createTableWidget();
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
+ auto FloatingWidget = d->DockManager->addDockWidgetFloating(DockWidget);
+ FloatingWidget->move(QPoint(40, 40));
+}
+
+
+//============================================================================
+void CMainWindow::showStatusDialog()
+{
+ CStatusDialog Dialog(d->DockManager);
+ Dialog.exec();
+}
+
+
+//============================================================================
+void CMainWindow::toggleDockWidgetWindowTitle()
+{
+ QString Title = d->WindowTitleTestDockWidget->windowTitle();
+ int i = Title.indexOf(" (Test)");
+ if (-1 == i)
+ {
+ Title += " (Test)";
+ }
+ else
+ {
+ Title = Title.left(i);
+ }
+ d->WindowTitleTestDockWidget->setWindowTitle(Title);
+}
+
+
+//============================================================================
+void CMainWindow::applyVsStyle()
+{
+ QFile StyleSheetFile(":adsdemo/res/visual_studio_light.css");
+ StyleSheetFile.open(QIODevice::ReadOnly);
+ QTextStream StyleSheetStream(&StyleSheetFile);
+ auto Stylesheet = StyleSheetStream.readAll();
+ StyleSheetFile.close();
+ d->DockManager->setStyleSheet(Stylesheet);
+}
+
+
+//============================================================================
+void CMainWindow::createImageViewer()
+{
+ QAction* a = qobject_cast(sender());
+ qDebug() << "createImageViewer " << a->text();
+
+ auto DockWidget = d->createImageViewer();
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
+ DockWidget->setFeature(ads::CDockWidget::DockWidgetForceCloseWithArea, true);
+ DockWidget->setFeature(ads::CDockWidget::CustomCloseHandling, true);
+ DockWidget->resize(QSize(640, 480));
+ connect(DockWidget, &ads::CDockWidget::closeRequested, this,
+ &CMainWindow::onImageViewerCloseRequested);
+
+ if (a->text().startsWith("Floating"))
+ {
+ auto FloatingWidget = d->DockManager->addDockWidgetFloating(DockWidget);
+ FloatingWidget->move(QPoint(20, 20));
+ }
+ else if (a->text().startsWith("Docked"))
+ {
+ d->DockManager->addDockWidget(ads::RightDockWidgetArea, DockWidget);
+ }
+ else if (a->text().startsWith("Pinned"))
+ {
+ d->DockManager->addAutoHideDockWidget(ads::SideBarLeft, DockWidget);
+ }
+}
+
+
+//============================================================================
+void CMainWindow::lockWorkspace(bool Value)
+{
+ if (Value)
+ {
+ d->DockManager->lockDockWidgetFeaturesGlobally();
+ }
+ else
+ {
+ d->DockManager->lockDockWidgetFeaturesGlobally(ads::CDockWidget::NoDockWidgetFeatures);
+ }
+}
+
diff --git a/QtADS/demo/MainWindow.h b/QtADS/demo/MainWindow.h
new file mode 100644
index 0000000..dd12360
--- /dev/null
+++ b/QtADS/demo/MainWindow.h
@@ -0,0 +1,74 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+/*******************************************************************************
+** Qt Advanced Docking System
+** Copyright (C) 2017 Uwe Kindler
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License as published by the Free Software Foundation; either
+** version 2.1 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Lesser General Public License for more details.
+**
+** You should have received a copy of the GNU Lesser General Public
+** License along with this library; If not, see .
+******************************************************************************/
+
+
+//============================================================================
+/// \file MainWindow.h
+/// \author Uwe Kindler
+/// \date 13.02.2018
+/// \brief Declaration of CMainWindow class
+//============================================================================
+
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include
+
+
+
+struct MainWindowPrivate;
+
+
+/**
+ * Simple main window for demo
+ */
+class CMainWindow : public QMainWindow
+{
+ Q_OBJECT
+private:
+ MainWindowPrivate* d;///< private data - pimpl
+ friend struct MainWindowPrivate;
+
+protected:
+ virtual void closeEvent(QCloseEvent* event) override;
+
+public:
+ explicit CMainWindow(QWidget *parent = 0);
+ virtual ~CMainWindow();
+
+private slots:
+ void on_actionSaveState_triggered(bool);
+ void on_actionRestoreState_triggered(bool);
+ void savePerspective();
+ void onViewToggled(bool Open);
+ void onViewVisibilityChanged(bool Visible);
+ void createEditor();
+ void createTable();
+ void onEditorCloseRequested();
+ void onImageViewerCloseRequested();
+ void showStatusDialog();
+ void toggleDockWidgetWindowTitle();
+ void applyVsStyle();
+ void createImageViewer();
+ void lockWorkspace(bool Value);
+};
+
+#endif // MAINWINDOW_H
diff --git a/QtADS/demo/RenderWidget.cpp b/QtADS/demo/RenderWidget.cpp
new file mode 100644
index 0000000..c168e96
--- /dev/null
+++ b/QtADS/demo/RenderWidget.cpp
@@ -0,0 +1,108 @@
+//============================================================================
+/// \file RenderWidget.cpp
+/// \author Uwe Kindler
+/// \date 04.11.2022
+/// \brief Implementation of CRenderWidget
+//============================================================================
+
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include "RenderWidget.h"
+
+#include
+#include
+
+
+//===========================================================================
+CRenderWidget::CRenderWidget(QWidget* Parent) :
+ QWidget(Parent), m_ScaleFactor(1)
+{
+ this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+ this->setCursor(Qt::OpenHandCursor);
+}
+
+//===========================================================================
+CRenderWidget::~CRenderWidget()
+{
+
+}
+
+//===========================================================================
+void CRenderWidget::showImage(const QImage& Image)
+{
+ m_Image = QPixmap::fromImage(Image);
+ this->adjustWidgetSize();
+ this->repaint();
+}
+
+//===========================================================================
+void CRenderWidget::paintEvent(QPaintEvent* Event)
+{
+ Q_UNUSED(Event);
+ QPainter Painter(this);
+ Painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ Painter.setRenderHint(QPainter::Antialiasing, true);
+ Painter.scale(m_ScaleFactor, m_ScaleFactor);
+ Painter.drawPixmap(QPoint(0, 0), m_Image);
+}
+
+//============================================================================
+void CRenderWidget::zoomIn()
+{
+ scaleImage(1.25);
+}
+
+//============================================================================
+void CRenderWidget::zoomOut()
+{
+ scaleImage(0.8);
+}
+
+//============================================================================
+void CRenderWidget::zoomByValue(double ZoomValue)
+{
+ scaleImage(ZoomValue);
+}
+
+//============================================================================
+void CRenderWidget::normalSize()
+{
+ m_ScaleFactor = 1;
+ this->adjustWidgetSize();
+}
+
+//============================================================================
+void CRenderWidget::scaleImage(double ScaleFactor)
+{
+ m_ScaleFactor *= ScaleFactor;
+ this->adjustWidgetSize();
+}
+
+//============================================================================
+void CRenderWidget::adjustWidgetSize()
+{
+ QSize ScaledImageSize = m_Image.size() * m_ScaleFactor;
+ if (ScaledImageSize != this->size())
+ {
+ this->setFixedSize(ScaledImageSize);
+ }
+}
+
+//============================================================================
+void CRenderWidget::scaleToSize(const QSize& TargetSize)
+{
+ if (m_Image.isNull())
+ {
+ return;
+ }
+ double ScaleFactorH = (double) TargetSize.width() / m_Image.size().width();
+ double ScaleFactorV = (double) TargetSize.height()
+ / m_Image.size().height();
+ m_ScaleFactor = (ScaleFactorH < ScaleFactorV) ? ScaleFactorH : ScaleFactorV;
+ this->adjustWidgetSize();
+}
+
+//---------------------------------------------------------------------------
+// EOF RenderWidget.cpp
diff --git a/QtADS/demo/RenderWidget.h b/QtADS/demo/RenderWidget.h
new file mode 100644
index 0000000..81fedf1
--- /dev/null
+++ b/QtADS/demo/RenderWidget.h
@@ -0,0 +1,111 @@
+#ifndef RenderWidgetH
+#define RenderWidgetH
+//============================================================================
+/// \file RenderWidget.h
+/// \author Uwe Kindler
+/// \date 04.11.2022
+/// \brief Declaration of CRenderWidget
+//============================================================================
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include
+#include
+
+//============================================================================
+// FORWARD DECLARATIONS
+//============================================================================
+class QImage;
+
+
+/**
+ * @brief Widget for fast display of images (i.e. for video capture devices)
+ */
+class CRenderWidget : public QWidget
+{
+ Q_OBJECT
+private:
+ QPixmap m_Image;
+ double m_ScaleFactor;
+
+protected:
+ /**
+ * @brief Reimplemented paint event method showing actual image.
+ */
+ void paintEvent(QPaintEvent* PaintEvent);
+
+ /**
+ * @brief Change scale factor
+ */
+ void scaleImage(double ScaleFactor);
+
+ /**
+ * @brief Adjust widget size to size of image.
+ */
+ void adjustWidgetSize();
+
+public:
+ /**
+ * Constructor
+ * @param[in] Parent Parent widget.
+ */
+ CRenderWidget(QWidget* Parent);
+
+ /**
+ * Destructor
+ */
+ virtual ~CRenderWidget();
+
+signals:
+ /**
+ * @brief Signalize change of captured image size.
+ * @param ImageSize New image size.
+ */
+ void imageSizeChanged(const QSize& ImageSize);
+
+public slots:
+ /**
+ * @brief Show new image in render widget.
+ */
+ void showImage(const QImage& Image);
+
+ /**
+ * @brief Zoom into the scene.
+ * This function decreases the scaling factor by setting it to the previous
+ * value in internal scaling list.
+ * @brief Steps The number of steps to zoom in. One step is 25%.
+ */
+ void zoomIn();
+
+ /**
+ * @brief Zoom out of the scene.
+ * This function decreases the scaling factor by setting it to the next
+ * value in internal scaling list.
+ * @brief Steps The number of steps to zoom out. One step is 25%.
+ */
+ void zoomOut();
+
+ /**
+ * @brief Change zoom by zoom value.
+ * @param[in] ZoomValue This is the zoom value to apply. A value of 1
+ * means no change a value > 1 increases the image (i.e. 1.25 would increase
+ * the image by 25%) and a value of < 1 decreases the image size (i.e.
+ * a value of 0.8 would decrease the image size by 25%).
+ */
+ void zoomByValue(double ZoomValue);
+
+ /**
+ * @brief Resets the actual scaling to 1 and display the image with its
+ * actual pixel size.
+ */
+ void normalSize();
+
+ /**
+ * @brief Scales the wiget and its content image to the given TargetSize
+ */
+ void scaleToSize(const QSize& TargetSize);
+}; // class CRenderWidget
+
+//---------------------------------------------------------------------------
+#endif // RenderWidgetH
diff --git a/QtADS/demo/StatusDialog.cpp b/QtADS/demo/StatusDialog.cpp
new file mode 100644
index 0000000..fe8b4f5
--- /dev/null
+++ b/QtADS/demo/StatusDialog.cpp
@@ -0,0 +1,88 @@
+//============================================================================
+/// \file StatusDialog.cpp
+/// \author Uwe Kindler
+/// \date 13.04.2020
+/// \brief Implementation of CStatusDialog class
+//============================================================================
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include "StatusDialog.h"
+
+#include
+
+#include "DockManager.h"
+#include "DockWidget.h"
+#include "ui_StatusDialog.h"
+
+/**
+ * Private data class of CStatusDialog class (pimpl)
+ */
+struct StatusDialogPrivate
+{
+ CStatusDialog *_this;
+ Ui::CStatusDialogClass ui;
+ ads::CDockManager* DockManager;
+ QMap DockWidgets;
+
+ /**
+ * Private data constructor
+ */
+ StatusDialogPrivate(CStatusDialog *_public);
+};
+// struct StatusDialogPrivate
+
+//============================================================================
+StatusDialogPrivate::StatusDialogPrivate(CStatusDialog *_public) :
+ _this(_public)
+{
+
+}
+
+//============================================================================
+CStatusDialog::CStatusDialog(ads::CDockManager* DockManager) :
+ QDialog(DockManager),
+ d(new StatusDialogPrivate(this))
+{
+ d->ui.setupUi(this);
+ d->DockManager = DockManager;
+ d->DockWidgets = DockManager->dockWidgetsMap();
+
+ for (auto it = d->DockWidgets.begin(); it != d->DockWidgets.end(); ++it)
+ {
+ QVariant vDockWidget = QVariant::fromValue(it.value());
+ d->ui.dockWidgetsComboBox->addItem(it.key(), vDockWidget);
+ }
+}
+
+//============================================================================
+CStatusDialog::~CStatusDialog()
+{
+ delete d;
+}
+
+
+//============================================================================
+void CStatusDialog::on_dockWidgetsComboBox_currentIndexChanged(int index)
+{
+ if (index < 0)
+ {
+ return;
+ }
+
+ auto vDockWidget = d->ui.dockWidgetsComboBox->currentData();
+ auto DockWidget = vDockWidget.value();
+ d->ui.isClosedCheckBox->setChecked(DockWidget->isClosed());
+ d->ui.isFloatingCheckBox->setChecked(DockWidget->isFloating());
+ d->ui.tabbedCheckBox->setChecked(DockWidget->isTabbed());
+ d->ui.isCurrentTabCheckBox->setChecked(DockWidget->isCurrentTab());
+ d->ui.closableCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetClosable));
+ d->ui.movableCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetMovable));
+ d->ui.floatableCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetFloatable));
+ d->ui.deleteOnCloseCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::DockWidgetDeleteOnClose));
+ d->ui.customCloseHandlingCheckBox->setChecked(DockWidget->features().testFlag(ads::CDockWidget::CustomCloseHandling));
+}
+
+//---------------------------------------------------------------------------
+// EOF StatusDialog.cpp
diff --git a/QtADS/demo/StatusDialog.h b/QtADS/demo/StatusDialog.h
new file mode 100644
index 0000000..977fe82
--- /dev/null
+++ b/QtADS/demo/StatusDialog.h
@@ -0,0 +1,47 @@
+#ifndef StatusDialogH
+#define StatusDialogH
+//============================================================================
+/// \file StatusDialog.h
+/// \author Uwe Kindler
+/// \date 13.04.2020
+/// \brief Declaration of CStatusDialog class
+//============================================================================
+
+//============================================================================
+// INCLUDES
+//============================================================================
+#include
+
+namespace ads {class CDockManager;}
+struct StatusDialogPrivate;
+
+/**
+ * Displays status info about dock widgets
+ */
+class CStatusDialog : public QDialog
+{
+ Q_OBJECT
+private:
+ StatusDialogPrivate* d; ///< private data (pimpl)
+ friend struct StatusDialogPrivate;
+
+private slots:
+ void on_dockWidgetsComboBox_currentIndexChanged(int index);
+
+protected:
+public:
+ using Super = QDialog;
+ /**
+ * Default Constructor
+ */
+ CStatusDialog(ads::CDockManager* parent);
+
+ /**
+ * Virtual Destructor
+ */
+ virtual ~CStatusDialog();
+}; // class StatusDialog
+
+ // namespace namespace_name
+//-----------------------------------------------------------------------------
+#endif // StatusDialogH
diff --git a/QtADS/demo/StatusDialog.ui b/QtADS/demo/StatusDialog.ui
new file mode 100644
index 0000000..9bd07a1
--- /dev/null
+++ b/QtADS/demo/StatusDialog.ui
@@ -0,0 +1,146 @@
+
+
+ CStatusDialogClass
+
+
+
+ 0
+ 0
+ 357
+ 331
+
+
+
+
+ 0
+ 0
+
+
+
+ Dock Widget Status
+
+
+
+ QLayout::SetFixedSize
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Dock Widget:
+
+
+
+
+
+
+
+ 300
+ 0
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Status
+
+
+
+
+
+ closed
+
+
+
+
+
+
+ floating
+
+
+
+
+
+
+ tabbed
+
+
+
+
+
+
+ is current tab
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Feature Flags
+
+
+
+
+
+ DockWidgetClosable
+
+
+
+
+
+
+ DockWidgetMovable
+
+
+
+
+
+
+ DockWidgetFloatable
+
+
+
+
+
+
+ DockWidgetDeleteOnClose
+
+
+
+
+
+
+ CustomCloseHandling
+
+
+
+
+
+
+
+
+
+
+
diff --git a/QtADS/demo/app.css b/QtADS/demo/app.css
new file mode 100644
index 0000000..b316b29
--- /dev/null
+++ b/QtADS/demo/app.css
@@ -0,0 +1,4 @@
+ads--CTitleBarButton::menu-indicator
+{
+ image: none;
+}
\ No newline at end of file
diff --git a/QtADS/demo/app.ico b/QtADS/demo/app.ico
new file mode 100644
index 0000000..3a57c64
Binary files /dev/null and b/QtADS/demo/app.ico differ
diff --git a/QtADS/demo/app.rc b/QtADS/demo/app.rc
new file mode 100644
index 0000000..b8bb54a
--- /dev/null
+++ b/QtADS/demo/app.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "app.ico"
diff --git a/QtADS/demo/demo.pro b/QtADS/demo/demo.pro
new file mode 100644
index 0000000..913b5be
--- /dev/null
+++ b/QtADS/demo/demo.pro
@@ -0,0 +1,49 @@
+ADS_OUT_ROOT = $${OUT_PWD}/..
+
+TARGET = AdvancedDockingSystemDemo
+DESTDIR = $${ADS_OUT_ROOT}/lib
+QT += core gui widgets quick quickwidgets
+
+include(../ads.pri)
+
+lessThan(QT_MAJOR_VERSION, 6) {
+ win32 {
+ QT += axcontainer
+ }
+}
+
+CONFIG += c++14
+CONFIG += debug_and_release
+DEFINES += QT_DEPRECATED_WARNINGS
+RC_FILE += app.rc
+
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+
+HEADERS += \
+ MainWindow.h \
+ StatusDialog.h \
+ ImageViewer.h \
+ RenderWidget.h
+
+SOURCES += \
+ main.cpp \
+ MainWindow.cpp \
+ StatusDialog.cpp \
+ ImageViewer.cpp \
+ RenderWidget.cpp
+
+FORMS += \
+ mainwindow.ui \
+ StatusDialog.ui
+
+RESOURCES += demo.qrc
+
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+
+
+INCLUDEPATH += ../src
+DEPENDPATH += ../src
diff --git a/QtADS/demo/demo.qrc b/QtADS/demo/demo.qrc
new file mode 100644
index 0000000..8b35293
--- /dev/null
+++ b/QtADS/demo/demo.qrc
@@ -0,0 +1,43 @@
+
+
+ images/folder.svg
+ images/folder_open.svg
+ images/note_add.svg
+ images/picture_in_picture.svg
+ images/restore.svg
+ images/save.svg
+ images/date_range.svg
+ images/edit.svg
+ images/grid_on.svg
+ images/custom-menu-button.svg
+ app.css
+ images/plus.svg
+ images/help_outline.svg
+ images/fullscreen.svg
+ images/create_floating_editor.svg
+ images/create_floating_table.svg
+ images/docked_editor.svg
+ images/tab.svg
+ res/visual_studio_light.css
+ images/color_lens.svg
+ images/ads_icon.svg
+ images/ads_logo.svg
+ images/find_in_page.svg
+ images/perm_media.svg
+ images/zoom_in.svg
+ images/zoom_out.svg
+ images/zoom_out_map.svg
+ images/ads_tile_blue.svg
+ images/ads_tile_blue_light.svg
+ images/ads_tile_green.svg
+ images/ads_tile_orange.svg
+ images/photo.svg
+ images/crop_original.svg
+ images/panorama.svg
+ images/ads_icon2.svg
+ images/font_download.svg
+ images/lock_outline.svg
+ images/lock.svg
+ images/lock_open.svg
+
+
diff --git a/QtADS/demo/images/ads_icon.svg b/QtADS/demo/images/ads_icon.svg
new file mode 100644
index 0000000..ee0ac56
--- /dev/null
+++ b/QtADS/demo/images/ads_icon.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/QtADS/demo/images/ads_icon2.svg b/QtADS/demo/images/ads_icon2.svg
new file mode 100644
index 0000000..8ed092a
--- /dev/null
+++ b/QtADS/demo/images/ads_icon2.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/QtADS/demo/images/ads_logo.svg b/QtADS/demo/images/ads_logo.svg
new file mode 100644
index 0000000..da1b3b4
--- /dev/null
+++ b/QtADS/demo/images/ads_logo.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/QtADS/demo/images/ads_tile_blue.svg b/QtADS/demo/images/ads_tile_blue.svg
new file mode 100644
index 0000000..91ec6dc
--- /dev/null
+++ b/QtADS/demo/images/ads_tile_blue.svg
@@ -0,0 +1,33 @@
+
+
diff --git a/QtADS/demo/images/ads_tile_blue_light.svg b/QtADS/demo/images/ads_tile_blue_light.svg
new file mode 100644
index 0000000..aa9bb83
--- /dev/null
+++ b/QtADS/demo/images/ads_tile_blue_light.svg
@@ -0,0 +1,147 @@
+
+
+
+
diff --git a/QtADS/demo/images/ads_tile_green.svg b/QtADS/demo/images/ads_tile_green.svg
new file mode 100644
index 0000000..ce8075a
--- /dev/null
+++ b/QtADS/demo/images/ads_tile_green.svg
@@ -0,0 +1,33 @@
+
+
diff --git a/QtADS/demo/images/ads_tile_orange.svg b/QtADS/demo/images/ads_tile_orange.svg
new file mode 100644
index 0000000..bb343dd
--- /dev/null
+++ b/QtADS/demo/images/ads_tile_orange.svg
@@ -0,0 +1,33 @@
+
+
diff --git a/QtADS/demo/images/color_lens.svg b/QtADS/demo/images/color_lens.svg
new file mode 100644
index 0000000..4560497
--- /dev/null
+++ b/QtADS/demo/images/color_lens.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/create_floating_editor.svg b/QtADS/demo/images/create_floating_editor.svg
new file mode 100644
index 0000000..82f701b
--- /dev/null
+++ b/QtADS/demo/images/create_floating_editor.svg
@@ -0,0 +1,80 @@
+
+
diff --git a/QtADS/demo/images/create_floating_table.svg b/QtADS/demo/images/create_floating_table.svg
new file mode 100644
index 0000000..8de57a1
--- /dev/null
+++ b/QtADS/demo/images/create_floating_table.svg
@@ -0,0 +1,80 @@
+
+
diff --git a/QtADS/demo/images/crop_original.svg b/QtADS/demo/images/crop_original.svg
new file mode 100644
index 0000000..a4a6513
--- /dev/null
+++ b/QtADS/demo/images/crop_original.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/custom-menu-button.svg b/QtADS/demo/images/custom-menu-button.svg
new file mode 100644
index 0000000..fde0535
--- /dev/null
+++ b/QtADS/demo/images/custom-menu-button.svg
@@ -0,0 +1,32 @@
+
+
diff --git a/QtADS/demo/images/date_range.svg b/QtADS/demo/images/date_range.svg
new file mode 100644
index 0000000..47087e0
--- /dev/null
+++ b/QtADS/demo/images/date_range.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/docked_editor.svg b/QtADS/demo/images/docked_editor.svg
new file mode 100644
index 0000000..5624074
--- /dev/null
+++ b/QtADS/demo/images/docked_editor.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/edit.svg b/QtADS/demo/images/edit.svg
new file mode 100644
index 0000000..064047b
--- /dev/null
+++ b/QtADS/demo/images/edit.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/find_in_page.svg b/QtADS/demo/images/find_in_page.svg
new file mode 100644
index 0000000..ff4e346
--- /dev/null
+++ b/QtADS/demo/images/find_in_page.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/folder.svg b/QtADS/demo/images/folder.svg
new file mode 100644
index 0000000..8d5eb69
--- /dev/null
+++ b/QtADS/demo/images/folder.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/folder_open.svg b/QtADS/demo/images/folder_open.svg
new file mode 100644
index 0000000..9201f64
--- /dev/null
+++ b/QtADS/demo/images/folder_open.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/font_download.svg b/QtADS/demo/images/font_download.svg
new file mode 100644
index 0000000..ecf5582
--- /dev/null
+++ b/QtADS/demo/images/font_download.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/fullscreen.svg b/QtADS/demo/images/fullscreen.svg
new file mode 100644
index 0000000..2cf89e3
--- /dev/null
+++ b/QtADS/demo/images/fullscreen.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/grid_on.svg b/QtADS/demo/images/grid_on.svg
new file mode 100644
index 0000000..058d415
--- /dev/null
+++ b/QtADS/demo/images/grid_on.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/help_outline.svg b/QtADS/demo/images/help_outline.svg
new file mode 100644
index 0000000..66f85ee
--- /dev/null
+++ b/QtADS/demo/images/help_outline.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/lock.svg b/QtADS/demo/images/lock.svg
new file mode 100644
index 0000000..ec11129
--- /dev/null
+++ b/QtADS/demo/images/lock.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/lock_open.svg b/QtADS/demo/images/lock_open.svg
new file mode 100644
index 0000000..a30effc
--- /dev/null
+++ b/QtADS/demo/images/lock_open.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/lock_outline.svg b/QtADS/demo/images/lock_outline.svg
new file mode 100644
index 0000000..613e430
--- /dev/null
+++ b/QtADS/demo/images/lock_outline.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/material_icons_license.txt b/QtADS/demo/images/material_icons_license.txt
new file mode 100644
index 0000000..f464cdd
--- /dev/null
+++ b/QtADS/demo/images/material_icons_license.txt
@@ -0,0 +1,211 @@
+ The Google Material icons and modifications can be used free of charge for
+ commerical and non-commerical projects according to the Apache License 2.0.
+
+ An attribution to https://material.io/icons/ and/or https://iconfu.com on
+ your website or in your app's "about" screen would be wonderful.
+
+ Please do not re-sell the icons.
+
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/QtADS/demo/images/note_add.svg b/QtADS/demo/images/note_add.svg
new file mode 100644
index 0000000..385cd39
--- /dev/null
+++ b/QtADS/demo/images/note_add.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/panorama.svg b/QtADS/demo/images/panorama.svg
new file mode 100644
index 0000000..5716c3d
--- /dev/null
+++ b/QtADS/demo/images/panorama.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/perm_media.svg b/QtADS/demo/images/perm_media.svg
new file mode 100644
index 0000000..2dac12f
--- /dev/null
+++ b/QtADS/demo/images/perm_media.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/photo.svg b/QtADS/demo/images/photo.svg
new file mode 100644
index 0000000..6da0234
--- /dev/null
+++ b/QtADS/demo/images/photo.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/picture_in_picture.svg b/QtADS/demo/images/picture_in_picture.svg
new file mode 100644
index 0000000..73e7239
--- /dev/null
+++ b/QtADS/demo/images/picture_in_picture.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/plus.svg b/QtADS/demo/images/plus.svg
new file mode 100644
index 0000000..33e9a27
--- /dev/null
+++ b/QtADS/demo/images/plus.svg
@@ -0,0 +1,123 @@
+
+
diff --git a/QtADS/demo/images/restore.svg b/QtADS/demo/images/restore.svg
new file mode 100644
index 0000000..5089983
--- /dev/null
+++ b/QtADS/demo/images/restore.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/save.svg b/QtADS/demo/images/save.svg
new file mode 100644
index 0000000..351b8ed
--- /dev/null
+++ b/QtADS/demo/images/save.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/tab.svg b/QtADS/demo/images/tab.svg
new file mode 100644
index 0000000..df5fd7c
--- /dev/null
+++ b/QtADS/demo/images/tab.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/zoom_in.svg b/QtADS/demo/images/zoom_in.svg
new file mode 100644
index 0000000..b65ca3c
--- /dev/null
+++ b/QtADS/demo/images/zoom_in.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/zoom_out.svg b/QtADS/demo/images/zoom_out.svg
new file mode 100644
index 0000000..d291238
--- /dev/null
+++ b/QtADS/demo/images/zoom_out.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/images/zoom_out_map.svg b/QtADS/demo/images/zoom_out_map.svg
new file mode 100644
index 0000000..dedc2d5
--- /dev/null
+++ b/QtADS/demo/images/zoom_out_map.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/QtADS/demo/main.cpp b/QtADS/demo/main.cpp
new file mode 100644
index 0000000..8832783
--- /dev/null
+++ b/QtADS/demo/main.cpp
@@ -0,0 +1,62 @@
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+
+
+void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ QByteArray localMsg = msg.toLocal8Bit();
+ switch (type) {
+ case QtDebugMsg:
+ fprintf(stdout, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ break;
+ case QtInfoMsg:
+ fprintf(stdout, "Info: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ break;
+ case QtWarningMsg:
+ fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ break;
+ case QtCriticalMsg:
+ fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ break;
+ case QtFatalMsg:
+ fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
+ abort();
+ }
+
+ fflush(stderr);
+ fflush(stdout);
+}
+
+int main(int argc, char *argv[])
+{
+#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
+ QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
+#if QT_VERSION >= 0x050600
+ QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+#endif
+#endif
+ std::shared_ptr b;
+ QApplication a(argc, argv);
+ a.setApplicationName("Advanced Docking System Demo");
+ a.setQuitOnLastWindowClosed(true);
+ a.setWindowIcon(QIcon(":/adsdemo/images/ads_icon2.svg"));
+
+ qInstallMessageHandler(myMessageOutput);
+ qDebug() << "Message handler test";
+
+ CMainWindow mw;
+ mw.show();
+
+ QFile StyleSheetFile(":/adsdemo/app.css");
+ StyleSheetFile.open(QIODevice::ReadOnly);
+ QTextStream StyleSheetStream(&StyleSheetFile);
+ a.setStyleSheet(StyleSheetStream.readAll());
+ StyleSheetFile.close();
+ return a.exec();
+}
diff --git a/QtADS/demo/main.py b/QtADS/demo/main.py
new file mode 100644
index 0000000..c0de017
--- /dev/null
+++ b/QtADS/demo/main.py
@@ -0,0 +1,613 @@
+import datetime
+import logging
+import os
+import sys
+
+from PyQt5 import uic
+from PyQt5.QtCore import (QCoreApplication, QDir, Qt, QSettings, QSignalBlocker,
+ QRect, QPoint, qDebug, qInstallMessageHandler,
+ QtDebugMsg, QtInfoMsg, QtWarningMsg,
+ QtCriticalMsg, QtFatalMsg, QSize)
+from PyQt5.QtGui import (QGuiApplication, QIcon, QCloseEvent)
+from PyQt5.QtWidgets import (QCalendarWidget, QFileSystemModel, QFrame, QLabel,
+ QMenu, QTreeView, QAction, QWidgetAction,
+ QComboBox, QStyle, QSizePolicy, QInputDialog, QMenu,
+ QToolButton, QWidget, QPlainTextEdit,
+ QTableWidget, QTableWidgetItem, QApplication,
+ QMessageBox)
+try:
+ from PyQt5.QAxContainer import QAxWidget
+except ImportError:
+ ACTIVEX_AVAILABLE = False
+else:
+ ACTIVEX_AVAILABLE = True
+
+from PyQtAds import QtAds
+
+import rc # pyrcc5 demo.qrc -o rc.py
+from status_dialog import CStatusDialog
+
+UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
+MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
+
+
+class _State:
+ label_count = 0
+ calendar_count = 0
+ file_system_count = 0
+ editor_count = 0
+ table_count = 0
+ activex_count = 0
+
+
+def features_string(dock_widget: QtAds.CDockWidget) -> str:
+ '''Function returns a features string with closable (c), movable (m) and floatable (f)
+ features. i.e. The following string is for a not closable but movable and floatable
+ widget: c- m+ f+'''
+
+ f = dock_widget.features()
+ closable = f & QtAds.CDockWidget.DockWidgetClosable
+ movable = f & QtAds.CDockWidget.DockWidgetMovable
+ floatable = f & QtAds.CDockWidget.DockWidgetFloatable
+
+ return "c{} m{} f{}".format("+" if closable else "-",
+ "+" if movable else "-",
+ "+" if floatable else "-")
+
+
+def append_feature_string_to_window_title(dock_widget: QtAds.CDockWidget):
+ '''Appends the string returned by features_string() to the window title of
+ the given DockWidget'''
+
+ dock_widget.setWindowTitle(dock_widget.windowTitle() + " ({})".format(features_string(dock_widget)))
+
+
+def svg_icon(filename: str):
+ '''Helper function to create an SVG icon'''
+ # This is a workaround, because because in item views SVG icons are not
+ # properly scaled and look blurry or pixelate
+ icon = QIcon(filename)
+ icon.addPixmap(icon.pixmap(92))
+ return icon
+
+
+class CMinSizeTableWidget(QTableWidget):
+ """Custom QTableWidget with a minimum size hint to test CDockWidget
+ setMinimumSizeHintMode() function of CDockWidget"""
+
+ def minimumSizeHint(self) -> QSize:
+ return QSize(300, 100)
+
+
+class CCustomComponentsFactory(QtAds.CDockComponentsFactory):
+
+ def createDockAreaTitleBar(self, dock_area: QtAds.CDockAreaWidget) -> QtAds.CDockAreaTitleBar:
+ title_bar = QtAds.CDockAreaTitleBar(dock_area)
+ custom_button = QToolButton(dock_area)
+ custom_button.setToolTip("Help")
+ custom_button.setIcon(svg_icon(":/adsdemo/images/help_outline.svg"))
+ custom_button.setAutoRaise(True)
+ index = title_bar.indexOf(title_bar.button(QtAds.TitleBarButtonTabsMenu))
+ title_bar.insertWidget(index + 1, custom_button)
+ return title_bar
+
+
+class MainWindow(MainWindowUI, MainWindowBase):
+ save_perspective_action: QAction
+ perspective_list_action: QWidgetAction
+ perspective_combo_box: QComboBox
+ dock_manager: QtAds.CDockManager
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.save_perspective_action = None
+ self.perspective_list_action = None
+ self.perspective_combo_box = None
+ self.dock_manager = None
+ self.window_title_test_dock_widget = None
+ self.last_docked_editor = None
+
+ self.setupUi(self)
+ self.create_actions()
+
+ # uncomment the following line if the tab close button should be
+ # a QToolButton instead of a QPushButton
+ # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.configFlags() | QtAds.CDockManager.TabCloseButtonIsToolButton)
+
+ # uncomment the following line if you want to use opaque undocking and
+ # opaque splitter resizing
+ #QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DefaultOpaqueConfig)
+
+ # uncomment the following line if you want a fixed tab width that does
+ # not change if the visibility of the close button changes
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.RetainTabSizeWhenCloseButtonHidden, True)
+
+ # uncomment the following line if you don't want close button on DockArea's title bar
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasCloseButton, False)
+
+ # uncomment the following line if you don't want undock button on DockArea's title bar
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasUndockButton, False)
+
+ # uncomment the following line if you don't want tabs menu button on DockArea's title bar
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHasTabsMenuButton, False)
+
+ # uncomment the following line if you don't want disabled buttons to appear on DockArea's title bar
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaHideDisabledButtons, True)
+
+ # uncomment the following line if you want to show tabs menu button on DockArea's title bar only when there are more than one tab and at least of them has elided title
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.DockAreaDynamicTabsMenuButtonVisibility, True)
+
+ # uncomment the following line if you want floating container to always show application title instead of active dock widget's title
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetTitle, False)
+
+ # uncomment the following line if you want floating container to show active dock widget's icon instead of always showing application icon
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FloatingContainerHasWidgetIcon, True)
+
+ # uncomment the following line if you want a central widget in the main dock container (the dock manager) without a titlebar
+ # If you enable this code, you can test it in the demo with the Calendar 0
+ # dock widget.
+ #QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.HideSingleCentralWidgetTitleBar, True)
+
+ # uncomment the following line to enable focus highlighting of the dock
+ # widget that has the focus
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
+
+ # uncomment if you would like to enable an equal distribution of the
+ # available size of a splitter to all contained dock widgets
+ # QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.EqualSplitOnInsertion, True)
+
+ # Now create the dock manager and its content
+ self.dock_manager = QtAds.CDockManager(self)
+
+ # Uncomment the following line to have the old style where the dock
+ # area close button closes the active tab
+ # QtAds.CDockManager.setConfigFlags(QtAds.CDockManager.DockAreaHasCloseButton
+ # | QtAds.CDockManager.DockAreaCloseButtonClosesTab)
+ self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
+
+ self.create_content()
+ # Default window geometry - center on screen
+ self.resize(1280, 720)
+ self.setGeometry(QStyle.alignedRect(
+ Qt.LeftToRight, Qt.AlignCenter, self.frameSize(),
+ QGuiApplication.primaryScreen().availableGeometry()))
+
+ # self.restore_state()
+ self.restore_perspectives()
+
+ def create_content(self):
+ # Test container docking
+ dock_widget = self.create_calendar_dock_widget()
+ dock_widget.setFeature(QtAds.CDockWidget.DockWidgetClosable, False)
+ special_dock_area = self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
+
+ # For this Special Dock Area we want to avoid dropping on the center of it (i.e. we don't want this widget to be ever tabbified):
+ special_dock_area.setAllowedAreas(QtAds.OuterDockAreas)
+ # special_dock_area.setAllowedAreas(QtAds.LeftDockWidgetArea | QtAds.RightDockWidgetArea) # just for testing
+
+ dock_widget = self.create_long_text_label_dock_widget()
+ self.window_title_test_dock_widget = dock_widget
+ dock_widget.setFeature(QtAds.CDockWidget.DockWidgetFocusable, False)
+ self.dock_manager.addDockWidget(QtAds.LeftDockWidgetArea, dock_widget)
+ file_system_widget = self.create_file_system_tree_dock_widget()
+ tool_bar = file_system_widget.createDefaultToolBar()
+ tool_bar.addAction(self.actionSaveState)
+ tool_bar.addAction(self.actionRestoreState)
+ file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
+ append_feature_string_to_window_title(file_system_widget)
+ self.dock_manager.addDockWidget(QtAds.BottomDockWidgetArea, file_system_widget)
+
+ file_system_widget = self.create_file_system_tree_dock_widget()
+ file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetMovable, False)
+ file_system_widget.setFeature(QtAds.CDockWidget.DockWidgetFloatable, False)
+ append_feature_string_to_window_title(file_system_widget)
+
+ # Test custom factory - we inject a help button into the title bar
+ QtAds.CDockComponentsFactory.setFactory(CCustomComponentsFactory())
+ top_dock_area = self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, file_system_widget)
+ # Uncomment the next line if you would like to test the
+ # HideSingleWidgetTitleBar functionality
+ # top_dock_area.setDockAreaFlag(QtAds.CDockAreaWidget.HideSingleWidgetTitleBar, True)
+ QtAds.CDockComponentsFactory.resetDefaultFactory()
+
+ # We create a calendar widget and clear all flags to prevent the dock area
+ # from closing
+ dock_widget = self.create_calendar_dock_widget()
+ dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
+ dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
+ # Now we create a action to test resizing of DockArea widget
+ action = self.menuTests.addAction("Resize {}".format(dock_widget.windowTitle()))
+ def action_triggered():
+ splitter = QtAds.internal.findParent(QtAds.CDockSplitter, dock_area)
+ if not splitter:
+ return
+ # We change the sizes of the splitter that contains the Calendar 1 widget
+ # to resize the dock widget
+ width = splitter.width()
+ splitter.setSizes([width * 2/3, width * 1/3])
+ action.triggered.connect(action_triggered)
+
+ # Now we add a custom button to the dock area title bar that will create
+ # new editor widgets when clicked
+ custom_button = QToolButton(dock_area)
+ custom_button.setToolTip("Create Editor")
+ custom_button.setIcon(svg_icon(":/adsdemo/images/plus.svg"))
+ custom_button.setAutoRaise(True)
+
+ title_bar = dock_area.titleBar()
+ index = title_bar.indexOf(title_bar.tabBar())
+ title_bar.insertWidget(index + 1, custom_button)
+ def on_button_clicked():
+ dock_widget = self.create_editor_widget()
+ dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
+ self.dock_manager.addDockWidgetTabToArea(dock_widget, dock_area)
+ dock_widget.closeRequested.connect(self.on_editor_close_requested)
+ custom_button.clicked.connect(on_button_clicked)
+
+ # Test dock area docking
+ right_dock_area = self.dock_manager.addDockWidget(
+ QtAds.RightDockWidgetArea,
+ self.create_long_text_label_dock_widget(), top_dock_area)
+ self.dock_manager.addDockWidget(
+ QtAds.TopDockWidgetArea,
+ self.create_long_text_label_dock_widget(), right_dock_area)
+
+ bottom_dock_area = self.dock_manager.addDockWidget(
+ QtAds.BottomDockWidgetArea,
+ self.create_long_text_label_dock_widget(), right_dock_area)
+
+ self.dock_manager.addDockWidget(
+ QtAds.CenterDockWidgetArea,
+ self.create_long_text_label_dock_widget(), right_dock_area)
+ self.dock_manager.addDockWidget(
+ QtAds.CenterDockWidgetArea,
+ self.create_long_text_label_dock_widget(), bottom_dock_area)
+
+
+ action = self.menuTests.addAction("Set {} Floating".format(dock_widget.windowTitle()))
+ action.triggered.connect(dock_widget.setFloating)
+ action = self.menuTests.addAction("Set {} As Current Tab".format(dock_widget.windowTitle()))
+ action.triggered.connect(dock_widget.setAsCurrentTab)
+ action = self.menuTests.addAction("Raise {}".format(dock_widget.windowTitle()))
+ action.triggered.connect(dock_widget.raise_)
+
+ if ACTIVEX_AVAILABLE:
+ flags = self.dock_manager.configFlags()
+ if flags & QtAds.CDockManager.OpaqueUndocking:
+ self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea,
+ self.create_activex_widget(), right_dock_area)
+
+ for dock_widget in self.dock_manager.dockWidgetsMap().values():
+ dock_widget.viewToggled.connect(self.on_view_toggled)
+ dock_widget.visibilityChanged.connect(self.on_view_visibility_changed)
+
+ def create_actions(self):
+ self.toolBar.addAction(self.actionSaveState)
+ self.toolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
+ self.actionSaveState.setIcon(svg_icon(":/adsdemo/images/save.svg"))
+ self.toolBar.addAction(self.actionRestoreState)
+ self.actionRestoreState.setIcon(svg_icon(":/adsdemo/images/restore.svg"))
+
+ self.save_perspective_action = QAction("Create Perspective", self)
+ self.save_perspective_action.setIcon(svg_icon(":/adsdemo/images/picture_in_picture.svg"))
+ self.save_perspective_action.triggered.connect(self.save_perspective)
+ self.perspective_list_action = QWidgetAction(self)
+ self.perspective_combo_box = QComboBox(self)
+ self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents)
+ self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+ self.perspective_list_action.setDefaultWidget(self.perspective_combo_box)
+ self.toolBar.addSeparator()
+ self.toolBar.addAction(self.perspective_list_action)
+ self.toolBar.addAction(self.save_perspective_action)
+
+ a = self.toolBar.addAction("Create Floating Editor")
+ a.setProperty("Floating", True)
+ a.setToolTip("Creates floating dynamic dockable editor windows that are deleted on close")
+ a.setIcon(svg_icon(":/adsdemo/images/note_add.svg"))
+ a.triggered.connect(self.create_editor)
+ self.menuTests.addAction(a)
+
+ a = self.toolBar.addAction("Create Docked Editor")
+ a.setProperty("Floating", False)
+ a.setToolTip("Creates a docked editor windows that are deleted on close")
+ a.setIcon(svg_icon(":/adsdemo/images/docked_editor.svg"))
+ a.triggered.connect(self.create_editor)
+ self.menuTests.addAction(a)
+
+ a = self.toolBar.addAction("Create Floating Table")
+ a.setToolTip("Creates floating dynamic dockable table with millions of entries")
+ a.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
+ a.triggered.connect(self.create_table)
+ self.menuTests.addAction(a)
+
+ self.menuTests.addSeparator()
+ a = self.menuTests.addAction("Show Status Dialog")
+ a.triggered.connect(self.show_status_dialog)
+ self.menuTests.addSeparator()
+
+ def closeEvent(self, event: QCloseEvent):
+ self.save_state()
+ self.dock_manager.deleteLater()
+ super().closeEvent(event)
+
+ def on_actionSaveState_triggered(self, state: bool):
+ qDebug("MainWindow::on_action_save_state_triggered")
+ self.save_state()
+
+ def on_actionRestoreState_triggered(self, state: bool):
+ qDebug("MainWindow::on_action_restore_state_triggered")
+ self.restore_state()
+
+ def save_perspective(self):
+ perspective_name, ok = QInputDialog.getText(self, "Save perspective",
+ "Enter unique name:")
+
+ if ok and perspective_name:
+ self.dock_manager.addPerspective(perspective_name)
+ _ = QSignalBlocker(self.perspective_combo_box)
+ self.perspective_combo_box.clear()
+ self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
+ self.perspective_combo_box.setCurrentText(perspective_name)
+
+ self.save_perspectives()
+
+ def on_view_toggled(self, open: bool):
+ dock_widget = self.sender()
+ if dock_widget is None:
+ return
+
+ qDebug("{} view_toggled({})".format(dock_widget.objectName(), open))
+
+ def on_view_visibility_changed(self, visible: bool):
+ dock_widget = self.sender()
+ if dock_widget is None:
+ return
+
+ # qDebug("{} visibility_changed({})".format(dock_widget.objectName(), visible))
+
+ def create_editor(self):
+ sender = self.sender()
+ floating = sender.property("Floating")
+ dock_widget = self.create_editor_widget()
+ dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
+ dock_widget.setFeature(QtAds.CDockWidget.DockWidgetForceCloseWithArea, True)
+ dock_widget.closeRequested.connect(self.on_editor_close_requested)
+
+ if floating:
+ floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget)
+ floating_widget.move(QPoint(20, 20))
+ else:
+ editor_area = self.last_docked_editor.dockAreaWidget() if self.last_docked_editor is not None else None
+ if editor_area is not None:
+ self.dock_manager.setConfigFlag(QtAds.CDockManager.EqualSplitOnInsertion, True)
+ self.dock_manager.addDockWidget(QtAds.RightDockWidgetArea, dock_widget, editor_area)
+ else:
+ self.dock_manager.addDockWidget(QtAds.TopDockWidgetArea, dock_widget)
+ self.last_docked_editor = dock_widget
+
+ def on_editor_close_requested(self):
+ dock_widget = self.sender()
+ result = QMessageBox.question(self, "Close Editor",
+ "Editor {} contains unsaved changes? Would you like to close it?".format(dock_widget.windowTitle()))
+ if result == QMessageBox.Yes:
+ dock_widget.closeDockWidget()
+
+ def create_table(self):
+ dock_widget = self.create_table_widget()
+ dock_widget.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
+ floating_widget = self.dock_manager.addDockWidgetFloating(dock_widget)
+ floating_widget.move(QPoint(40, 40))
+
+ def show_status_dialog(self):
+ dialog = CStatusDialog(self.dock_manager)
+ dialog.exec_()
+
+
+ def toggle_dock_widget_window_title(self):
+ title = self.window_title_test_dock_widget.windowTitle()
+ i = title.find(" (Test) ")
+ if i == -1:
+ title += " (Test) "
+ else:
+ title = title[i]
+ self.window_title_test_dock_widget.setWindowTitle(title)
+
+ def save_state(self):
+ '''
+ Saves the dock manager state and the main window geometry
+ '''
+ settings = QSettings("Settings.ini", QSettings.IniFormat)
+ settings.setValue("mainWindow/Geometry", self.saveGeometry())
+ settings.setValue("mainWindow/State", self.saveState())
+ settings.setValue("mainWindow/DockingState", self.dock_manager.saveState())
+
+ def restore_state(self):
+ '''
+ Restores the dock manager state
+ '''
+ settings = QSettings("Settings.ini", QSettings.IniFormat)
+ geom = settings.value("mainWindow/Geometry")
+ if geom is not None:
+ self.restoreGeometry(geom)
+
+ state = settings.value("mainWindow/State")
+ if state is not None:
+ self.restoreState(state)
+
+ state = settings.value("mainWindow/DockingState")
+ if state is not None:
+ self.dock_manager.restore_state(state)
+
+ def save_perspectives(self):
+ '''
+ Save the list of perspectives
+ '''
+ settings = QSettings("Settings.ini", QSettings.IniFormat)
+ self.dock_manager.savePerspectives(settings)
+
+ def restore_perspectives(self):
+ '''
+ Restore the perspective listo of the dock manager
+ '''
+ settings = QSettings("Settings.ini", QSettings.IniFormat)
+ self.dock_manager.loadPerspectives(settings)
+ self.perspective_combo_box.clear()
+ self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
+
+ def save_perspective(self):
+ perspective_name, ok = QInputDialog.getText(self, 'Save perspective', 'Enter unique name:')
+ if ok and perspective_name:
+ self.dock_manager.addPerspective(perspective_name)
+ _ = QSignalBlocker(self.perspective_combo_box)
+ self.perspective_combo_box.clear()
+ self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
+ self.perspective_combo_box.setCurrentText(perspective_name)
+ self.save_perspectives()
+
+ def create_long_text_label_dock_widget(self) -> QtAds.CDockWidget:
+ label = QLabel()
+ label.setWordWrap(True)
+ label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
+ label.setText('''Label {} {} - Lorem ipsum dolor sit amet, consectetuer
+ adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum
+ sociis natoque penatibus et magnis dis parturient montes, nascetur
+ ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium
+ quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla
+ vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut,
+ imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis
+ pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi.
+ Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu,
+ consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra
+ quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
+ '''.format(_State.label_count, datetime.datetime.now().strftime("%H:%M:%S:%f")))
+ dock_widget = QtAds.CDockWidget("Label {}".format(_State.label_count))
+ _State.label_count += 1
+ dock_widget.setWidget(label)
+
+ self.menuView.addAction(dock_widget.toggleViewAction())
+ return dock_widget
+
+ def create_calendar_dock_widget(self) -> QtAds.CDockWidget:
+ widget = QCalendarWidget()
+
+ dock_widget = QtAds.CDockWidget("Calendar {}".format(_State.calendar_count))
+ _State.calendar_count += 1
+ # The following lines are for testing the setWidget() and takeWidget()
+ # functionality
+ dock_widget.setWidget(widget)
+ dock_widget.setWidget(widget) # what happens if we set a widget if a widget is already set
+ dock_widget.takeWidget() # we remove the widget
+ dock_widget.setWidget(widget) # and set the widget again - there should be no error
+ dock_widget.setToggleViewActionMode(QtAds.CDockWidget.ActionModeShow)
+ dock_widget.setIcon(svg_icon(":/adsdemo/images/date_range.svg"))
+ self.menuView.addAction(dock_widget.toggleViewAction())
+ return dock_widget
+
+ def create_file_system_tree_dock_widget(self) -> QtAds.CDockWidget:
+ widget = QTreeView()
+ widget.setFrameShape(QFrame.NoFrame)
+
+ m = QFileSystemModel(widget)
+ m.setRootPath(QDir.currentPath())
+ widget.setModel(m)
+
+ dock_widget = QtAds.CDockWidget("Filesystem {}".format(_State.file_system_count))
+ _State.file_system_count += 1
+ dock_widget.setWidget(widget)
+ self.menuView.addAction(dock_widget.toggleViewAction())
+ return dock_widget
+
+ def create_editor_widget(self) -> QtAds.CDockWidget:
+ widget = QPlainTextEdit()
+ widget.setPlaceholderText("This is an editor. If you close the editor, it will be "
+ "deleted. Enter your text here.")
+ widget.setStyleSheet("border: none")
+ dock_widget = QtAds.CDockWidget("Editor {}".format(_State.editor_count))
+ _State.editor_count += 1
+ dock_widget.setWidget(widget)
+ dock_widget.setIcon(svg_icon(":/adsdemo/images/edit.svg"))
+ dock_widget.setFeature(QtAds.CDockWidget.CustomCloseHandling, True)
+ self.menuView.addAction(dock_widget.toggleViewAction())
+
+ options_menu = QMenu(dock_widget)
+ options_menu.setTitle("Options")
+ options_menu.setToolTip(options_menu.title())
+ options_menu.setIcon(svg_icon(":/adsdemo/images/custom-menu-button.svg"))
+ menu_action = options_menu.menuAction()
+ # The object name of the action will be set for the QToolButton that
+ # is created in the dock area title bar. You can use this name for CSS
+ # styling
+ menu_action.setObjectName("options_menu")
+ dock_widget.setTitleBarActions([options_menu.menuAction()])
+ a = options_menu.addAction("Clear Editor")
+ a.triggered.connect(widget.clear)
+
+ return dock_widget
+
+
+ def create_table_widget(self) -> QtAds.CDockWidget:
+ widget = CMinSizeTableWidget()
+ dock_widget = QtAds.CDockWidget("Table {}".format(_State.table_count))
+ _State.table_count += 1
+ COLCOUNT = 5
+ ROWCOUNT = 30
+ widget.setColumnCount(COLCOUNT)
+ widget.setRowCount(ROWCOUNT)
+ for col in range(ROWCOUNT):
+ widget.setHorizontalHeaderItem(col, QTableWidgetItem("Col {}".format(col + 1)))
+ for row in range(ROWCOUNT):
+ widget.setItem(row, col, QTableWidgetItem("T {:}-{:}".format(row + 1, col + 1)))
+
+ dock_widget.setWidget(widget)
+ dock_widget.setIcon(svg_icon(":/adsdemo/images/grid_on.svg"))
+ dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromContent)
+ toolbar = dock_widget.createDefaultToolBar()
+ action = toolbar.addAction(svg_icon(":/adsdemo/images/fullscreen.svg"), "Toggle Fullscreen")
+
+ def on_toggle_fullscreen():
+ if dock_widget.isFullScreen():
+ dock_widget.showNormal()
+ else:
+ dock_widget.showFullScreen()
+
+ action.triggered.connect(on_toggle_fullscreen)
+ self.menuView.addAction(dock_widget.toggleViewAction())
+ return dock_widget
+
+ def create_activex_widget(self, parent: QWidget = None) -> QtAds.CDockWidget:
+ widget = QAxWidget("{6bf52a52-394a-11d3-b153-00c04f79faa6}", parent)
+ dock_widget = QtAds.CDockWidget("Active X {}".format(_State.activex_count))
+ _State.activex_count += 1
+ dock_widget.setWidget(widget)
+ self.menuView.addAction(dock_widget.toggleViewAction())
+ return dock_widget
+
+
+def my_message_output(type, context, msg):
+ if type == QtDebugMsg:
+ print("Debug: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
+ elif type == QtInfoMsg:
+ print("Info: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
+ elif type == QtWarningMsg:
+ print("Warning: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
+ elif type == QtCriticalMsg:
+ print("Critical: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
+ elif type == QtFatalMsg:
+ print("Fatal: {} ({}:{}, {})".format(msg, context.file, context.line, context.function))
+
+
+if __name__ == '__main__':
+ QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
+ QGuiApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
+ app = QApplication(sys.argv)
+ app.setQuitOnLastWindowClosed(True)
+
+ with open(os.path.join(os.path.dirname(__file__), "app.css"), "r") as style_sheet_file:
+ app.setStyleSheet(style_sheet_file.read())
+
+ qInstallMessageHandler(my_message_output)
+ qDebug("Message handler test")
+
+ mw = MainWindow()
+ mw.show()
+ app.exec_()
diff --git a/QtADS/demo/mainwindow.ui b/QtADS/demo/mainwindow.ui
new file mode 100644
index 0000000..ea5c711
--- /dev/null
+++ b/QtADS/demo/mainwindow.ui
@@ -0,0 +1,87 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ MainWindow
+
+
+ QMainWindow::AllowTabbedDocks
+
+
+
+
+
+
+ 0
+ 0
+ 400
+ 21
+
+
+
+
+ File
+
+
+
+
+
+
+ View
+
+
+
+
+ About
+
+
+
+
+ Tests
+
+
+
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+ Exit
+
+
+
+
+ Save State
+
+
+
+
+ Restore State
+
+
+
+
+
+
+
diff --git a/QtADS/demo/res/visual_studio_light.css b/QtADS/demo/res/visual_studio_light.css
new file mode 100644
index 0000000..056163a
--- /dev/null
+++ b/QtADS/demo/res/visual_studio_light.css
@@ -0,0 +1,379 @@
+
+/*
+ * Visual Studio like light theme
+ */
+
+/*****************************************************************************
+ * CDockManager
+ *****************************************************************************/
+ads--CDockManager
+{
+ background: palette(window);
+}
+
+
+
+/*****************************************************************************
+ * CDockContainerWidget
+ *****************************************************************************/
+ads--CDockContainerWidget {
+ background: palette(window);
+ padding: 2px;
+}
+
+
+/*****************************************************************************
+ * CDockAreaWidget
+ *****************************************************************************/
+ads--CDockAreaWidget {
+ background: palette(window);
+ /*border: 1px solid palette(dark);*/
+}
+
+
+ads--CDockAreaTitleBar {
+ background: transparent;
+ border-bottom: 2px solid rgb(204, 204, 204);
+ padding-bottom: 0px;
+}
+
+
+ads--CTitleBarButton {
+ padding: 0px 0px;
+ background: transparent;
+ border: none;
+}
+
+ads--CTitleBarButton:hover {
+ background: rgba(0, 0, 0, 24);
+}
+
+ads--CTitleBarButton:pressed {
+ background: rgba(0, 0, 0, 48);
+}
+
+QScrollArea#dockWidgetScrollArea {
+ padding: 0px;
+ border: none;
+}
+
+#tabsMenuButton::menu-indicator {
+ image: none;
+}
+
+
+#dockAreaCloseButton {
+ qproperty-icon: url(:/ads/images/close-button.svg),
+ url(:/ads/images/close-button-disabled.svg) disabled;
+ qproperty-iconSize: 16px;
+}
+
+#detachGroupButton {
+ qproperty-icon: url(:/ads/images/detach-button.svg),
+ url(:/ads/images/detach-button-disabled.svg) disabled;
+ qproperty-iconSize: 16px;
+}
+
+
+ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar {
+ border-bottom: 2px solid palette(highlight);
+}
+
+
+/*****************************************************************************
+ * CDockWidgetTab
+ *****************************************************************************/
+ads--CDockWidgetTab {
+ background: palette(window);
+ border: none;
+ padding: 0 0px;
+ qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/
+}
+
+ads--CDockWidgetTab[activeTab="true"] {
+ background: rgb(204, 204, 204);
+}
+
+ads--CDockWidgetTab QLabel {
+ color: palette(foreground);
+}
+
+ads--CDockWidgetTab[activeTab="true"] QLabel {
+ color: palette(foreground);
+}
+
+
+#tabCloseButton {
+ margin-top: 2px;
+ background: none;
+ border: none;
+ padding: 0px -2px;
+ qproperty-icon: url(:/ads/images/close-button.svg),
+ url(:/ads/images/close-button-disabled.svg) disabled;
+ qproperty-iconSize: 16px;
+}
+
+#tabCloseButton:hover {
+ /*border: 1px solid rgba(0, 0, 0, 32);*/
+ background: rgba(0, 0, 0, 24);
+}
+
+#tabCloseButton:pressed {
+ background: rgba(0, 0, 0, 48);
+}
+
+
+/* Focus related styling */
+ads--CDockWidgetTab[focused="true"] {
+ background: palette(highlight);
+ border-color: palette(highlight);
+}
+
+ads--CDockWidgetTab[focused="true"] > #tabCloseButton {
+ qproperty-icon: url(:/ads/images/close-button-focused.svg)
+}
+
+ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover {
+ background: rgba(255, 255, 255, 48);
+}
+
+ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed {
+ background: rgba(255, 255, 255, 92);
+}
+
+ads--CDockWidgetTab[focused="true"] QLabel {
+ color: palette(light);
+}
+
+
+/*****************************************************************************
+ * CDockWidget
+ *****************************************************************************/
+ads--CDockWidget {
+ background: palette(light);
+ border: 1px solid rgb(204, 204, 204);
+ border-top: none;
+}
+
+
+
+/*****************************************************************************
+ *
+ * Styling of auto hide functionality
+ *
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ * CAutoHideTab
+ *****************************************************************************/
+ads--CAutoHideTab {
+ qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/
+ background: none;
+ border: none;
+ padding-left: 2px;
+ padding-right: 0px;
+ text-align: center;
+ min-height: 20px;
+ padding-bottom: 2px;
+}
+
+
+ads--CAutoHideTab:hover
+{
+ color: palette(highlight);
+}
+
+
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"],
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"] {
+ border-top: 6px solid rgba(0, 0, 0, 48);
+}
+
+
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"],
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"] {
+ border-bottom: 6px solid rgba(0, 0, 0, 48);
+}
+
+
+
+ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="0"],
+ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="2"],
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"][activeTab="true"],
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"][activeTab="true"] {
+ border-top: 6px solid palette(highlight);
+}
+
+
+ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="1"],
+ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="3"],
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"][activeTab="true"],
+ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"][activeTab="true"] {
+ border-bottom: 6px solid palette(highlight);
+}
+
+
+/**
+ * Auto hide tabs with icon only
+ */
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"] {
+ border-top: 6px solid rgba(0, 0, 0, 48);
+}
+
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"] {
+ border-left: 6px solid rgba(0, 0, 0, 48);
+}
+
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"] {
+ border-right: 6px solid rgba(0, 0, 0, 48);
+}
+
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"] {
+ border-bottom: 6px solid rgba(0, 0, 0, 48);
+}
+
+
+/**
+ * Auto hide tabs with icon only hover
+ */
+ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="0"],
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"][activeTab="true"] {
+ border-top: 6px solid palette(highlight);
+}
+
+ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="1"],
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"][activeTab="true"] {
+ border-left: 6px solid palette(highlight);
+}
+
+ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="2"],
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"][activeTab="true"] {
+ border-right: 6px solid palette(highlight);
+}
+
+ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="3"],
+ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] {
+ border-bottom: 6px solid palette(highlight);
+}
+
+
+
+/*****************************************************************************
+ * CAutoHideSideBar
+ *****************************************************************************/
+ads--CAutoHideSideBar{
+ background: palette(window);
+ border: none;
+ qproperty-spacing: 12;
+}
+
+#sideTabsContainerWidget {
+ background: transparent;
+}
+
+
+ads--CAutoHideSideBar[sideBarLocation="0"] {
+ border-bottom: 1px solid palette(dark);
+}
+
+ads--CAutoHideSideBar[sideBarLocation="1"] {
+ border-right: 1px solid palette(dark);
+}
+
+ads--CAutoHideSideBar[sideBarLocation="2"] {
+ border-left: 1px solid palette(dark);
+}
+
+ads--CAutoHideSideBar[sideBarLocation="3"] {
+ border-top: 1px solid palette(dark);
+}
+
+
+/*****************************************************************************
+ * CAutoHideDockContainer
+ *****************************************************************************/
+ads--CAutoHideDockContainer {
+ background: palette(window);
+}
+
+
+ads--CAutoHideDockContainer ads--CDockAreaTitleBar {
+ background: palette(highlight);
+ padding: 0px;
+ border: none;
+}
+
+
+/*
+ * This is required because the ads--CDockAreaWidget[focused="true"] will
+ * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule
+ */
+ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar {
+ background: palette(highlight);
+ padding: 0px;
+ border: none;
+}
+
+
+#autoHideTitleLabel {
+ padding-left: 4px;
+ color: palette(light);
+}
+
+
+/*****************************************************************************
+ * CAutoHideDockContainer titlebar buttons
+ *****************************************************************************/
+#dockAreaAutoHideButton {
+ qproperty-icon: url(:/ads/images/vs-pin-button.svg);
+ qproperty-iconSize: 16px;
+}
+
+ads--CAutoHideDockContainer #dockAreaAutoHideButton {
+ qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg);
+ qproperty-iconSize: 16px;
+}
+
+
+ads--CAutoHideDockContainer #dockAreaCloseButton{
+ qproperty-icon: url(:/ads/images/close-button-focused.svg)
+}
+
+
+ads--CAutoHideDockContainer ads--CTitleBarButton:hover {
+ background: rgba(255, 255, 255, 48);
+}
+
+ads--CAutoHideDockContainer ads--CTitleBarButton:pressed {
+ background: rgba(255, 255, 255, 96);
+}
+
+/*****************************************************************************
+ * CAutoHideDockContainer Titlebar and Buttons
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ * CResizeHandle
+ *****************************************************************************/
+ads--CResizeHandle {
+ background: palette(window);
+}
+
+
+ads--CAutoHideDockContainer[sideBarLocation="0"] ads--CResizeHandle {
+ border-top: 1px solid palette(dark);
+}
+
+ads--CAutoHideDockContainer[sideBarLocation="1"] ads--CResizeHandle {
+ border-left: 1px solid palette(dark);
+}
+
+ads--CAutoHideDockContainer[sideBarLocation="2"] ads--CResizeHandle {
+ border-right: 1px solid palette(dark);
+}
+
+ads--CAutoHideDockContainer[sideBarLocation="3"] ads--CResizeHandle {
+ border-top: 1px solid palette(dark);
+}
diff --git a/QtADS/demo/status_dialog.py b/QtADS/demo/status_dialog.py
new file mode 100644
index 0000000..cf58a38
--- /dev/null
+++ b/QtADS/demo/status_dialog.py
@@ -0,0 +1,38 @@
+import os
+import sys
+
+from PyQt5 import uic
+import PyQtAds as QtAds
+
+UI_FILE = os.path.join(os.path.dirname(__file__), 'StatusDialog.ui')
+StatusDialogUI, StatusDialogBase = uic.loadUiType(UI_FILE)
+
+class CStatusDialog(StatusDialogUI, StatusDialogBase):
+
+ def __init__(self, dock_manager: QtAds.CDockManager, parent=None):
+ super().__init__(parent)
+
+ self.setupUi(self)
+
+ self.dock_manager = dock_manager
+ self.dock_widgets = self.dock_manager.dockWidgetsMap()
+
+ for key, widget in self.dock_widgets.items():
+ self.dockWidgetsComboBox.addItem(key, widget)
+
+ def on_dockWidgetsComboBox_currentIndexChanged(self, index: int):
+ if not isinstance(index, int):
+ return
+ if index < 0:
+ return
+
+ dock_widget = self.dockWidgetsComboBox.currentData()
+ self.isClosedCheckBox.setChecked(dock_widget.isClosed())
+ self.isFloatingCheckBox.setChecked(dock_widget.isFloating())
+ self.tabbedCheckBox.setChecked(dock_widget.isTabbed())
+ self.isCurrentTabCheckBox.setChecked(dock_widget.isCurrentTab())
+ self.closableCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetClosable)
+ self.movableCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetMovable)
+ self.floatableCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetFloatable)
+ self.deleteOnCloseCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.DockWidgetDeleteOnClose)
+ self.customCloseHandlingCheckBox.setChecked(dock_widget.features() & QtAds.CDockWidget.CustomCloseHandling)
diff --git a/QtADS/doc/AutoHide_Animation.gif b/QtADS/doc/AutoHide_Animation.gif
new file mode 100644
index 0000000..c82fad1
Binary files /dev/null and b/QtADS/doc/AutoHide_Animation.gif differ
diff --git a/QtADS/doc/AutoHide_Change_Sidebar.gif b/QtADS/doc/AutoHide_Change_Sidebar.gif
new file mode 100644
index 0000000..07312fb
Binary files /dev/null and b/QtADS/doc/AutoHide_Change_Sidebar.gif differ
diff --git a/QtADS/doc/AutoHide_Context_Menu.png b/QtADS/doc/AutoHide_Context_Menu.png
new file mode 100644
index 0000000..614e706
Binary files /dev/null and b/QtADS/doc/AutoHide_Context_Menu.png differ
diff --git a/QtADS/doc/AutoHide_Drag_DockArea.gif b/QtADS/doc/AutoHide_Drag_DockArea.gif
new file mode 100644
index 0000000..50e1872
Binary files /dev/null and b/QtADS/doc/AutoHide_Drag_DockArea.gif differ
diff --git a/QtADS/doc/AutoHide_Drag_to_Float_or_Dock.gif b/QtADS/doc/AutoHide_Drag_to_Float_or_Dock.gif
new file mode 100644
index 0000000..fa7f0ba
Binary files /dev/null and b/QtADS/doc/AutoHide_Drag_to_Float_or_Dock.gif differ
diff --git a/QtADS/doc/AutoHide_Drag_to_Sidebar.gif b/QtADS/doc/AutoHide_Drag_to_Sidebar.gif
new file mode 100644
index 0000000..72e998f
Binary files /dev/null and b/QtADS/doc/AutoHide_Drag_to_Sidebar.gif differ
diff --git a/QtADS/doc/AutoHide_Movie.gif b/QtADS/doc/AutoHide_Movie.gif
new file mode 100644
index 0000000..19aa78c
Binary files /dev/null and b/QtADS/doc/AutoHide_Movie.gif differ
diff --git a/QtADS/doc/AutoHide_PinTo.png b/QtADS/doc/AutoHide_PinTo.png
new file mode 100644
index 0000000..5f653e5
Binary files /dev/null and b/QtADS/doc/AutoHide_PinTo.png differ
diff --git a/QtADS/doc/AutoHide_Sort_Tabs.gif b/QtADS/doc/AutoHide_Sort_Tabs.gif
new file mode 100644
index 0000000..6bac89c
Binary files /dev/null and b/QtADS/doc/AutoHide_Sort_Tabs.gif differ
diff --git a/QtADS/doc/AutoHide_Tab_Insert_Order.gif b/QtADS/doc/AutoHide_Tab_Insert_Order.gif
new file mode 100644
index 0000000..391d80a
Binary files /dev/null and b/QtADS/doc/AutoHide_Tab_Insert_Order.gif differ
diff --git a/QtADS/doc/DockArea_Tab_Insertion_Order.gif b/QtADS/doc/DockArea_Tab_Insertion_Order.gif
new file mode 100644
index 0000000..2823d76
Binary files /dev/null and b/QtADS/doc/DockArea_Tab_Insertion_Order.gif differ
diff --git a/QtADS/doc/Feature_ImageViewer.png b/QtADS/doc/Feature_ImageViewer.png
new file mode 100644
index 0000000..b1eb521
Binary files /dev/null and b/QtADS/doc/Feature_ImageViewer.png differ
diff --git a/QtADS/doc/TabMenu.png b/QtADS/doc/TabMenu.png
new file mode 100644
index 0000000..44f1760
Binary files /dev/null and b/QtADS/doc/TabMenu.png differ
diff --git a/QtADS/doc/TabMenu_dark.png b/QtADS/doc/TabMenu_dark.png
new file mode 100644
index 0000000..f7f7447
Binary files /dev/null and b/QtADS/doc/TabMenu_dark.png differ
diff --git a/QtADS/doc/ads_icon.svg b/QtADS/doc/ads_icon.svg
new file mode 100644
index 0000000..4231be6
--- /dev/null
+++ b/QtADS/doc/ads_icon.svg
@@ -0,0 +1,77 @@
+
+
diff --git a/QtADS/doc/ads_icon_256.png b/QtADS/doc/ads_icon_256.png
new file mode 100644
index 0000000..3e7c912
Binary files /dev/null and b/QtADS/doc/ads_icon_256.png differ
diff --git a/QtADS/doc/ads_icon_512.png b/QtADS/doc/ads_icon_512.png
new file mode 100644
index 0000000..a86ff61
Binary files /dev/null and b/QtADS/doc/ads_icon_512.png differ
diff --git a/QtADS/doc/ads_logo.svg b/QtADS/doc/ads_logo.svg
new file mode 100644
index 0000000..13edf85
--- /dev/null
+++ b/QtADS/doc/ads_logo.svg
@@ -0,0 +1,33 @@
+
+
diff --git a/QtADS/doc/ads_logo_ukraine.jpg b/QtADS/doc/ads_logo_ukraine.jpg
new file mode 100644
index 0000000..bf36a02
Binary files /dev/null and b/QtADS/doc/ads_logo_ukraine.jpg differ
diff --git a/QtADS/doc/ads_qt_marketplace_description.md b/QtADS/doc/ads_qt_marketplace_description.md
new file mode 100644
index 0000000..1d8c987
--- /dev/null
+++ b/QtADS/doc/ads_qt_marketplace_description.md
@@ -0,0 +1,101 @@
+# Advanced Docking System for Qt
+
+Qt Advanced Docking System lets you create customizable layouts using a full
+featured window docking system similar to what is found in many popular
+integrated development environments (IDEs) such as Visual Studio.
+
+[](https://www.youtube.com/watch?v=7pdNfafg3Qc)
+
+Everything is implemented with standard Qt functionality without any
+platform specific code. Basic usage of QWidgets and QLayouts and using basic
+styles as much as possible.
+
+## Features
+
+### Docking everywhere - with or without a central widget
+
+The Advanced Docking System works with or without a central widget.
+You can dock on every border of the main window or you can dock into each dock area - so you are
+free to dock almost everywhere.
+
+
+
+
+
+### Docking inside floating windows
+
+There is no difference between the main window and a floating window. Docking
+into floating windows is supported.
+
+
+
+
+
+### Grouped dragging
+
+When dragging the titlebar of a dock, all the tabs that are tabbed with it are
+going to be dragged. So you can move complete groups of tabbed widgets into
+a floating widget or from one dock area to another one.
+
+
+
+
+
+### Perspectives for fast switching of the complete main window layout
+
+A perspective defines the set and layout of dock windows in the main
+window. You can save the current layout of the dockmanager into a named
+perspective to make your own custom perspective. Later you can simply
+select a perspective from the perspective list to quickly switch the complete
+main window layout.
+
+
+
+
+
+### Opaque and non-opaque splitter resizing
+
+The advanced docking system uses standard QSplitters as resize separators and thus supports opaque and non-opaque resizing functionality of QSplitter. In some rare cases, for very complex widgets or on slow machines resizing via separator on the fly may cause flicking and glaring of rendered content inside a widget. The global dock manager flag `OpaqueSplitterResize` configures the resizing behaviour of the splitters. If this flag is set, then widgets are resized dynamically (opaquely) while interactively moving the splitters.
+
+
+
+If this flag is cleared, the widget resizing is deferred until the mouse button is released - this is some kind of lazy resizing separator.
+
+
+
+### Opaque and non-opaque undocking
+
+By default, opaque undocking is active. That means, as soon as you drag a dock widget or a dock area with a number of dock widgets it will be undocked and moved into a floating widget and then the floating widget will be dragged around. That means undocking will take place immediately. You can compare this with opaque splitter resizing. If the flag `OpaqueUndocking` is cleared, then non-opaque undocking is active. In this mode, undocking is more like a standard drag and drop operation. That means, the dragged dock widget or dock area is not undocked immediately. Instead, a drag preview widget is created and dragged around to indicate the future position of the dock widget or dock area. The actual dock operation is only executed when the mouse button is released. That makes it possible, to cancel an active drag operation with the escape key.
+
+The drag preview widget can be configured by a number of global dock manager flags:
+
+- `DragPreviewIsDynamic`: if this flag is enabled, the preview will be adjusted dynamically to the drop area
+- `DragPreviewShowsContentPixmap`: the created drag preview window shows a static copy of the content of the dock widget / dock are that is dragged
+- `DragPreviewHasWindowFrame`: this flag configures if the drag preview is frameless like a QRubberBand or looks like a real window
+
+The best way to test non-opaque undocking is to set the standard flags: `CDockManager::setConfigFlags(CDockManager::DefaultNonOpaqueConfig)`.
+
+### Tab-menu for easy handling of many tabbed dock widgets
+
+Tabs are a good way to quickly switch between dockwidgets in a dockarea. However, if the number of dockwidgets in a dockarea is too large, this may affect the usability of the tab bar. To keep track in this situation, you can use the tab menu. The menu allows you to quickly select the dockwidget you want to activate from a drop down menu.
+
+
+
+### Many different ways to detach dock widgets
+
+You can detach dock widgets and also dock areas in the following ways:
+
+- by dragging the dock widget tab or the dock area title bar
+- by double clicking the tab or title bar
+- by using the detach menu entry from the tab and title bar drop down menu
+
+### Supports deletion of dynamically created dock widgets
+
+Normally clicking the close button of a dock widget will just hide the widget and the user can show it again using the toggleView() action of the dock widget. This is meant for user interfaces with a static amount of widgets. But the advanced docking system also supports dynamic dock widgets that will get deleted on close. If you set the dock widget flag `DockWidgetDeleteOnClose` for a certain dock widget, then it will be deleted as soon as you close this dock widget. This enables the implementation of user interfaces with dynamically created editors, like in word processing applications or source code development tools.
+
+### Python PyQt5 Bindings
+
+
+
+The Advanced Docking System comes with a complete Python integration based on
+PyQt5 bindings. The package is available via [conda-forge](https://github.com/conda-forge/pyqtads-feedstock).
diff --git a/QtADS/doc/ads_qt_marketplace_manifest.json b/QtADS/doc/ads_qt_marketplace_manifest.json
new file mode 100644
index 0000000..2c733a7
--- /dev/null
+++ b/QtADS/doc/ads_qt_marketplace_manifest.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "http://qt.io/schema/extension-schema-v1#",
+ "title": "Qt Advanced Docking System",
+ "extensionType": [
+ "library"
+ ],
+ "version": "3.8.2",
+ "vendor": {
+ "name": "githubuser0xFFFF",
+ "url": "https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System"
+ },
+ "contact": "https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues",
+ "icon": "https://raw.githubusercontent.com/githubuser0xFFFF/Qt-Advanced-Docking-System/master/doc/ads_icon.svg",
+ "licenses": [
+ { "licenseType": "LGPL-2.1-only",
+ "licenseUrl": "https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" }
+ ],
+ "created": "2017-03-30",
+ "lastUpdate": "2022-03-02",
+ "platforms": [
+ "Windows 7-11", "Kubuntu 18.04", "Kubuntu 19.10", "Ubuntu 19.10", "Ubuntu 20.04"
+ ],
+ "qtVersions": [
+ "5.5.1 or newer"
+ ],
+ "tags": [
+ "Widgets", "Docking"],
+ "bugUrl": "https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues",
+ "sourceRepoUrl": "https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System"
+}
diff --git a/QtADS/doc/advanced-docking_video.png b/QtADS/doc/advanced-docking_video.png
new file mode 100644
index 0000000..3280ba8
Binary files /dev/null and b/QtADS/doc/advanced-docking_video.png differ
diff --git a/QtADS/doc/autohide-feature-demo.png b/QtADS/doc/autohide-feature-demo.png
new file mode 100644
index 0000000..9e7eff7
Binary files /dev/null and b/QtADS/doc/autohide-feature-demo.png differ
diff --git a/QtADS/doc/central_widget.gif b/QtADS/doc/central_widget.gif
new file mode 100644
index 0000000..e766741
Binary files /dev/null and b/QtADS/doc/central_widget.gif differ
diff --git a/QtADS/doc/cfg_flag_ActiveTabHasCloseButton_false.png b/QtADS/doc/cfg_flag_ActiveTabHasCloseButton_false.png
new file mode 100644
index 0000000..3632baa
Binary files /dev/null and b/QtADS/doc/cfg_flag_ActiveTabHasCloseButton_false.png differ
diff --git a/QtADS/doc/cfg_flag_ActiveTabHasCloseButton_true.png b/QtADS/doc/cfg_flag_ActiveTabHasCloseButton_true.png
new file mode 100644
index 0000000..be83d37
Binary files /dev/null and b/QtADS/doc/cfg_flag_ActiveTabHasCloseButton_true.png differ
diff --git a/QtADS/doc/cfg_flag_AllTabsHaveCloseButton_true.png b/QtADS/doc/cfg_flag_AllTabsHaveCloseButton_true.png
new file mode 100644
index 0000000..f925cba
Binary files /dev/null and b/QtADS/doc/cfg_flag_AllTabsHaveCloseButton_true.png differ
diff --git a/QtADS/doc/cfg_flag_AlwaysShowTabs_false_true.png b/QtADS/doc/cfg_flag_AlwaysShowTabs_false_true.png
new file mode 100644
index 0000000..3c192cd
Binary files /dev/null and b/QtADS/doc/cfg_flag_AlwaysShowTabs_false_true.png differ
diff --git a/QtADS/doc/cfg_flag_AutoHideCloseButtonCollapsesDock_false.gif b/QtADS/doc/cfg_flag_AutoHideCloseButtonCollapsesDock_false.gif
new file mode 100644
index 0000000..24c7c99
Binary files /dev/null and b/QtADS/doc/cfg_flag_AutoHideCloseButtonCollapsesDock_false.gif differ
diff --git a/QtADS/doc/cfg_flag_AutoHideCloseButtonCollapsesDock_true.gif b/QtADS/doc/cfg_flag_AutoHideCloseButtonCollapsesDock_true.gif
new file mode 100644
index 0000000..4b971c4
Binary files /dev/null and b/QtADS/doc/cfg_flag_AutoHideCloseButtonCollapsesDock_true.gif differ
diff --git a/QtADS/doc/cfg_flag_AutoHideHasCloseButton.png b/QtADS/doc/cfg_flag_AutoHideHasCloseButton.png
new file mode 100644
index 0000000..4cd16a3
Binary files /dev/null and b/QtADS/doc/cfg_flag_AutoHideHasCloseButton.png differ
diff --git a/QtADS/doc/cfg_flag_AutoHideHasMinimizeButton.png b/QtADS/doc/cfg_flag_AutoHideHasMinimizeButton.png
new file mode 100644
index 0000000..f99143a
Binary files /dev/null and b/QtADS/doc/cfg_flag_AutoHideHasMinimizeButton.png differ
diff --git a/QtADS/doc/cfg_flag_AutoHideSideBarsIconOnly_false.png b/QtADS/doc/cfg_flag_AutoHideSideBarsIconOnly_false.png
new file mode 100644
index 0000000..95293a6
Binary files /dev/null and b/QtADS/doc/cfg_flag_AutoHideSideBarsIconOnly_false.png differ
diff --git a/QtADS/doc/cfg_flag_AutoHideSideBarsIconOnly_true.png b/QtADS/doc/cfg_flag_AutoHideSideBarsIconOnly_true.png
new file mode 100644
index 0000000..575fdea
Binary files /dev/null and b/QtADS/doc/cfg_flag_AutoHideSideBarsIconOnly_true.png differ
diff --git a/QtADS/doc/cfg_flag_DisableTabTextEliding_false.png b/QtADS/doc/cfg_flag_DisableTabTextEliding_false.png
new file mode 100644
index 0000000..72acc4e
Binary files /dev/null and b/QtADS/doc/cfg_flag_DisableTabTextEliding_false.png differ
diff --git a/QtADS/doc/cfg_flag_DisableTabTextEliding_true.png b/QtADS/doc/cfg_flag_DisableTabTextEliding_true.png
new file mode 100644
index 0000000..256eba3
Binary files /dev/null and b/QtADS/doc/cfg_flag_DisableTabTextEliding_true.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaDynamicTabsMenuButtonVisibility_true_hidden.png b/QtADS/doc/cfg_flag_DockAreaDynamicTabsMenuButtonVisibility_true_hidden.png
new file mode 100644
index 0000000..52a5388
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaDynamicTabsMenuButtonVisibility_true_hidden.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaDynamicTabsMenuButtonVisibility_true_visible.png b/QtADS/doc/cfg_flag_DockAreaDynamicTabsMenuButtonVisibility_true_visible.png
new file mode 100644
index 0000000..5d2ae0a
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaDynamicTabsMenuButtonVisibility_true_visible.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaHasAutoHideButton.png b/QtADS/doc/cfg_flag_DockAreaHasAutoHideButton.png
new file mode 100644
index 0000000..0ca1013
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaHasAutoHideButton.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaHasCloseButton_false.png b/QtADS/doc/cfg_flag_DockAreaHasCloseButton_false.png
new file mode 100644
index 0000000..9109146
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaHasCloseButton_false.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaHasCloseButton_true.png b/QtADS/doc/cfg_flag_DockAreaHasCloseButton_true.png
new file mode 100644
index 0000000..b35afc2
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaHasCloseButton_true.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaHasTabsMenuButton_false_true.png b/QtADS/doc/cfg_flag_DockAreaHasTabsMenuButton_false_true.png
new file mode 100644
index 0000000..d61801f
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaHasTabsMenuButton_false_true.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaHasUndockButton_false_true.png b/QtADS/doc/cfg_flag_DockAreaHasUndockButton_false_true.png
new file mode 100644
index 0000000..b421684
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaHasUndockButton_false_true.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaHideDisabledButtons_false.png b/QtADS/doc/cfg_flag_DockAreaHideDisabledButtons_false.png
new file mode 100644
index 0000000..e983108
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaHideDisabledButtons_false.png differ
diff --git a/QtADS/doc/cfg_flag_DockAreaHideDisabledButtons_true.png b/QtADS/doc/cfg_flag_DockAreaHideDisabledButtons_true.png
new file mode 100644
index 0000000..869e004
Binary files /dev/null and b/QtADS/doc/cfg_flag_DockAreaHideDisabledButtons_true.png differ
diff --git a/QtADS/doc/cfg_flag_DragPreviewHasWindowFrame_true.png b/QtADS/doc/cfg_flag_DragPreviewHasWindowFrame_true.png
new file mode 100644
index 0000000..c61396e
Binary files /dev/null and b/QtADS/doc/cfg_flag_DragPreviewHasWindowFrame_true.png differ
diff --git a/QtADS/doc/cfg_flag_DragPreviewShowsContentPixmap_false.png b/QtADS/doc/cfg_flag_DragPreviewShowsContentPixmap_false.png
new file mode 100644
index 0000000..6acdc28
Binary files /dev/null and b/QtADS/doc/cfg_flag_DragPreviewShowsContentPixmap_false.png differ
diff --git a/QtADS/doc/cfg_flag_DragPreviewShowsContentPixmap_true.png b/QtADS/doc/cfg_flag_DragPreviewShowsContentPixmap_true.png
new file mode 100644
index 0000000..dc7f090
Binary files /dev/null and b/QtADS/doc/cfg_flag_DragPreviewShowsContentPixmap_true.png differ
diff --git a/QtADS/doc/cfg_flag_EqualSplitOnInsertion_false.png b/QtADS/doc/cfg_flag_EqualSplitOnInsertion_false.png
new file mode 100644
index 0000000..a72cb77
Binary files /dev/null and b/QtADS/doc/cfg_flag_EqualSplitOnInsertion_false.png differ
diff --git a/QtADS/doc/cfg_flag_EqualSplitOnInsertion_true.png b/QtADS/doc/cfg_flag_EqualSplitOnInsertion_true.png
new file mode 100644
index 0000000..69891ac
Binary files /dev/null and b/QtADS/doc/cfg_flag_EqualSplitOnInsertion_true.png differ
diff --git a/QtADS/doc/cfg_flag_FloatingContainerForceNativeTitleBar_false.png b/QtADS/doc/cfg_flag_FloatingContainerForceNativeTitleBar_false.png
new file mode 100644
index 0000000..3cdb8c9
Binary files /dev/null and b/QtADS/doc/cfg_flag_FloatingContainerForceNativeTitleBar_false.png differ
diff --git a/QtADS/doc/cfg_flag_FloatingContainerForceNativeTitleBar_true.png b/QtADS/doc/cfg_flag_FloatingContainerForceNativeTitleBar_true.png
new file mode 100644
index 0000000..2b06fb2
Binary files /dev/null and b/QtADS/doc/cfg_flag_FloatingContainerForceNativeTitleBar_true.png differ
diff --git a/QtADS/doc/cfg_flag_FloatingContainerHasWidgetIcon_false.png b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetIcon_false.png
new file mode 100644
index 0000000..31b7d33
Binary files /dev/null and b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetIcon_false.png differ
diff --git a/QtADS/doc/cfg_flag_FloatingContainerHasWidgetIcon_true.png b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetIcon_true.png
new file mode 100644
index 0000000..3723dda
Binary files /dev/null and b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetIcon_true.png differ
diff --git a/QtADS/doc/cfg_flag_FloatingContainerHasWidgetTitle_false.png b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetTitle_false.png
new file mode 100644
index 0000000..8bb19d9
Binary files /dev/null and b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetTitle_false.png differ
diff --git a/QtADS/doc/cfg_flag_FloatingContainerHasWidgetTitle_true.png b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetTitle_true.png
new file mode 100644
index 0000000..fc79173
Binary files /dev/null and b/QtADS/doc/cfg_flag_FloatingContainerHasWidgetTitle_true.png differ
diff --git a/QtADS/doc/cfg_flag_FocusHighlighting.gif b/QtADS/doc/cfg_flag_FocusHighlighting.gif
new file mode 100644
index 0000000..e9f5782
Binary files /dev/null and b/QtADS/doc/cfg_flag_FocusHighlighting.gif differ
diff --git a/QtADS/doc/cfg_flag_HideSingleCentralWidgetTitleBar_false.png b/QtADS/doc/cfg_flag_HideSingleCentralWidgetTitleBar_false.png
new file mode 100644
index 0000000..0891661
Binary files /dev/null and b/QtADS/doc/cfg_flag_HideSingleCentralWidgetTitleBar_false.png differ
diff --git a/QtADS/doc/cfg_flag_HideSingleCentralWidgetTitleBar_true.png b/QtADS/doc/cfg_flag_HideSingleCentralWidgetTitleBar_true.png
new file mode 100644
index 0000000..851efeb
Binary files /dev/null and b/QtADS/doc/cfg_flag_HideSingleCentralWidgetTitleBar_true.png differ
diff --git a/QtADS/doc/cfg_flag_MiddleMouseButtonClosesTab.gif b/QtADS/doc/cfg_flag_MiddleMouseButtonClosesTab.gif
new file mode 100644
index 0000000..a6b0097
Binary files /dev/null and b/QtADS/doc/cfg_flag_MiddleMouseButtonClosesTab.gif differ
diff --git a/QtADS/doc/cfg_flag_RetainTabSizeWhenCloseButtonHidden_true.png b/QtADS/doc/cfg_flag_RetainTabSizeWhenCloseButtonHidden_true.png
new file mode 100644
index 0000000..0bc7f6f
Binary files /dev/null and b/QtADS/doc/cfg_flag_RetainTabSizeWhenCloseButtonHidden_true.png differ
diff --git a/QtADS/doc/cfg_flag_ShowTabTextOnlyForActiveTab_true.png b/QtADS/doc/cfg_flag_ShowTabTextOnlyForActiveTab_true.png
new file mode 100644
index 0000000..8678bc4
Binary files /dev/null and b/QtADS/doc/cfg_flag_ShowTabTextOnlyForActiveTab_true.png differ
diff --git a/QtADS/doc/donate.png b/QtADS/doc/donate.png
new file mode 100644
index 0000000..8d0b0ab
Binary files /dev/null and b/QtADS/doc/donate.png differ
diff --git a/QtADS/doc/dynamic_drag_preview.gif b/QtADS/doc/dynamic_drag_preview.gif
new file mode 100644
index 0000000..669a4fd
Binary files /dev/null and b/QtADS/doc/dynamic_drag_preview.gif differ
diff --git a/QtADS/doc/floating-widget-dragndrop.png b/QtADS/doc/floating-widget-dragndrop.png
new file mode 100644
index 0000000..b9f8682
Binary files /dev/null and b/QtADS/doc/floating-widget-dragndrop.png differ
diff --git a/QtADS/doc/floating-widget-dragndrop_dark.png b/QtADS/doc/floating-widget-dragndrop_dark.png
new file mode 100644
index 0000000..afca242
Binary files /dev/null and b/QtADS/doc/floating-widget-dragndrop_dark.png differ
diff --git a/QtADS/doc/grouped-dragging.gif b/QtADS/doc/grouped-dragging.gif
new file mode 100644
index 0000000..a27d04d
Binary files /dev/null and b/QtADS/doc/grouped-dragging.gif differ
diff --git a/QtADS/doc/grouped-dragging.png b/QtADS/doc/grouped-dragging.png
new file mode 100644
index 0000000..d6a12e9
Binary files /dev/null and b/QtADS/doc/grouped-dragging.png differ
diff --git a/QtADS/doc/grouped-dragging_dark.png b/QtADS/doc/grouped-dragging_dark.png
new file mode 100644
index 0000000..8fb659c
Binary files /dev/null and b/QtADS/doc/grouped-dragging_dark.png differ
diff --git a/QtADS/doc/linux_kubuntu_1804.png b/QtADS/doc/linux_kubuntu_1804.png
new file mode 100644
index 0000000..e1c41e6
Binary files /dev/null and b/QtADS/doc/linux_kubuntu_1804.png differ
diff --git a/QtADS/doc/linux_ubuntu_1910.png b/QtADS/doc/linux_ubuntu_1910.png
new file mode 100644
index 0000000..41ef800
Binary files /dev/null and b/QtADS/doc/linux_ubuntu_1910.png differ
diff --git a/QtADS/doc/macos.png b/QtADS/doc/macos.png
new file mode 100644
index 0000000..8c2842e
Binary files /dev/null and b/QtADS/doc/macos.png differ
diff --git a/QtADS/doc/non_opaque_resizing.gif b/QtADS/doc/non_opaque_resizing.gif
new file mode 100644
index 0000000..7582f5d
Binary files /dev/null and b/QtADS/doc/non_opaque_resizing.gif differ
diff --git a/QtADS/doc/non_opaque_undocking.gif b/QtADS/doc/non_opaque_undocking.gif
new file mode 100644
index 0000000..e0bf9bf
Binary files /dev/null and b/QtADS/doc/non_opaque_undocking.gif differ
diff --git a/QtADS/doc/opaque_resizing.gif b/QtADS/doc/opaque_resizing.gif
new file mode 100644
index 0000000..c979924
Binary files /dev/null and b/QtADS/doc/opaque_resizing.gif differ
diff --git a/QtADS/doc/opaque_undocking.gif b/QtADS/doc/opaque_undocking.gif
new file mode 100644
index 0000000..71be813
Binary files /dev/null and b/QtADS/doc/opaque_undocking.gif differ
diff --git a/QtADS/doc/perspectives.gif b/QtADS/doc/perspectives.gif
new file mode 100644
index 0000000..1290921
Binary files /dev/null and b/QtADS/doc/perspectives.gif differ
diff --git a/QtADS/doc/perspectives.png b/QtADS/doc/perspectives.png
new file mode 100644
index 0000000..d905209
Binary files /dev/null and b/QtADS/doc/perspectives.png differ
diff --git a/QtADS/doc/perspectives_dark.png b/QtADS/doc/perspectives_dark.png
new file mode 100644
index 0000000..34fb27c
Binary files /dev/null and b/QtADS/doc/perspectives_dark.png differ
diff --git a/QtADS/doc/preview-dragndrop.png b/QtADS/doc/preview-dragndrop.png
new file mode 100644
index 0000000..b1eae80
Binary files /dev/null and b/QtADS/doc/preview-dragndrop.png differ
diff --git a/QtADS/doc/preview-dragndrop_dark.png b/QtADS/doc/preview-dragndrop_dark.png
new file mode 100644
index 0000000..ba44afd
Binary files /dev/null and b/QtADS/doc/preview-dragndrop_dark.png differ
diff --git a/QtADS/doc/preview_dark.png b/QtADS/doc/preview_dark.png
new file mode 100644
index 0000000..2e530ea
Binary files /dev/null and b/QtADS/doc/preview_dark.png differ
diff --git a/QtADS/doc/python_logo.png b/QtADS/doc/python_logo.png
new file mode 100644
index 0000000..f35b180
Binary files /dev/null and b/QtADS/doc/python_logo.png differ
diff --git a/QtADS/doc/showcase_adtf.png b/QtADS/doc/showcase_adtf.png
new file mode 100644
index 0000000..633bc04
Binary files /dev/null and b/QtADS/doc/showcase_adtf.png differ
diff --git a/QtADS/doc/showcase_d-tect-x.jpg b/QtADS/doc/showcase_d-tect-x.jpg
new file mode 100644
index 0000000..6157535
Binary files /dev/null and b/QtADS/doc/showcase_d-tect-x.jpg differ
diff --git a/QtADS/doc/showcase_d-tect-x.png b/QtADS/doc/showcase_d-tect-x.png
new file mode 100644
index 0000000..16adf7f
Binary files /dev/null and b/QtADS/doc/showcase_d-tect-x.png differ
diff --git a/QtADS/doc/showcase_dream3d_nx.png b/QtADS/doc/showcase_dream3d_nx.png
new file mode 100644
index 0000000..b64434f
Binary files /dev/null and b/QtADS/doc/showcase_dream3d_nx.png differ
diff --git a/QtADS/doc/showcase_ezEngine_editor.png b/QtADS/doc/showcase_ezEngine_editor.png
new file mode 100644
index 0000000..98df567
Binary files /dev/null and b/QtADS/doc/showcase_ezEngine_editor.png differ
diff --git a/QtADS/doc/showcase_hivewe.png b/QtADS/doc/showcase_hivewe.png
new file mode 100644
index 0000000..f7ba52b
Binary files /dev/null and b/QtADS/doc/showcase_hivewe.png differ
diff --git a/QtADS/doc/showcase_labplot.png b/QtADS/doc/showcase_labplot.png
new file mode 100644
index 0000000..a8a1d75
Binary files /dev/null and b/QtADS/doc/showcase_labplot.png differ
diff --git a/QtADS/doc/showcase_metgem.png b/QtADS/doc/showcase_metgem.png
new file mode 100644
index 0000000..76e54bd
Binary files /dev/null and b/QtADS/doc/showcase_metgem.png differ
diff --git a/QtADS/doc/showcase_notepad_next.png b/QtADS/doc/showcase_notepad_next.png
new file mode 100644
index 0000000..2e8ea1d
Binary files /dev/null and b/QtADS/doc/showcase_notepad_next.png differ
diff --git a/QtADS/doc/showcase_plot_juggler.png b/QtADS/doc/showcase_plot_juggler.png
new file mode 100644
index 0000000..a4f074b
Binary files /dev/null and b/QtADS/doc/showcase_plot_juggler.png differ
diff --git a/QtADS/doc/showcase_pre_workbench.png b/QtADS/doc/showcase_pre_workbench.png
new file mode 100644
index 0000000..ac31f32
Binary files /dev/null and b/QtADS/doc/showcase_pre_workbench.png differ
diff --git a/QtADS/doc/showcase_qmix_elements.png b/QtADS/doc/showcase_qmix_elements.png
new file mode 100644
index 0000000..4223f2c
Binary files /dev/null and b/QtADS/doc/showcase_qmix_elements.png differ
diff --git a/QtADS/doc/showcase_qt_design_studio.png b/QtADS/doc/showcase_qt_design_studio.png
new file mode 100644
index 0000000..9353e3b
Binary files /dev/null and b/QtADS/doc/showcase_qt_design_studio.png differ
diff --git a/QtADS/doc/showcase_qt_design_studio_video.png b/QtADS/doc/showcase_qt_design_studio_video.png
new file mode 100644
index 0000000..98ca054
Binary files /dev/null and b/QtADS/doc/showcase_qt_design_studio_video.png differ
diff --git a/QtADS/doc/showcase_qtcreator.png b/QtADS/doc/showcase_qtcreator.png
new file mode 100644
index 0000000..11ae122
Binary files /dev/null and b/QtADS/doc/showcase_qtcreator.png differ
diff --git a/QtADS/doc/showcase_ramses_composer.png b/QtADS/doc/showcase_ramses_composer.png
new file mode 100644
index 0000000..1fd2ddd
Binary files /dev/null and b/QtADS/doc/showcase_ramses_composer.png differ
diff --git a/QtADS/doc/showcase_resinsight.png b/QtADS/doc/showcase_resinsight.png
new file mode 100644
index 0000000..d5ab8f5
Binary files /dev/null and b/QtADS/doc/showcase_resinsight.png differ
diff --git a/QtADS/doc/showcase_robox_ide.png b/QtADS/doc/showcase_robox_ide.png
new file mode 100644
index 0000000..02d7e89
Binary files /dev/null and b/QtADS/doc/showcase_robox_ide.png differ
diff --git a/QtADS/doc/tab_menu.gif b/QtADS/doc/tab_menu.gif
new file mode 100644
index 0000000..49fb1e8
Binary files /dev/null and b/QtADS/doc/tab_menu.gif differ
diff --git a/QtADS/doc/taiwan_ukraine.jpg b/QtADS/doc/taiwan_ukraine.jpg
new file mode 100644
index 0000000..f2f5822
Binary files /dev/null and b/QtADS/doc/taiwan_ukraine.jpg differ
diff --git a/QtADS/doc/ukraine.jpg b/QtADS/doc/ukraine.jpg
new file mode 100644
index 0000000..2e5c065
Binary files /dev/null and b/QtADS/doc/ukraine.jpg differ
diff --git a/QtADS/doc/user-guide.md b/QtADS/doc/user-guide.md
new file mode 100644
index 0000000..e59bae6
--- /dev/null
+++ b/QtADS/doc/user-guide.md
@@ -0,0 +1,844 @@
+# User Guide
+
+- [Configuration Flags](#configuration-flags)
+ - [Setting Configuration Flags](#setting-configuration-flags)
+ - [`ActiveTabHasCloseButton`](#activetabhasclosebutton)
+ - [`DockAreaHasCloseButton`](#dockareahasclosebutton)
+ - [`DockAreaCloseButtonClosesTab`](#dockareaclosebuttonclosestab)
+ - [`OpaqueSplitterResize`](#opaquesplitterresize)
+ - [`XmlAutoFormattingEnabled`](#xmlautoformattingenabled)
+ - [`XmlCompressionEnabled`](#xmlcompressionenabled)
+ - [`TabCloseButtonIsToolButton`](#tabclosebuttonistoolbutton)
+ - [`AllTabsHaveCloseButton`](#alltabshaveclosebutton)
+ - [`RetainTabSizeWhenCloseButtonHidden`](#retaintabsizewhenclosebuttonhidden)
+ - [`DragPreviewIsDynamic`](#dragpreviewisdynamic)
+ - [`DragPreviewShowsContentPixmap`](#dragpreviewshowscontentpixmap)
+ - [`DragPreviewHasWindowFrame`](#dragpreviewhaswindowframe)
+ - [`AlwaysShowTabs`](#alwaysshowtabs)
+ - [`DockAreaHasUndockButton`](#dockareahasundockbutton)
+ - [`DockAreaHasTabsMenuButton`](#dockareahastabsmenubutton)
+ - [`DockAreaHideDisabledButtons`](#dockareahidedisabledbuttons)
+ - [`DockAreaDynamicTabsMenuButtonVisibility`](#dockareadynamictabsmenubuttonvisibility)
+ - [`FloatingContainerHasWidgetTitle`](#floatingcontainerhaswidgettitle)
+ - [`FloatingContainerHasWidgetIcon`](#floatingcontainerhaswidgeticon)
+ - [`HideSingleCentralWidgetTitleBar`](#hidesinglecentralwidgettitlebar)
+ - [`FocusHighlighting`](#focushighlighting)
+ - [`EqualSplitOnInsertion`](#equalsplitoninsertion)
+ - [`FloatingContainerForceNativeTitleBar` (Linux only)](#floatingcontainerforcenativetitlebar-linux-only)
+ - [`FloatingContainerForceQWidgetTitleBar` (Linux only)](#floatingcontainerforceqwidgettitlebar-linux-only)
+ - [`MiddleMouseButtonClosesTab`](#middlemousebuttonclosestab)
+ - [`DisableTabTextEliding`](#disabletabtexteliding)
+ - [`ShowTabTextOnlyForActiveTab`](#showtabtextonlyforactivetab)
+- [Auto-Hide Configuration Flags](#auto-hide-configuration-flags)
+ - [Auto Hide Dock Widgets](#auto-hide-dock-widgets)
+ - [Pinning Auto-Hide Widgets to a certain border](#pinning-auto-hide-widgets-to-a-certain-border)
+ - [Show / Hide Auto-Hide Widgets via Mouse Over](#show--hide-auto-hide-widgets-via-mouse-over)
+ - [Drag \& Drop to Auto-Hide](#drag--drop-to-auto-hide)
+ - [Auto-Hide Tab Insertion Order](#auto-hide-tab-insertion-order)
+ - [Auto-Hide Tab Sorting](#auto-hide-tab-sorting)
+ - [Auto-Hide Drag to Float / Dock](#auto-hide-drag-to-float--dock)
+ - [Auto-Hide Context Menu](#auto-hide-context-menu)
+ - [Adding Auto Hide Widgets](#adding-auto-hide-widgets)
+ - [Setting Auto-Hide Flags](#setting-auto-hide-flags)
+ - [`AutoHideFeatureEnabled`](#autohidefeatureenabled)
+ - [`DockAreaHasAutoHideButton`](#dockareahasautohidebutton)
+ - [`AutoHideButtonTogglesArea`](#autohidebuttontogglesarea)
+ - [`AutoHideButtonCheckable`](#autohidebuttoncheckable)
+ - [`AutoHideSideBarsIconOnly`](#autohidesidebarsicononly)
+ - [`AutoHideShowOnMouseOver`](#autohideshowonmouseover)
+ - [`AutoHideCloseButtonCollapsesDock`](#autohideclosebuttoncollapsesdock)
+ - [`AutoHideHasCloseButton`](#autohidehasclosebutton)
+ - [`AutoHideHasMinimizeButton`](#autohidehasminimizebutton)
+- [DockWidget Feature Flags](#dockwidget-feature-flags)
+ - [`DockWidgetClosable`](#dockwidgetclosable)
+ - [`DockWidgetMovable`](#dockwidgetmovable)
+ - [`DockWidgetFloatable`](#dockwidgetfloatable)
+ - [`DockWidgetDeleteOnClose`](#dockwidgetdeleteonclose)
+ - [`CustomCloseHandling`](#customclosehandling)
+ - [`DockWidgetFocusable`](#dockwidgetfocusable)
+ - [`DockWidgetForceCloseWithArea`](#dockwidgetforceclosewitharea)
+ - [`NoTab`](#notab)
+ - [`DeleteContentOnClose`](#deletecontentonclose)
+- [Central Widget](#central-widget)
+- [Empty Dock Area](#empty-dock-area)
+- [Custom Close Handling](#custom-close-handling)
+- [Styling](#styling)
+ - [Disabling the Internal Style Sheet](#disabling-the-internal-style-sheet)
+
+## Configuration Flags
+
+The Advanced Docking System has a number of global configuration options to
+configure the design and the functionality of the docking system. Each
+configuration will be explained in detail in the following sections.
+
+### Setting Configuration Flags
+
+You must set the configuration flags before creating the dock manager
+instance otherwise the manager will not be created correctly and will
+crash upon being created. That means, setting the configurations flags
+is the first thing you must do, if you use the library.
+
+```c++
+CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig);
+CDockManager::setConfigFlag(CDockManager::RetainTabSizeWhenCloseButtonHidden, true);
+...
+d->DockManager = new CDockManager(this);
+```
+
+If you set the configurations flags, you can set individual flags using the
+function `CDockManager::setConfigFlag` or you can set all flags using
+the function `CDockManager::setConfigFlags`. Instead of settings all
+flags individually, it is better to pick a predefined set of configuration
+flags and then modify individual flags. The following predefined
+configurations are available
+
+- `DefaultNonOpaqueConfig` - uses non opaque splitter resizing and non opaque docking
+- `DefaultOpaqueConfig` - uses opaque splitter resizing and opaque docking
+
+Pick one of those predefined configurations and then modify the following
+configurations flags to adjust the docking system to your needs.
+
+### `ActiveTabHasCloseButton`
+
+If this flag is set (default configuration), the active tab in a tab area has
+a close button.
+
+
+
+If this flag is cleared, the active tab has no close button. You can combine
+this with the flag `DockAreaCloseButtonClosesTab` to use the close button
+of the dock are to close the single tabs.
+
+
+
+### `DockAreaHasCloseButton`
+
+If the flag is set (default configuration) each dock area has a close button.
+
+
+
+If this flag is cleared, dock areas do not have a close button.
+
+
+
+### `DockAreaCloseButtonClosesTab`
+
+If the flag is set, the dock area close button closes the active tab,
+if not set, it closes the complete dock area (default).
+
+### `OpaqueSplitterResize`
+
+The advanced docking system uses standard `QSplitters` as resize separators and thus supports opaque and non-opaque resizing functionality of `QSplitter`. In some rare cases, for very complex widgets or on slow machines resizing via separator on the fly may cause flicking and glaring of rendered content inside a widget. This global dock manager flag configures the resizing behaviour of the splitters. If this flag is set, then widgets are resized dynamically (opaquely) while interactively moving the splitters. If you select the predefined configuration `DefaultOpaqueConfig`, then this is the configured behaviour.
+
+
+
+If this flag is cleared, the widget resizing is deferred until the mouse button is released - this is some kind of lazy resizing separator. If you select the predefined
+configuration `DefaultNonOpaqueConfig`, then this is the configured behaviour.
+
+
+
+### `XmlAutoFormattingEnabled`
+
+If enabled, the XML writer automatically adds line-breaks and indentation to
+empty sections between elements (ignorable whitespace). This is used, when
+the current state or perspective is saved. It is disabled by default.
+
+### `XmlCompressionEnabled`
+
+If enabled, the XML output will be compressed and is not human readable anymore.
+This ie enabled by default to minimize the size of the saved data.
+
+### `TabCloseButtonIsToolButton`
+
+If enabled the tab close buttons will be `QToolButtons` instead of `QPushButtons` -
+disabled by default. Normally the default configuration should be ok but if your
+application requires `QToolButtons` instead of `QPushButtons` for styling reasons
+or for any other reasons, then you can enable this flag.
+
+### `AllTabsHaveCloseButton`
+
+If this flag is set, then all tabs that are closable show a close button. The
+advantage of this setting is that the size of the tabs does not change and the
+user can immediately close each tab. The disadvantage is that all tabs take up
+more space.
+
+
+
+If this flas is cleared, then only the active tab has a close button (default)
+and therefore the tabs need less space.
+
+
+
+### `RetainTabSizeWhenCloseButtonHidden`
+
+If this flag is set, the space for the close button is reserved even if the
+close button is not visible. This flag is disabled by default. If this flag
+is disabled, the tab size dynamically changes if the close button is
+visible / hidden in a tab. If this flag is enabled, the tab size always remains
+constant, that means, if enabled, the tabs need more space.
+
+
+
+### `DragPreviewIsDynamic`
+
+If non-opaque undocking is enabled, this flag defines the behavior of the drag
+preview window. If this flag is enabled, then it will give the user the
+impression, that the floating drag preview is dynamically adjusted to the drop
+area. In order to give the perfect impression, you should disable the flags
+`DragPreviewShowsContentPixmap` and `DragPreviewHasWindowFrame`.
+
+```c++
+CDockManager::setConfigFlag(CDockManager::DragPreviewIsDynamic, true);
+CDockManager::setConfigFlag(CDockManager::DragPreviewShowsContentPixmap, false);
+CDockManager::setConfigFlag(CDockManager::DragPreviewHasWindowFrame, false);
+```
+
+
+
+### `DragPreviewShowsContentPixmap`
+
+If non-opaque undocking is enabled, the created drag preview window shows a
+copy of the content of the dock widget / dock are that is dragged, if this
+flag is enabled (default).
+
+
+
+If this flag is disabled, the drag preview is only a transparent `QRubberBand`
+like window without any content.
+
+
+
+### `DragPreviewHasWindowFrame`
+
+If non-opaque undocking is enabled, then this flag configures if the drag
+preview is frameless (default) or looks like a real window. If it is enabled,
+then the drag preview is a transparent window with a system window frame.
+
+
+
+### `AlwaysShowTabs`
+
+If this option is enabled, the tab of a dock widget is always displayed - even
+if it is the only visible dock widget in a floating widget. In the image below
+on the left side, the flag is disabled (default) and on the right side it is
+enabled.
+
+
+
+### `DockAreaHasUndockButton`
+
+If the flag is set (default) each dock area has an undock button (right
+image). If the flag is cleared, a dock area has no undock button (left image)
+
+
+
+### `DockAreaHasTabsMenuButton`
+
+Tabs are a good way to quickly switch between dockwidgets in a dockarea.
+However, if the number of dockwidgets in a dockarea is too large, this may affect
+the usability of the tab bar. To keep track in this situation, you can use the
+tab menu. The menu allows you to quickly select the dockwidget you want to
+activate from a drop down menu. This flag shows / hides the tabs menu button
+in the dock area title bar. On the left side, the tabs menu button flag
+is cleared.
+
+
+
+### `DockAreaHideDisabledButtons`
+
+If certain flags of a dock widget are disabled, like `DockWidgetClosable` or
+`DockWidgetFloatable`, then the corresponding dock area buttons like close
+button or detach button are disabled (greyed out). This is the default
+setting.
+
+
+
+If the flag is set, disabled dock area buttons will not appear on the toolbar at
+all - they are hidden.
+
+
+
+### `DockAreaDynamicTabsMenuButtonVisibility`
+
+If this flag is cleared, the the tabs menu button is always visible. This is
+the default setting. If the flag is set, the tabs menu button will be shown
+only when it is required - that means, if the tabs are elided.
+
+
+
+If the tabs are not elided, the tabs menu button is hidden.
+
+
+
+### `FloatingContainerHasWidgetTitle`
+
+If set (default), the floating widget window title reflects the title of the
+current dock widget.
+
+
+
+otherwise it displays the title set with `CDockManager::setFloatingContainersTitle` or
+application name as window title.
+
+
+
+### `FloatingContainerHasWidgetIcon`
+
+If set, the floating widget icon reflects the icon of the current dock widget
+
+
+
+otherwise (default setting) it displays application icon.
+
+
+
+### `HideSingleCentralWidgetTitleBar`
+
+If there is only one single visible dock widget in the main dock container (the dock manager)
+and if this flag is set, then the titlebar of this dock widget will be hidden.
+This only makes sense for non draggable and non floatable dock widgets and enables
+the creation of some kind of "central" static widget. Because the titlebar is
+hidden, it is not possible to drag out the central widget to make it floating
+or to close it via the close button.
+
+
+
+Unless a central widget explicitly has been set with setCentralWidget, the
+Advanced Docking System is without a static central widget and it wouldn't know
+about a central static widget.
+Therefore this flag is disabled by default and a central single dock widget
+still has a titlebar to drag it out of the main window.
+
+
+
+### `FocusHighlighting`
+
+If this is enabled, the docking system is able to highlight the tab and the
+components of a dock area with a different style (i.e. a different color).
+This option is disabled by default and needs to be enabled explicitly
+because it adds some overhead. The dock manager needs to react on focus
+changes and dock widget dragging to highlight the right dock widget. You should
+enable it only, if you really need it for your application.
+
+If the feature is enabled, you can also connect to the new dock manager
+signal `focusedDockWidgetChanged(CDockWidget* old, CDockWidget* now)` to
+react on focus changes and to prepare the content of the focused dock
+widget.
+
+You can click into the tab, the titlebar or the content of a dock widget
+to focus it.
+
+
+
+For the focused dock widget and dock widget tab, the property `focused` will
+be set to true and you can use this property to style the focused dock
+widget differently. The picture above uses the following styling:
+
+```css
+/* Color the tab with the highlight color */
+ads--CDockWidgetTab[focused="true"]
+{
+ background: palette(highlight);
+ border-color: palette(highlight);
+}
+
+/* Use a different colored close button icon to match the test color */
+ads--CDockWidgetTab[focused="true"] > #tabCloseButton
+{
+ qproperty-icon: url(:/ads/images/close-button-focused.svg)
+}
+
+/* Make a hovered focused close button a little bit lighter */
+ads--CDockWidgetTab[focused="true"] > #tabCloseButton:hover
+{
+ background: rgba(255, 255, 255, 48);
+}
+
+/* Make a pressed focused close button even more lighter */
+ads--CDockWidgetTab[focused="true"] > #tabCloseButton:pressed
+{
+ background: rgba(255, 255, 255, 92);
+}
+
+/* Use a different color for the tab label */
+ads--CDockWidgetTab[focused="true"] QLabel
+{
+ color: palette(light);
+}
+
+/* Paint a nice solid line for the whole title bar to create the illusion
+ of an active tab */
+ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar
+{
+ background: transparent;
+ border-bottom: 2px solid palette(highlight);
+ padding-bottom: 0px;
+}
+```
+
+If you have a content widget that does not support focussing for some reason
+(like `QVTKOpenGLStereoWidget` from the [VTK library](https://github.com/Kitware/VTK)),
+then you can manually switch the focus by reacting on mouse events. The
+following code shows, how to install en event filter on the `QVTKOpenGLStereoWidget`
+to properly switch the focus on `QEvent::MouseButtonPress`:
+
+```c++
+static ads::CDockWidget* createVTK2DWindow(QMenu* ViewMenu, QObject* EventFilter)
+{
+ QVTKOpenGLStereoWidget* qvtkOpenGLStereoWidget = new QVTKOpenGLStereoWidget;
+ ads::CDockWidget* DockWidget = new ads::CDockWidget("2D Window");
+ DockWidget->setWidget(qvtkOpenGLStereoWidget);
+ qvtkOpenGLStereoWidget->installEventFilter(EventFilter);
+ qvtkOpenGLStereoWidget->setProperty("DockWidget", QVariant::fromValue(DockWidget));
+ return DockWidget;
+}
+```
+
+Now we can use the event filter function to react on mouse events and then
+use the dock manager function `setDockWidgetFocused()` to switch the focus:
+
+```c++
+bool CMainWindow::eventFilter(QObject *watched, QEvent *event)
+{
+ if (event->type() == QEvent::MouseButtonPress)
+ {
+ QVTKOpenGLStereoWidget* vtkWidget = qobject_cast(watched);
+ auto vDockWidget = vtkWidget->property("DockWidget");
+ ads::CDockWidget* DockWidget = nullptr;
+ if (vDockWidget.isValid())
+ {
+ DockWidget = qvariant_cast(vDockWidget);
+ }
+
+ if (DockWidget)
+ {
+ d->DockManager->setDockWidgetFocused(DockWidget);
+ }
+ }
+ return false;
+}
+```
+
+### `EqualSplitOnInsertion`
+
+This flag configures how the space is distributed if a new dock widget is
+inserted into an existing dock area. The flag is disabled by default. If 3
+dock widgets are inserted with the following code
+
+```c++
+d->DockManager->addDockWidget(ads::RightDockWidgetArea, DockWidget, EditorArea);
+```
+
+then this is the result, if the flag is disabled:
+
+
+
+If the flag is enabled, then the space is equally distributed to all widgets
+in a splitter:
+
+
+
+
+### `FloatingContainerForceNativeTitleBar` (Linux only)
+
+Since release 3.6 the library supports native title bars and window decorations
+for floating widgets on Linux (thanks to a user contribution).
+Native title bars and window decorations are supported by most Linux window
+managers, such as Compiz or Xfwm. Some window managers like KWin do not properly
+support this feature. Native floating widgets look better because of the native
+styling and the support all window manager features like snapping to window
+borders or maximizing. The library tries to detect the window manager during
+runtime and activates native window decorations if possible:
+
+
+
+If you would like to overwrite this autodetection, then you can activate this
+flag to force native window titlebars. You can overwrite autodetection and this
+flag, if you set the environment variable `ADS_UseNativeTitle` to 0 or 1.
+
+### `FloatingContainerForceQWidgetTitleBar` (Linux only)
+
+If your window manager (i.e. KWin) does not properly support native floating
+windows, the docking library falls back to QWidget based floating widget
+title bars.
+
+
+
+If you would like to overwrite autodetection, then you can activate this flag
+to force QWidget based title bars. You can overwrite autodetection and this
+flag, if you set the environment variable `ADS_UseNativeTitle` to 0 or 1.
+
+### `MiddleMouseButtonClosesTab`
+
+If the flag is set, the user can use the mouse middle button to close the tab
+under the mouse. So you do not need to exactly hit the tab close button to
+close tab. Just click with the middle mouse button on a tab like this is
+possible in various web browsers.
+
+
+
+### `DisableTabTextEliding`
+
+Set this flag to disable eliding of tab texts in dock area tabs:
+
+
+
+The flag is disabled by default and the text in all tabs is elided to show as
+many tabs as possible even if there is not much space:
+
+
+
+### `ShowTabTextOnlyForActiveTab`
+
+Set this flag (default = false) to show label texts in dock area tabs only
+for active tabs. Inactive tabs only show their icon:
+
+
+
+## Auto-Hide Configuration Flags
+
+### Auto Hide Dock Widgets
+
+The Advanced Docking System supports "Auto-Hide" functionality for **all**
+dock containers. The "Auto Hide" feature allows to display more information
+using less screen space by hiding or showing windows pinned to one of the
+four dock container borders.
+
+Enabling this feature adds a button with a pin icon to each dock area.
+
+
+
+By clicking this button, the current dock widget (or the complete area - depending on the
+configuration flags) will be pinned to a certain border. The border is chosen
+depending on the location of the dock area. If you click the pin button while
+holding down the **Ctrl** key, the whole dock area will be pinned to a certain
+border.
+
+### Pinning Auto-Hide Widgets to a certain border
+
+If you would like to pin a dock widget or a dock area to a certain border,
+then you can right-click into the dock widget tab or into the dock area title bar
+to show the context menu. Then you can select the location via the **Pin to** menu:
+
+
+
+### Show / Hide Auto-Hide Widgets via Mouse Over
+
+Normally Auto-Hide widgets are shown by clicking the Auto-Hide tab and hidden by
+clicking the Auto-Hide tab again or by clicking into any other dock widget in
+the same container. If the Auto-Hide config flag `AutoHideShowOnMouseOver` is set,
+the Auto-Hide widget is shown, if the user hovers over the Auto-Hide tab and is
+collapsed if the mouse cursor leaves the Auto-Hide widget. Showing and hiding
+by mouse click still works if this feature is enabled.
+
+### Drag & Drop to Auto-Hide
+
+You can easily drag any dock widget or any floating widget to the
+borders of a window to pin it as a auto-hide tab in one of the 4 sidebars.
+If you drag a dock widget close the one of the four window borders, special
+drop overlays will be shown to indicate the drop area for auto-hide widgets:
+
+
+
+Of course, this also works with dock areas:
+
+
+
+If you drag a dock widget or dock area into a sidebar, then you even have
+control over where tabs are inserted. Simply drag your mouse over a specific
+auto-hide tab, and your dragged dock widget will be inserted before this tab.
+Drag to the sidebar area behind the last tab, and the dragged widget will be
+appended as last tab. In the following screen capture, the **Image Viewer 1** will
+be inserted before the **Table 0** Auto-Hide tab and the **Image Viewer 2**
+is appended behind the last tab:
+
+
+
+### Auto-Hide Tab Insertion Order
+
+It is also possible to drag Auto-Hide tabs to a new auto-hide position.
+That means, you can drag them to a different border or sidebar:
+
+
+
+### Auto-Hide Tab Sorting
+
+You can drag Auto-Hide tabs to a new position in the current sidebar
+to sort them:
+
+
+
+### Auto-Hide Drag to Float / Dock
+
+But that is not all. You can also simply move Auto-Hide tabs to another
+floating widget or dock them via drag and drop:
+
+
+
+### Auto-Hide Context Menu
+
+All Auto-Hide tabs now have a context menu, that provides all the functionality
+that you know from Dock widget tabs. With the **Pin To...** item from the
+context menu it is very easy to move an Auto-Hide tab to a different Auto-Hide
+sidebar:
+
+
+
+### Adding Auto Hide Widgets
+
+Adding an auto hide widget is similar to adding a dock widget, simply call
+`dockManager->addAutoHideDockWidget()`.
+
+```c++
+CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig);
+d->DockManager = new CDockManager(this);
+CDockWidget* TableDockWidget = new CDockWidget("Table 1");
+DockManager->addAutoHideDockWidget(SideBarLeft, TableDockWidget);
+```
+
+See `autohide` example or the demo application to learn how it works.
+
+### Setting Auto-Hide Flags
+
+The Advanced Docking System has a number of global configuration flags to
+configure the Auto-Hide functionality. You should set the Auto-Hide flags before
+creating the dock manager instance. That means, you should set the Auto-Hide
+flags after setting the configuration flags.
+
+```c++
+CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
+CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig);
+CDockManager::setAutoHideConfigFlag(CDockManager::AutoHideShowOnMouseOver, true);
+...
+d->DockManager = new CDockManager(this);
+```
+
+If you set the Auto-Hide flags, you can set individual flags using the
+function `CDockManager::setAutoHideConfigFlag` or you can set all flags using
+the function `CDockManager::setAutoHideConfigFlags`. Instead of settings all
+flags individually, it is better to pick a predefined set of configuration
+flags and then modify individual flags. The following predefined
+configurations are available
+
+- `DefaultAutoHideConfig` - default auto hide config
+
+Pick one of those predefined configurations and then modify the following
+configurations flags to adjust the docking system to your needs.
+
+### `AutoHideFeatureEnabled`
+
+Enables / disables the Auto-Hide functionality. Only if this flag is enabled,
+the other Auto-Hide flags will be evaluated.
+
+### `DockAreaHasAutoHideButton`
+
+If this flag is set (default), then each dock area has a pin button in the title
+bar to toggle Auto-Hide state.
+
+
+
+### `AutoHideButtonTogglesArea`
+
+If set, the the pin button in the dock area title bar toggles the complete area.
+If not set (default), then the pin button toggles the current active tab / dock
+widget and pressing the **Ctrl** key while clicking the pin button toggles the
+complete ara.
+
+### `AutoHideButtonCheckable`
+
+Normally the pin button in the dock area title bar is not checkable. If this
+flag is set, then the button is checkable. That means, if button is checked,
+the dock widget is pinned.
+
+### `AutoHideSideBarsIconOnly`
+
+Normally the Auto-Hide tabs show the icon and title of the dock widget:
+
+
+
+You can set this flag, if you would like to have only icons in the Auto-Hide
+tabs instead of icon and dock widget title. If this is set, the Auto-Hide tab
+needs less space. The tooltip of each tab still shows the dock widget title.
+
+
+
+### `AutoHideShowOnMouseOver`
+
+Normally Auto-Hide widgets are shown by clicking the Auto-Hide tab and
+hidden by clicking the Auto-Hide tab again or by clicking into any other
+dock widget in the same container. If this flag is set, the Auto-Hide widget
+is shown, if the user hovers over the Auto-Hide tab or if the users moves the
+mouse outside of the Auto-Hide widget. Showing and hiding my mouse click still
+works if this feature is enabled.
+
+### `AutoHideCloseButtonCollapsesDock`
+
+Some users don't understand the distinction between closing an auto hide dock and
+collapsing an auto hide dock. This may lead to situations where they press the
+close button (losing the side tab widget) instead of simply clicking outside
+the auto hide dock (collapsing the dock).
+
+
+
+If `AutoHideCloseButtonCollapsesDock` option is active, the
+close button in an auto hide widget collapses the auto hide widget instead of
+closing it.
+
+
+
+If you enable the `AutoHideHasMinimizeButton` flag, you should disable this
+flag our you will have two buttons with minimize functionality.
+
+### `AutoHideHasCloseButton`
+
+If this flag is set (default), then each auto hide widget has a close button:
+
+
+
+The functionality of the close button (close or minimize) is configured by the
+`AutoHideCloseButtonCollapsesDock` flag.
+
+### `AutoHideHasMinimizeButton`
+
+If this flag is set (disabled by default), then each auto hide widget has a minimize button.
+
+
+
+## DockWidget Feature Flags
+
+### `DockWidgetClosable`
+
+If set, the dock widget will have a close button.
+
+### `DockWidgetMovable`
+
+If a dock widget is movable, then it and can be moved to a new position in the
+current dock container. Disable this flag to prevent moving of a dock widget
+via mouse.
+
+### `DockWidgetFloatable`
+
+If set, a dock widget can be dragged into a floating window.
+
+### `DockWidgetDeleteOnClose`
+
+Deletes the dock widget and its content when it is closed.
+
+### `CustomCloseHandling`
+
+Clicking the close button will not close the dock widget but emits the
+`closeRequested()` signal instead. This allows the application to implement
+a custom close handling.
+
+### `DockWidgetFocusable`
+
+If this is enabled, a dock widget can get focus highlighting.
+
+### `DockWidgetForceCloseWithArea`
+
+A dock widget will be closed when the dock area hosting it is closed. If the
+`DockWidgetDeleteOnClose` feature is enabled for a dock widget, then it will
+be deleted, if the user clicks the close button of this dock widget. If the
+user clicks the close button of the dock area that contains this widget,
+then only the visibility of the dock widget is toggled. If this feature flag
+is set, the closing the dock area also closes the dock widget. That means, if
+the dock widget feature `DockWidgetDeleteOnClose` is set for the dock widgets
+in a dock area, then all dock widgets will be deleted if the dock area is closed.
+
+### `NoTab`
+
+A dock widget tab will never be shown if this flag is set.
+
+### `DeleteContentOnClose`
+
+Deletes only the contained widget on close, keeping the dock widget intact and
+in place. Attempts to rebuild the contents widget on show if there is a widget
+factory set. See [issue #365](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/pull/365) for more details.
+
+## Central Widget
+
+The Advanced Docking System has been developed to overcome the limitations of
+the native Qt docking system with its central widget concept. This was the
+reason that until version 3.6 of the library, there was no support for such
+thing like a central widget. Thanks to the contribution of a user the library
+now supports a central widget.
+
+In the Advanced Docking System a central widget is a docking widget that is
+neither closable nor movable or floatable. A central widget has no title bar
+and so it is not possible for the user to hide, close or drag the central
+widget. If there is a central widget, then also the distribution of the sizes
+for the dock widgets around the central widget is different:
+
+- **no central widget (default)** - on resizing the available space is
+distributed to all dock widgets - the size of all dock widgets
+shrinks or grows
+- **with central widget** - on resizing only the central widget is resized - the
+dock widgets around the central widget keep their size (see the animation below)
+
+
+
+To set a central widget, you just need to pass your central dock widget
+to the dock manager `setCentralWidget` function:
+
+```c++
+auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);
+```
+
+See the `centralwidget` example to learn how it works.
+
+> ##### Note
+> The central widget needs to be the first dock widget that is added to the
+> dock manager. The function does not work and returns a `nullptr` if there
+> are already other dock widgets registered. So `setCentralWidget` should be
+> the first function that you call when adding dock widgets.
+
+## Empty Dock Area
+
+Some applications require a fixed DockArea that is always visible, even if it
+does not contain any DockWidgets. I.e. the DockArea is in this case a kind
+of central widget that is always visible (see this
+[issue](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/199)).
+
+Since version 3.7.1 the advanced docking system supports this feature. The
+`emptydockarea` example shows how this can be implemented with the library. You
+just need to create a dock widget and set the feature flag `CDockWidget::NoTab`.
+This permanently hides the tab widget of this area and removes it from the tab
+menu. For this special dock widget you should also disable all other features
+(movable, closable and floatable) to prevent closing and moving of this widget.
+If you use the `CDockManager::setCentralWidget` function like in the example
+code below, then you don't need to disable these features because this is done
+in the `setCentralWidget` function.
+
+```c++
+QLabel* label = new QLabel();
+label->setText("This is a DockArea which is always visible, even if it does not contain any DockWidgets.");
+label->setAlignment(Qt::AlignCenter);
+CDockWidget* CentralDockWidget = new CDockWidget("CentralWidget");
+CentralDockWidget->setWidget(label);
+CentralDockWidget->setFeature(ads::CDockWidget::NoTab, true);// set the flag before adding the widget to dock manager
+auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);
+```
+
+## Custom Close Handling
+
+Normally clicking the close button of a dock widget will just hide the widget and the user can show it again using the `toggleView()` action of the dock widget. This is meant for user interfaces with a static amount of widgets. But the advanced docking system also supports dynamic dock widgets that will get deleted on close. If you set the dock widget flag `DockWidgetDeleteOnClose` for a certain dock widget, then it will be deleted as soon as you close this dock widget. This enables the implementation of user interfaces with dynamically created editors, like in word processing applications or source code development tools.
+
+When an entire area is closed, the default behavior is to hide the dock widgets it contains regardless of the `DockWidgetDeleteOnClose` flag except if there is only one dock widget. In this special case, the `DockWidgetDeleteOnClose` flag is followed. This behavior can be changed by setting the `DockWidgetForceCloseWithArea` flag to all the dock widgets that needs to be closed with their area.
+
+## Styling
+
+The Advanced Docking System supports styling via [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet.html). All components like splitters, tabs, buttons, titlebar and
+icons are styleable this way.
+
+### Disabling the Internal Style Sheet
+
+The dock manager uses an internal stylesheet to style its components. That
+means, the style that you see in the demo application comes from the
+internal stylesheets that you will find in `src/stylesheets` folder. If you want
+to disable this internal stylesheet because your application uses its own,
+just call the function for settings the stylesheet with an empty string.
+
+```c++
+DockManager->setStyleSheet("");
+```
+
diff --git a/QtADS/examples/CMakeLists.txt b/QtADS/examples/CMakeLists.txt
new file mode 100644
index 0000000..ba2a064
--- /dev/null
+++ b/QtADS/examples/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.5)
+project(QtADSExamples LANGUAGES CXX VERSION ${VERSION_SHORT})
+add_subdirectory(simple)
+add_subdirectory(hideshow)
+add_subdirectory(sidebar)
+add_subdirectory(deleteonclose)
+add_subdirectory(centralwidget)
+add_subdirectory(autohide)
+add_subdirectory(emptydockarea)
+add_subdirectory(dockindock)
\ No newline at end of file
diff --git a/QtADS/examples/autohide/CMakeLists.txt b/QtADS/examples/autohide/CMakeLists.txt
new file mode 100644
index 0000000..3379067
--- /dev/null
+++ b/QtADS/examples/autohide/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_autohide VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(AutoHideExample WIN32
+ main.cpp
+ mainwindow.cpp
+ mainwindow.ui
+)
+target_include_directories(AutoHideExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(AutoHideExample PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(AutoHideExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(AutoHideExample PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Auto Hide Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/autohide/autohide.pro b/QtADS/examples/autohide/autohide.pro
new file mode 100644
index 0000000..8a00c62
--- /dev/null
+++ b/QtADS/examples/autohide/autohide.pro
@@ -0,0 +1,34 @@
+ADS_OUT_ROOT = $${OUT_PWD}/../..
+
+QT += core gui widgets
+
+TARGET = AutoHideExample
+DESTDIR = $${ADS_OUT_ROOT}/lib
+TEMPLATE = app
+CONFIG += c++14
+CONFIG += debug_and_release
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+include(../../ads.pri)
+INCLUDEPATH += ../../src
+DEPENDPATH += ../../src
+
diff --git a/QtADS/examples/autohide/main.cpp b/QtADS/examples/autohide/main.cpp
new file mode 100644
index 0000000..fa4c4fd
--- /dev/null
+++ b/QtADS/examples/autohide/main.cpp
@@ -0,0 +1,10 @@
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ CMainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/QtADS/examples/autohide/main.py b/QtADS/examples/autohide/main.py
new file mode 100644
index 0000000..48c2927
--- /dev/null
+++ b/QtADS/examples/autohide/main.py
@@ -0,0 +1,106 @@
+import os
+import sys
+
+from PyQt5 import uic
+from PyQt5.QtCore import Qt, QTimer, QDir, QSignalBlocker
+from PyQt5.QtGui import QCloseEvent, QIcon
+from PyQt5.QtWidgets import (QApplication, QLabel, QCalendarWidget, QFrame, QTreeView,
+ QTableWidget, QFileSystemModel, QPlainTextEdit, QToolBar,
+ QWidgetAction, QComboBox, QAction, QSizePolicy, QInputDialog)
+
+import PyQtAds as QtAds
+
+UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
+MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
+
+class MainWindow(MainWindowUI, MainWindowBase):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.setupUi(self)
+
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.OpaqueSplitterResize, True)
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.XmlCompressionEnabled, False)
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
+ self.dock_manager = QtAds.CDockManager(self)
+
+ # Set central widget
+ text_edit = QPlainTextEdit()
+ text_edit.setPlaceholderText("This is the central editor. Enter your text here.")
+ central_dock_widget = QtAds.CDockWidget("CentralWidget")
+ central_dock_widget.setWidget(text_edit)
+ central_dock_area = self.dock_manager.setCentralWidget(central_dock_widget)
+ central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
+
+ # create other dock widgets
+ table = QTableWidget()
+ table.setColumnCount(3)
+ table.setRowCount(10)
+ table_dock_widget = QtAds.CDockWidget("Table 1")
+ table_dock_widget.setWidget(table)
+ table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ table_dock_widget.resize(250, 150)
+ table_dock_widget.setMinimumSize(200, 150)
+ table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, table_dock_widget)
+ self.menuView.addAction(table_dock_widget.toggleViewAction())
+
+ table = QTableWidget()
+ table.setColumnCount(5)
+ table.setRowCount(1020)
+ table_dock_widget = QtAds.CDockWidget("Table 2")
+ table_dock_widget.setWidget(table)
+ table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ table_dock_widget.resize(250, 150)
+ table_dock_widget.setMinimumSize(200, 150)
+ table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, table_area)
+ self.menuView.addAction(table_dock_widget.toggleViewAction())
+
+ properties_table = QTableWidget()
+ properties_table.setColumnCount(3)
+ properties_table.setRowCount(10)
+ properties_dock_widget = QtAds.CDockWidget("Properties")
+ properties_dock_widget.setWidget(properties_table)
+ properties_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ properties_dock_widget.resize(250, 150)
+ properties_dock_widget.setMinimumSize(200, 150)
+ self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, properties_dock_widget, central_dock_area)
+ self.menuView.addAction(properties_dock_widget.toggleViewAction())
+
+ self.create_perspective_ui()
+
+ def create_perspective_ui(self):
+ save_perspective_action = QAction("Create Perspective", self)
+ save_perspective_action.triggered.connect(self.save_perspective)
+ perspective_list_action = QWidgetAction(self)
+ self.perspective_combobox = QComboBox(self)
+ self.perspective_combobox.setSizeAdjustPolicy(QComboBox.AdjustToContents)
+ self.perspective_combobox.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+ self.perspective_combobox.activated[str].connect(self.dock_manager.openPerspective)
+ perspective_list_action.setDefaultWidget(self.perspective_combobox)
+ self.toolBar.addSeparator()
+ self.toolBar.addAction(perspective_list_action)
+ self.toolBar.addAction(save_perspective_action)
+
+ def save_perspective(self):
+ perspective_name, ok = QInputDialog.getText(self, "Save Perspective", "Enter Unique name:")
+ if not ok or not perspective_name:
+ return
+
+ self.dock_manager.addPerspective(perspective_name)
+ blocker = QSignalBlocker(self.perspective_combobox)
+ self.perspective_combobox.clear()
+ self.perspective_combobox.addItems(self.dock_manager.perspectiveNames())
+ self.perspective_combobox.setCurrentText(perspective_name)
+
+ def closeEvent(self, event: QCloseEvent):
+ self.dock_manager.deleteLater()
+ super().closeEvent(event)
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+
+ w = MainWindow()
+ w.show()
+ app.exec_()
diff --git a/QtADS/examples/autohide/mainwindow.cpp b/QtADS/examples/autohide/mainwindow.cpp
new file mode 100644
index 0000000..d70b51c
--- /dev/null
+++ b/QtADS/examples/autohide/mainwindow.cpp
@@ -0,0 +1,126 @@
+#include "mainwindow.h"
+
+#include "ui_mainwindow.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "AutoHideDockContainer.h"
+#include "DockAreaWidget.h"
+#include "DockAreaTitleBar.h"
+
+using namespace ads;
+
+
+CMainWindow::CMainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::CMainWindow)
+{
+ ui->setupUi(this);
+ CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true);
+ CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false);
+ CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
+ CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig);
+ DockManager = new CDockManager(this);
+
+ // Set central widget
+ QPlainTextEdit* w = new QPlainTextEdit();
+ w->setPlaceholderText("This is the central editor. Enter your text here.");
+ CDockWidget* CentralDockWidget = new CDockWidget("CentralWidget");
+ CentralDockWidget->setWidget(w);
+ auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);
+ CentralDockArea->setAllowedAreas(DockWidgetArea::OuterDockAreas);
+
+ // create other dock widgets
+ QTableWidget* table = new QTableWidget();
+ table->setColumnCount(3);
+ table->setRowCount(10);
+ CDockWidget* TableDockWidget = new CDockWidget("Table 1");
+ TableDockWidget->setWidget(table);
+ TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ TableDockWidget->setMinimumSize(200,150);
+ const auto autoHideContainer = DockManager->addAutoHideDockWidget(SideBarLocation::SideBarLeft, TableDockWidget);
+ autoHideContainer->setSize(480);
+ ui->menuView->addAction(TableDockWidget->toggleViewAction());
+
+ table = new QTableWidget();
+ table->setColumnCount(5);
+ table->setRowCount(1020);
+ TableDockWidget = new CDockWidget("Table 2");
+ TableDockWidget->setWidget(table);
+ TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ TableDockWidget->resize(250, 150);
+ TableDockWidget->setMinimumSize(200,150);
+ DockManager->addAutoHideDockWidget(SideBarLocation::SideBarLeft, TableDockWidget);
+ ui->menuView->addAction(TableDockWidget->toggleViewAction());
+
+ QTableWidget* propertiesTable = new QTableWidget();
+ propertiesTable->setColumnCount(3);
+ propertiesTable->setRowCount(10);
+ CDockWidget* PropertiesDockWidget = new CDockWidget("Properties");
+ PropertiesDockWidget->setWidget(propertiesTable);
+ PropertiesDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ PropertiesDockWidget->resize(250, 150);
+ PropertiesDockWidget->setMinimumSize(200,150);
+ DockManager->addDockWidget(DockWidgetArea::RightDockWidgetArea, PropertiesDockWidget, CentralDockArea);
+ ui->menuView->addAction(PropertiesDockWidget->toggleViewAction());
+
+ createPerspectiveUi();
+}
+
+CMainWindow::~CMainWindow()
+{
+ delete ui;
+}
+
+
+void CMainWindow::createPerspectiveUi()
+{
+ SavePerspectiveAction = new QAction("Create Perspective", this);
+ connect(SavePerspectiveAction, SIGNAL(triggered()), SLOT(savePerspective()));
+ PerspectiveListAction = new QWidgetAction(this);
+ PerspectiveComboBox = new QComboBox(this);
+ PerspectiveComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ PerspectiveComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ connect(PerspectiveComboBox, SIGNAL(currentTextChanged(const QString&)),
+ DockManager, SLOT(openPerspective(const QString&)));
+ PerspectiveListAction->setDefaultWidget(PerspectiveComboBox);
+ ui->toolBar->addSeparator();
+ ui->toolBar->addAction(PerspectiveListAction);
+ ui->toolBar->addAction(SavePerspectiveAction);
+}
+
+
+void CMainWindow::savePerspective()
+{
+ QString PerspectiveName = QInputDialog::getText(this, "Save Perspective", "Enter unique name:");
+ if (PerspectiveName.isEmpty())
+ {
+ return;
+ }
+
+ DockManager->addPerspective(PerspectiveName);
+ QSignalBlocker Blocker(PerspectiveComboBox);
+ PerspectiveComboBox->clear();
+ PerspectiveComboBox->addItems(DockManager->perspectiveNames());
+ PerspectiveComboBox->setCurrentText(PerspectiveName);
+}
+
+
+//============================================================================
+void CMainWindow::closeEvent(QCloseEvent* event)
+{
+ // Delete dock manager here to delete all floating widgets. This ensures
+ // that all top level windows of the dock manager are properly closed
+ DockManager->deleteLater();
+ QMainWindow::closeEvent(event);
+}
+
+
diff --git a/QtADS/examples/autohide/mainwindow.h b/QtADS/examples/autohide/mainwindow.h
new file mode 100644
index 0000000..75869da
--- /dev/null
+++ b/QtADS/examples/autohide/mainwindow.h
@@ -0,0 +1,43 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include
+
+#include "DockManager.h"
+#include "DockAreaWidget.h"
+#include "DockWidget.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class CMainWindow; }
+QT_END_NAMESPACE
+
+class CMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ CMainWindow(QWidget *parent = nullptr);
+ ~CMainWindow();
+
+protected:
+ virtual void closeEvent(QCloseEvent* event) override;
+
+private:
+ QAction* SavePerspectiveAction = nullptr;
+ QWidgetAction* PerspectiveListAction = nullptr;
+ QComboBox* PerspectiveComboBox = nullptr;
+
+ Ui::CMainWindow *ui;
+
+ ads::CDockManager* DockManager;
+ ads::CDockAreaWidget* StatusDockArea;
+ ads::CDockWidget* TimelineDockWidget;
+
+ void createPerspectiveUi();
+
+private slots:
+ void savePerspective();
+};
+#endif // MAINWINDOW_H
diff --git a/QtADS/examples/autohide/mainwindow.ui b/QtADS/examples/autohide/mainwindow.ui
new file mode 100644
index 0000000..f7d3b09
--- /dev/null
+++ b/QtADS/examples/autohide/mainwindow.ui
@@ -0,0 +1,47 @@
+
+
+ CMainWindow
+
+
+
+ 0
+ 0
+ 1284
+ 757
+
+
+
+ MainWindow
+
+
+
+
+
+ 0
+ 0
+ 1284
+ 21
+
+
+
+
+ View
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
diff --git a/QtADS/examples/centralwidget/CMakeLists.txt b/QtADS/examples/centralwidget/CMakeLists.txt
new file mode 100644
index 0000000..ae42cdf
--- /dev/null
+++ b/QtADS/examples/centralwidget/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_centralwidget VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(CentralWidgetExample WIN32
+ main.cpp
+ mainwindow.cpp
+ mainwindow.ui
+)
+target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(CentralWidgetExample PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(CentralWidgetExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(CentralWidgetExample PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Central Widget Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/centralwidget/centralwidget.pro b/QtADS/examples/centralwidget/centralwidget.pro
new file mode 100644
index 0000000..738ae78
--- /dev/null
+++ b/QtADS/examples/centralwidget/centralwidget.pro
@@ -0,0 +1,34 @@
+ADS_OUT_ROOT = $${OUT_PWD}/../..
+
+QT += core gui widgets
+
+TARGET = CentralWidgetExample
+DESTDIR = $${ADS_OUT_ROOT}/lib
+TEMPLATE = app
+CONFIG += c++14
+CONFIG += debug_and_release
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+include(../../ads.pri)
+INCLUDEPATH += ../../src
+DEPENDPATH += ../../src
+
diff --git a/QtADS/examples/centralwidget/main.cpp b/QtADS/examples/centralwidget/main.cpp
new file mode 100644
index 0000000..fa4c4fd
--- /dev/null
+++ b/QtADS/examples/centralwidget/main.cpp
@@ -0,0 +1,10 @@
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ CMainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/QtADS/examples/centralwidget/main.py b/QtADS/examples/centralwidget/main.py
new file mode 100644
index 0000000..48c2927
--- /dev/null
+++ b/QtADS/examples/centralwidget/main.py
@@ -0,0 +1,106 @@
+import os
+import sys
+
+from PyQt5 import uic
+from PyQt5.QtCore import Qt, QTimer, QDir, QSignalBlocker
+from PyQt5.QtGui import QCloseEvent, QIcon
+from PyQt5.QtWidgets import (QApplication, QLabel, QCalendarWidget, QFrame, QTreeView,
+ QTableWidget, QFileSystemModel, QPlainTextEdit, QToolBar,
+ QWidgetAction, QComboBox, QAction, QSizePolicy, QInputDialog)
+
+import PyQtAds as QtAds
+
+UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
+MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
+
+class MainWindow(MainWindowUI, MainWindowBase):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.setupUi(self)
+
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.OpaqueSplitterResize, True)
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.XmlCompressionEnabled, False)
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
+ self.dock_manager = QtAds.CDockManager(self)
+
+ # Set central widget
+ text_edit = QPlainTextEdit()
+ text_edit.setPlaceholderText("This is the central editor. Enter your text here.")
+ central_dock_widget = QtAds.CDockWidget("CentralWidget")
+ central_dock_widget.setWidget(text_edit)
+ central_dock_area = self.dock_manager.setCentralWidget(central_dock_widget)
+ central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
+
+ # create other dock widgets
+ table = QTableWidget()
+ table.setColumnCount(3)
+ table.setRowCount(10)
+ table_dock_widget = QtAds.CDockWidget("Table 1")
+ table_dock_widget.setWidget(table)
+ table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ table_dock_widget.resize(250, 150)
+ table_dock_widget.setMinimumSize(200, 150)
+ table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, table_dock_widget)
+ self.menuView.addAction(table_dock_widget.toggleViewAction())
+
+ table = QTableWidget()
+ table.setColumnCount(5)
+ table.setRowCount(1020)
+ table_dock_widget = QtAds.CDockWidget("Table 2")
+ table_dock_widget.setWidget(table)
+ table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ table_dock_widget.resize(250, 150)
+ table_dock_widget.setMinimumSize(200, 150)
+ table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, table_area)
+ self.menuView.addAction(table_dock_widget.toggleViewAction())
+
+ properties_table = QTableWidget()
+ properties_table.setColumnCount(3)
+ properties_table.setRowCount(10)
+ properties_dock_widget = QtAds.CDockWidget("Properties")
+ properties_dock_widget.setWidget(properties_table)
+ properties_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ properties_dock_widget.resize(250, 150)
+ properties_dock_widget.setMinimumSize(200, 150)
+ self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, properties_dock_widget, central_dock_area)
+ self.menuView.addAction(properties_dock_widget.toggleViewAction())
+
+ self.create_perspective_ui()
+
+ def create_perspective_ui(self):
+ save_perspective_action = QAction("Create Perspective", self)
+ save_perspective_action.triggered.connect(self.save_perspective)
+ perspective_list_action = QWidgetAction(self)
+ self.perspective_combobox = QComboBox(self)
+ self.perspective_combobox.setSizeAdjustPolicy(QComboBox.AdjustToContents)
+ self.perspective_combobox.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+ self.perspective_combobox.activated[str].connect(self.dock_manager.openPerspective)
+ perspective_list_action.setDefaultWidget(self.perspective_combobox)
+ self.toolBar.addSeparator()
+ self.toolBar.addAction(perspective_list_action)
+ self.toolBar.addAction(save_perspective_action)
+
+ def save_perspective(self):
+ perspective_name, ok = QInputDialog.getText(self, "Save Perspective", "Enter Unique name:")
+ if not ok or not perspective_name:
+ return
+
+ self.dock_manager.addPerspective(perspective_name)
+ blocker = QSignalBlocker(self.perspective_combobox)
+ self.perspective_combobox.clear()
+ self.perspective_combobox.addItems(self.dock_manager.perspectiveNames())
+ self.perspective_combobox.setCurrentText(perspective_name)
+
+ def closeEvent(self, event: QCloseEvent):
+ self.dock_manager.deleteLater()
+ super().closeEvent(event)
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+
+ w = MainWindow()
+ w.show()
+ app.exec_()
diff --git a/QtADS/examples/centralwidget/mainwindow.cpp b/QtADS/examples/centralwidget/mainwindow.cpp
new file mode 100644
index 0000000..3ad0056
--- /dev/null
+++ b/QtADS/examples/centralwidget/mainwindow.cpp
@@ -0,0 +1,133 @@
+#include "mainwindow.h"
+
+#include "ui_mainwindow.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "DockAreaWidget.h"
+#include "DockAreaTitleBar.h"
+#include "DockAreaTabBar.h"
+#include "FloatingDockContainer.h"
+#include "DockComponentsFactory.h"
+
+using namespace ads;
+
+
+CMainWindow::CMainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::CMainWindow)
+{
+ ui->setupUi(this);
+ CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true);
+ CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false);
+ CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
+ DockManager = new CDockManager(this);
+
+ // Set central widget
+ QPlainTextEdit* w = new QPlainTextEdit();
+ w->setPlaceholderText("This is the central editor. Enter your text here.");
+ CDockWidget* CentralDockWidget = new CDockWidget("CentralWidget");
+ CentralDockWidget->setWidget(w);
+ auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);
+ CentralDockArea->setAllowedAreas(DockWidgetArea::OuterDockAreas);
+
+ // create other dock widgets
+ QTableWidget* table = new QTableWidget();
+ table->setColumnCount(3);
+ table->setRowCount(10);
+ CDockWidget* TableDockWidget = new CDockWidget("Table 1");
+ TableDockWidget->setWidget(table);
+ TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ TableDockWidget->resize(250, 150);
+ TableDockWidget->setMinimumSize(200,150);
+ auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget);
+ ui->menuView->addAction(TableDockWidget->toggleViewAction());
+
+ table = new QTableWidget();
+ table->setColumnCount(5);
+ table->setRowCount(1020);
+ TableDockWidget = new CDockWidget("Table 2");
+ TableDockWidget->setWidget(table);
+ TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ TableDockWidget->resize(250, 150);
+ TableDockWidget->setMinimumSize(200,150);
+ DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea);
+ ui->menuView->addAction(TableDockWidget->toggleViewAction());
+
+ QTableWidget* propertiesTable = new QTableWidget();
+ propertiesTable->setColumnCount(3);
+ propertiesTable->setRowCount(10);
+ CDockWidget* PropertiesDockWidget = new CDockWidget("Properties");
+ PropertiesDockWidget->setWidget(propertiesTable);
+ PropertiesDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ PropertiesDockWidget->resize(250, 150);
+ PropertiesDockWidget->setMinimumSize(200,150);
+ DockManager->addDockWidget(DockWidgetArea::RightDockWidgetArea, PropertiesDockWidget, CentralDockArea);
+ ui->menuView->addAction(PropertiesDockWidget->toggleViewAction());
+
+ createPerspectiveUi();
+}
+
+CMainWindow::~CMainWindow()
+{
+ delete ui;
+}
+
+
+void CMainWindow::createPerspectiveUi()
+{
+ SavePerspectiveAction = new QAction("Create Perspective", this);
+ connect(SavePerspectiveAction, SIGNAL(triggered()), SLOT(savePerspective()));
+ PerspectiveListAction = new QWidgetAction(this);
+ PerspectiveComboBox = new QComboBox(this);
+ PerspectiveComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ PerspectiveComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ connect(PerspectiveComboBox, SIGNAL(currentTextChanged(const QString&)),
+ DockManager, SLOT(openPerspective(const QString&)));
+ PerspectiveListAction->setDefaultWidget(PerspectiveComboBox);
+ ui->toolBar->addSeparator();
+ ui->toolBar->addAction(PerspectiveListAction);
+ ui->toolBar->addAction(SavePerspectiveAction);
+}
+
+
+void CMainWindow::savePerspective()
+{
+ QString PerspectiveName = QInputDialog::getText(this, "Save Perspective", "Enter unique name:");
+ if (PerspectiveName.isEmpty())
+ {
+ return;
+ }
+
+ DockManager->addPerspective(PerspectiveName);
+ QSignalBlocker Blocker(PerspectiveComboBox);
+ PerspectiveComboBox->clear();
+ PerspectiveComboBox->addItems(DockManager->perspectiveNames());
+ PerspectiveComboBox->setCurrentText(PerspectiveName);
+}
+
+
+//============================================================================
+void CMainWindow::closeEvent(QCloseEvent* event)
+{
+ // Delete dock manager here to delete all floating widgets. This ensures
+ // that all top level windows of the dock manager are properly closed
+ DockManager->deleteLater();
+ QMainWindow::closeEvent(event);
+}
+
+
diff --git a/QtADS/examples/centralwidget/mainwindow.h b/QtADS/examples/centralwidget/mainwindow.h
new file mode 100644
index 0000000..75869da
--- /dev/null
+++ b/QtADS/examples/centralwidget/mainwindow.h
@@ -0,0 +1,43 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include
+
+#include "DockManager.h"
+#include "DockAreaWidget.h"
+#include "DockWidget.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class CMainWindow; }
+QT_END_NAMESPACE
+
+class CMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ CMainWindow(QWidget *parent = nullptr);
+ ~CMainWindow();
+
+protected:
+ virtual void closeEvent(QCloseEvent* event) override;
+
+private:
+ QAction* SavePerspectiveAction = nullptr;
+ QWidgetAction* PerspectiveListAction = nullptr;
+ QComboBox* PerspectiveComboBox = nullptr;
+
+ Ui::CMainWindow *ui;
+
+ ads::CDockManager* DockManager;
+ ads::CDockAreaWidget* StatusDockArea;
+ ads::CDockWidget* TimelineDockWidget;
+
+ void createPerspectiveUi();
+
+private slots:
+ void savePerspective();
+};
+#endif // MAINWINDOW_H
diff --git a/QtADS/examples/centralwidget/mainwindow.ui b/QtADS/examples/centralwidget/mainwindow.ui
new file mode 100644
index 0000000..f7d3b09
--- /dev/null
+++ b/QtADS/examples/centralwidget/mainwindow.ui
@@ -0,0 +1,47 @@
+
+
+ CMainWindow
+
+
+
+ 0
+ 0
+ 1284
+ 757
+
+
+
+ MainWindow
+
+
+
+
+
+ 0
+ 0
+ 1284
+ 21
+
+
+
+
+ View
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
diff --git a/QtADS/examples/configflags/CMakeLists.txt b/QtADS/examples/configflags/CMakeLists.txt
new file mode 100644
index 0000000..c231ee7
--- /dev/null
+++ b/QtADS/examples/configflags/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_centralwidget VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(configFlagsExample WIN32
+ main.cpp
+ mainwindow.cpp
+ mainwindow.ui
+)
+target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(CentralWidgetExample PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(CentralWidgetExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(CentralWidgetExample PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Central Widget Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/configflags/configflags.pro b/QtADS/examples/configflags/configflags.pro
new file mode 100644
index 0000000..8327174
--- /dev/null
+++ b/QtADS/examples/configflags/configflags.pro
@@ -0,0 +1,34 @@
+ADS_OUT_ROOT = $${OUT_PWD}/../..
+
+QT += core gui widgets
+
+TARGET = ConfigFlagsExample
+DESTDIR = $${ADS_OUT_ROOT}/lib
+TEMPLATE = app
+CONFIG += c++14
+CONFIG += debug_and_release
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+include(../../ads.pri)
+INCLUDEPATH += ../../src
+DEPENDPATH += ../../src
+
diff --git a/QtADS/examples/configflags/main.cpp b/QtADS/examples/configflags/main.cpp
new file mode 100644
index 0000000..fa4c4fd
--- /dev/null
+++ b/QtADS/examples/configflags/main.cpp
@@ -0,0 +1,10 @@
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ CMainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/QtADS/examples/configflags/mainwindow.cpp b/QtADS/examples/configflags/mainwindow.cpp
new file mode 100644
index 0000000..2ce359b
--- /dev/null
+++ b/QtADS/examples/configflags/mainwindow.cpp
@@ -0,0 +1,65 @@
+#include "mainwindow.h"
+
+#include "ui_mainwindow.h"
+
+#include
+#include
+
+#include "DockAreaWidget.h"
+#include "DockAreaTitleBar.h"
+
+
+using namespace ads;
+
+
+CMainWindow::CMainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::CMainWindow)
+{
+ ui->setupUi(this);
+
+ // Add the toolbar
+ auto toolbar_ = addToolBar("Top Toolbar");
+
+ // Create the dock manager
+ ads::CDockManager::setConfigFlags(ads::CDockManager::DefaultOpaqueConfig);
+ ads::CDockManager::setConfigFlag(ads::CDockManager::DockAreaHasCloseButton,
+ false);
+ ads::CDockManager::setConfigFlag(ads::CDockManager::DockAreaHasUndockButton,
+ false);
+ ads::CDockManager::setConfigFlag(
+ ads::CDockManager::DockAreaHasTabsMenuButton, false);
+ auto DockManager = new ads::CDockManager(this);
+
+ // Create a dockable widget
+ QLabel *l1 = new QLabel();
+ l1->setWordWrap(true);
+ l1->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l1->setText("Docking widget 1");
+ ads::CDockWidget *dockWidget1 = new ads::CDockWidget("Dock 1");
+ dockWidget1->setWidget(l1);
+ DockManager->addDockWidget(ads::LeftDockWidgetArea, dockWidget1);
+
+ QLabel *l2 = new QLabel();
+ l2->setWordWrap(true);
+ l2->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l2->setText("Docking widget 2");
+ ads::CDockWidget *dockWidget2 = new ads::CDockWidget("Dock 2");
+ dockWidget2->setWidget(l2);
+ DockManager->addDockWidget(ads::RightDockWidgetArea, dockWidget2);
+
+ // Add menu actions
+ ui->menuView->addAction(dockWidget1->toggleViewAction());
+ ui->menuView->addAction(dockWidget2->toggleViewAction());
+ toolbar_->addAction(dockWidget1->toggleViewAction());
+ toolbar_->addAction(dockWidget2->toggleViewAction());
+}
+
+
+CMainWindow::~CMainWindow()
+{
+ delete ui;
+}
+
+
+
diff --git a/QtADS/examples/configflags/mainwindow.h b/QtADS/examples/configflags/mainwindow.h
new file mode 100644
index 0000000..a2b45da
--- /dev/null
+++ b/QtADS/examples/configflags/mainwindow.h
@@ -0,0 +1,27 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include
+
+#include "DockManager.h"
+#include "DockAreaWidget.h"
+#include "DockWidget.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class CMainWindow; }
+QT_END_NAMESPACE
+
+class CMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ CMainWindow(QWidget *parent = nullptr);
+ ~CMainWindow();
+
+private:
+ Ui::CMainWindow *ui;
+};
+#endif // MAINWINDOW_H
diff --git a/QtADS/examples/configflags/mainwindow.ui b/QtADS/examples/configflags/mainwindow.ui
new file mode 100644
index 0000000..f7d3b09
--- /dev/null
+++ b/QtADS/examples/configflags/mainwindow.ui
@@ -0,0 +1,47 @@
+
+
+ CMainWindow
+
+
+
+ 0
+ 0
+ 1284
+ 757
+
+
+
+ MainWindow
+
+
+
+
+
+ 0
+ 0
+ 1284
+ 21
+
+
+
+
+ View
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
diff --git a/QtADS/examples/deleteonclose/CMakeLists.txt b/QtADS/examples/deleteonclose/CMakeLists.txt
new file mode 100644
index 0000000..98557a6
--- /dev/null
+++ b/QtADS/examples/deleteonclose/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_deleteonclose VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(DeleteOnCloseTest WIN32
+ main.cpp
+)
+target_include_directories(DeleteOnCloseTest PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(DeleteOnCloseTest PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(DeleteOnCloseTest PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(DeleteOnCloseTest PROPERTIES
+ AUTOMOC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Delete on Close Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/deleteonclose/deleteonclose.pro b/QtADS/examples/deleteonclose/deleteonclose.pro
new file mode 100644
index 0000000..95d1db0
--- /dev/null
+++ b/QtADS/examples/deleteonclose/deleteonclose.pro
@@ -0,0 +1,23 @@
+ADS_OUT_ROOT = $${OUT_PWD}/../..
+
+QT += core gui widgets
+
+TARGET = DeleteOnCloseTest
+DESTDIR = $${ADS_OUT_ROOT}/lib
+TEMPLATE = app
+CONFIG += c++14
+CONFIG += debug_and_release
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += main.cpp
+
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+include(../../ads.pri)
+INCLUDEPATH += ../../src
+DEPENDPATH += ../../src
+
diff --git a/QtADS/examples/deleteonclose/main.cpp b/QtADS/examples/deleteonclose/main.cpp
new file mode 100644
index 0000000..25f8ed1
--- /dev/null
+++ b/QtADS/examples/deleteonclose/main.cpp
@@ -0,0 +1,90 @@
+#include
+#include
+#include
+#include
+#include
+#include "DockManager.h"
+
+
+class MainWindow : public QMainWindow
+{
+private:
+ ads::CDockManager* m_DockManager = nullptr;
+
+protected:
+ virtual void closeEvent(QCloseEvent *event) override
+ {
+ QMainWindow::closeEvent(event);
+ if (m_DockManager)
+ {
+ m_DockManager->deleteLater();
+ }
+ }
+
+public:
+ void setDockManager(ads::CDockManager* DockManager) {m_DockManager = DockManager;}
+};
+
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+
+ ads::CDockManager::setConfigFlag(ads::CDockManager::FocusHighlighting, true);
+ ads::CDockManager::setConfigFlag(ads::CDockManager::AllTabsHaveCloseButton, true);
+ auto dockManager = new ads::CDockManager(&w);
+ w.setDockManager(dockManager);
+ QObject::connect(dockManager, &ads::CDockManager::focusedDockWidgetChanged, [] (ads::CDockWidget* old, ads::CDockWidget* now) {
+ static int Count = 0;
+ qDebug() << Count++ << " CDockManager::focusedDockWidgetChanged old: " << (old ? old->objectName() : "-") << " now: " << now->objectName() << " visible: " << now->isVisible();
+ now->widget()->setFocus();
+ });
+
+ QAction *action = new QAction("New [DockWidgetDeleteOnClose]", &w);
+ w.menuBar()->addAction(action);
+
+ int i = 0;
+ QObject::connect(action, &QAction::triggered, [&]() {
+ auto dw = new ads::CDockWidget(QStringLiteral("test %1 [DockWidgetDeleteOnClose]").arg(i++), &w);
+ auto editor = new QTextEdit(QStringLiteral("lorem ipsum..."), dw);
+ dw->setWidget(editor);
+ dw->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
+ auto area = dockManager->addDockWidgetTab(ads::CenterDockWidgetArea, dw);
+ qDebug() << "doc dock widget created!" << dw << area;
+ });
+
+ auto dw = new ads::CDockWidget(QStringLiteral("test %1 [DeleteContentOnClose]").arg(i++), &w);
+ auto editor = new QTextEdit(QStringLiteral("recreated lorem ipsum......"), dw);
+ dw->setWidget(editor);
+ dw->setFeature(ads::CDockWidget::DeleteContentOnClose, true);
+ dw->setWidgetFactory([](QWidget* dw)
+ {
+ static int timesRecreated = 0;
+ return new QTextEdit(QStringLiteral("recreated lorem ipsum... times %1").arg(++timesRecreated), dw);
+ });
+ auto area = dockManager->addDockWidgetTab(ads::CenterDockWidgetArea, dw);
+ qDebug() << "DeleteContentOnClose dock widget created!" << dw << area;
+
+ action = new QAction("Toggle [DeleteContentOnClose]", &w);
+ w.menuBar()->addAction(action);
+
+ QObject::connect(action, &QAction::triggered, [dw]() {
+ dw->toggleView(dw->isClosed());
+ qDebug() << QString("dock widget %1! contents widget %2!").arg(dw->isClosed() ? "closed" : "open", dw->widget() ? "created" : "deleted");
+ });
+
+ action = new QAction("New", &w);
+ w.menuBar()->addAction(action);
+ QObject::connect(action, &QAction::triggered, [&]() {
+ auto dw = new ads::CDockWidget(QStringLiteral("test %1").arg(i++), &w);
+ auto editor = new QTextEdit(QStringLiteral("lorem ipsum..."), dw);
+ dw->setWidget(editor);
+ auto area = dockManager->addDockWidgetTab(ads::CenterDockWidgetArea, dw);
+ qDebug() << "dock widget created!" << dw << area;
+ });
+
+ w.show();
+
+ return a.exec();
+}
diff --git a/QtADS/examples/deleteonclose/main.py b/QtADS/examples/deleteonclose/main.py
new file mode 100644
index 0000000..d1504bf
--- /dev/null
+++ b/QtADS/examples/deleteonclose/main.py
@@ -0,0 +1,73 @@
+import sys
+
+import PyQtAds as QtAds
+from PyQt5.QtGui import QCloseEvent
+from PyQt5.QtCore import (qDebug, pyqtSlot, QObject, pyqtSignal)
+from PyQt5.QtWidgets import (QMainWindow, QAction, QTextEdit, QApplication,
+ QMenuBar)
+
+
+class MainWindow(QMainWindow):
+ dock_manager = None
+
+ def closeEvent(self, event: QCloseEvent):
+ super().closeEvent(event)
+ if self.dock_manager is not None:
+ self.dock_manager.deleteLater()
+
+ def setDockManager(self, dock_manager: QtAds.CDockManager):
+ self.dock_manager = dock_manager
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+ w = MainWindow()
+
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.AllTabsHaveCloseButton, True)
+ dock_manager = QtAds.CDockManager(w)
+ w.setDockManager(dock_manager)
+
+ count = 0
+
+ def on_focused_dock_widget_changed(old: QtAds.CDockWidget, now: QtAds.CDockWidget):
+ global count
+ qDebug( "{:d} CDockManager::focusedDockWidgetChanged old: {} now: {} visible: {}".format(
+ count,
+ old.objectName() if old else "-",
+ now.objectName(),
+ now.isVisible()))
+ count += 1
+ now.widget().setFocus()
+
+ dock_manager.focusedDockWidgetChanged.connect(on_focused_dock_widget_changed)
+
+ action = QAction("New Delete On Close", w)
+ w.menuBar().addAction(action)
+
+ i = 0
+ def on_action_triggered():
+ global i
+ dw = QtAds.CDockWidget("test doc {:d}".format(i))
+ i += 1
+ editor = QTextEdit("lorem ipsum...", dw)
+ dw.setWidget(editor)
+ dw.setFeature(QtAds.CDockWidget.DockWidgetDeleteOnClose, True)
+ area = dock_manager.addDockWidgetTab(QtAds.CenterDockWidgetArea, dw)
+ qDebug("doc dock widget created! {} {}".format(dw, area))
+ action.triggered.connect(on_action_triggered)
+
+ action = QAction("New", w)
+ w.menuBar().addAction(action)
+ def on_action2_triggered():
+ global i
+ dw = QtAds.CDockWidget("test {:d}".format(i))
+ i += 1
+ editor = QTextEdit("lorem ipsum...", dw)
+ dw.setWidget(editor)
+ area = dock_manager.addDockWidgetTab(QtAds.CenterDockWidgetArea, dw)
+ qDebug("dock widget created! {} {}".format(dw, area))
+ action.triggered.connect(on_action2_triggered)
+
+ w.show()
+ app.exec_()
diff --git a/QtADS/examples/dockindock/CMakeLists.txt b/QtADS/examples/dockindock/CMakeLists.txt
new file mode 100644
index 0000000..39ba98c
--- /dev/null
+++ b/QtADS/examples/dockindock/CMakeLists.txt
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_dockindock VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(DockInDockExample WIN32
+ dockindock.cpp
+ dockindockmanager.cpp
+ perspectiveactions.cpp
+ perspectives.cpp
+ main.cpp
+ mainframe.cpp
+)
+target_include_directories(DockInDockExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(DockInDockExample PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(DockInDockExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(DockInDockExample PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Simple Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/dockindock/dockindock.cpp b/QtADS/examples/dockindock/dockindock.cpp
new file mode 100644
index 0000000..bacf42c
--- /dev/null
+++ b/QtADS/examples/dockindock/dockindock.cpp
@@ -0,0 +1,300 @@
+#include "dockindock.h"
+#include "perspectives.h"
+#include "dockindockmanager.h"
+#include "perspectiveactions.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+using namespace QtAdsUtl;
+
+DockInDockWidget::DockInDockWidget( QWidget* parent, bool canCreateNewGroups, PerspectivesManager* perspectivesManager ) :
+ DockInDockWidget( parent, (DockInDockWidget*)NULL, perspectivesManager )
+{
+ m_canCreateNewGroups = canCreateNewGroups;
+ m_topLevelDockWidget = this;
+}
+
+DockInDockWidget::DockInDockWidget( QWidget* parent, DockInDockWidget* topLevelDockWidget, PerspectivesManager* perspectivesManager ) :
+ baseClass( parent ),
+ m_topLevelDockWidget( topLevelDockWidget ),
+ m_canCreateNewGroups( (topLevelDockWidget) ? topLevelDockWidget->m_canCreateNewGroups : false ),
+ m_perspectivesManager( perspectivesManager )
+{
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ layout->setContentsMargins( 0,0,0,0 );
+ layout->addWidget( m_mgr = new DockInDockManager(*this) );
+}
+
+DockInDockWidget::~DockInDockWidget()
+{
+
+}
+
+ads::CDockAreaWidget* DockInDockWidget::addTabWidget( QWidget* widget, const QString& name, ads::CDockAreaWidget* after )
+{
+ return addTabWidget( widget, name, QIcon(), after );
+}
+
+ads::CDockAreaWidget* DockInDockWidget::addTabWidget( QWidget* widget, const QString& name, QIcon icon, ads::CDockAreaWidget* after )
+{
+ for ( auto existing : getTopLevelDockWidget()->getManager()->allDockWidgets(true,true) )
+ {
+ if ( existing.second->objectName() == name )
+ {
+ QMessageBox::critical( this, "Error", "Name '" + name + "' already in use" );
+ return NULL;
+ }
+ }
+
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(name);
+ DockWidget->setWidget(widget);
+ DockWidget->setIcon( icon );
+
+ // Add the dock widget to the top dock widget area
+ return m_mgr->addDockWidget(ads::CenterDockWidgetArea, DockWidget, after);
+}
+
+bool DockInDockWidget::isTopLevel()
+{
+ return objectName().isEmpty();
+}
+
+QString DockInDockWidget::getGroupNameError( const QString& groupName )
+{
+ if ( groupName.isEmpty() )
+ {
+ return "Group must have a non-empty name";
+ }
+
+ std::vector dockManagers = m_mgr->allManagers( true, true );
+ for ( auto mgr : dockManagers )
+ {
+ if ( mgr->getGroupName() == groupName )
+ return "Group name '" + groupName + "' already used";
+ }
+
+ return "";
+}
+
+DockInDockWidget* DockInDockWidget::createGroup( const QString& groupName, ads::CDockAreaWidget*& insertPos )
+{
+ return createGroup( groupName, QIcon(), insertPos );
+}
+
+DockInDockWidget* DockInDockWidget::createGroup( const QString& groupName, QIcon icon, ads::CDockAreaWidget*& insertPos )
+{
+ QString error = getGroupNameError( groupName );
+ if ( !error.isEmpty() )
+ {
+ QMessageBox::critical( NULL, "Error", error );
+ return NULL;
+ }
+
+ DockInDockWidget* child = new DockInDockWidget( this, m_topLevelDockWidget, m_perspectivesManager );
+ child->setObjectName( groupName );
+
+ ads::CDockWidget* DockWidget = new ads::CDockWidget(groupName);
+ DockWidget->setWidget(child);
+ DockWidget->setIcon(icon);
+
+ insertPos = m_mgr->addDockWidget(ads::CenterDockWidgetArea, DockWidget, insertPos);
+
+ return child;
+}
+
+void DockInDockWidget::destroyGroup( DockInDockWidget* widgetToRemove )
+{
+ auto topLevelWidget = widgetToRemove->getTopLevelDockWidget();
+
+ if ( topLevelWidget && topLevelWidget != widgetToRemove )
+ {
+ // reaffect all child docks to top-level
+ for ( auto dockwidget : widgetToRemove->getManager()->getWidgetsInGUIOrder() ) // don't use allDockWidgets to preserve sub-groups
+ {
+ MoveDockWidgetAction::move( dockwidget, topLevelWidget->getManager() );
+ }
+ assert( widgetToRemove->getManager()->allDockWidgets( true, true ).empty() );
+
+ // find widget's parent:
+ for ( auto dockwidget : topLevelWidget->getManager()->allDockWidgets( true, true ) )
+ {
+ if ( dockwidget.second->widget() == widgetToRemove )
+ {
+ dockwidget.first->removeDockWidget( dockwidget.second );
+ delete dockwidget.second;
+ //delete widgetToRemove; automatically deleted when dockWidget is deleted
+ widgetToRemove = NULL;
+ break;
+ }
+ }
+
+ assert( widgetToRemove == NULL );
+ }
+ else
+ {
+ assert( false );
+ }
+}
+
+void DockInDockWidget::attachViewMenu( QMenu* menu )
+{
+ connect( menu, SIGNAL(aboutToShow()), this, SLOT(autoFillAttachedViewMenu()) );
+}
+
+void DockInDockWidget::autoFillAttachedViewMenu()
+{
+ QMenu* menu = dynamic_cast( QObject::sender() );
+
+ if ( menu )
+ {
+ menu->clear();
+ setupViewMenu( menu );
+ }
+ else
+ {
+ assert( false );
+ }
+}
+
+void DockInDockWidget::setupViewMenu( QMenu* menu )
+{
+ std::vector dockManagers = m_mgr->allManagers( true, true );
+
+ bool hasPerspectivesMenu = false;
+ if ( getTopLevelDockWidget() == this )
+ hasPerspectivesMenu = (m_perspectivesManager != NULL);
+ else
+ assert( false );
+
+ QMenu* organize = menu;
+ if ( hasPerspectivesMenu )
+ organize = menu->addMenu( "Organize" );
+
+ setupMenu( organize, dockManagers );
+
+ if ( hasPerspectivesMenu )
+ {
+ QMenu* perspectives = menu->addMenu( "Perspectives" );
+ fillPerspectivesMenu( perspectives );
+ }
+}
+
+void DockInDockWidget::setupMenu( QMenu* menu, const std::vector& moveTo )
+{
+ m_mgr->fillViewMenu( menu, moveTo );
+ menu->addSeparator();
+ auto moveMenu = menu->addMenu( "Move" );
+ m_mgr->fillMoveMenu( moveMenu, moveTo );
+}
+
+void DockInDockWidget::fillPerspectivesMenu( QMenu* menu )
+{
+ menu->addAction( "Create perspective...", this, SLOT(createPerspective()) );
+
+ QStringList perspectiveNames;
+ if ( m_perspectivesManager )
+ perspectiveNames = m_perspectivesManager->perspectiveNames();
+
+ if ( !perspectiveNames.isEmpty() )
+ {
+ QMenu* load = menu->addMenu( "Load perspective" );
+ for (const auto& name : perspectiveNames)
+ {
+ load->addAction(new LoadPerspectiveAction( load, name, *this));
+ }
+ QMenu* remove = menu->addMenu( "Remove perspective" );
+ for (const auto& name : perspectiveNames)
+ {
+ remove->addAction( new RemovePerspectiveAction( remove, name, *this ));
+ }
+ }
+}
+
+void DockInDockWidget::setNewPerspectiveDefaultName( const QString& defaultName )
+{
+ m_newPerspectiveDefaultName = defaultName;
+}
+
+void DockInDockWidget::createPerspective()
+{
+ if ( !m_perspectivesManager )
+ return;
+
+ QString name = m_newPerspectiveDefaultName;
+ if ( !m_newPerspectiveDefaultName.isEmpty() )
+ {
+ int index = 2;
+ while ( m_perspectivesManager->perspectiveNames().contains( name ) )
+ {
+ name = m_newPerspectiveDefaultName + " (" + QString::number(index) + ")";
+ ++index;
+ }
+ }
+
+ while ( true )
+ {
+ bool ok = false;
+ name = QInputDialog::getText( NULL, "Create perspective", "Enter perspective name", QLineEdit::Normal, name, &ok );
+ if ( ok )
+ {
+ if ( name.isEmpty() )
+ {
+ QMessageBox::critical( NULL, "Error", "Perspective name cannot be empty" );
+ continue;
+ }
+ else if ( m_perspectivesManager->perspectiveNames().contains( name ) )
+ {
+ if ( QMessageBox::critical( NULL, "Error", "Perspective '" + name + "' already exists, overwrite it?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
+ continue;
+ }
+
+ m_perspectivesManager->addPerspective( name, *this );
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+static void dumpStatus( std::ostream& str, ads::CDockWidget* widget, const std::string& tab, std::string suffix )
+{
+ DockInDockManager* asMgr = DockInDockManager::dockInAManager( widget );
+ if ( asMgr )
+ {
+ asMgr->parent().dumpStatus( str, tab );
+ }
+ else
+ {
+ str << tab << widget->objectName().toStdString() << suffix << std::endl;
+ }
+}
+
+void DockInDockWidget::dumpStatus( std::ostream& str, std::string tab )
+{
+ str << tab << "Group: " << getManager()->getGroupName().toStdString() << std::endl;
+ tab += " ";
+ std::set visibleWidgets;
+ for ( auto widget : getManager()->getWidgetsInGUIOrder() )
+ {
+ visibleWidgets.insert( widget );
+ ::dumpStatus( str, widget, tab, "" );
+ }
+
+ for ( auto closed : getManager()->dockWidgetsMap() )
+ {
+ if ( visibleWidgets.find( closed ) == visibleWidgets.end() )
+ {
+ ::dumpStatus( str, closed, tab, " (closed)" );
+ }
+ }
+}
diff --git a/QtADS/examples/dockindock/dockindock.h b/QtADS/examples/dockindock/dockindock.h
new file mode 100644
index 0000000..aaa9ffd
--- /dev/null
+++ b/QtADS/examples/dockindock/dockindock.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include
+#include
+
+#include
+#include
+
+class QMenu;
+
+namespace ads
+{
+ class CDockAreaWidget;
+}
+
+namespace QtAdsUtl
+{
+
+class DockInDockManager;
+class PerspectivesManager;
+// tab of tab example for https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/306
+class DockInDockWidget : public QWidget
+{
+ typedef QWidget baseClass;
+
+ Q_OBJECT
+
+public:
+ DockInDockWidget( QWidget* parent, bool canCreateNewGroups, PerspectivesManager* perspectivesManager );
+ ~DockInDockWidget() override;
+
+ ads::CDockAreaWidget* addTabWidget( QWidget* widget, const QString& name, ads::CDockAreaWidget* after );
+ DockInDockWidget* createGroup( const QString& groupName, ads::CDockAreaWidget*& insertPos );
+
+ ads::CDockAreaWidget* addTabWidget( QWidget* widget, const QString& name, QIcon icon, ads::CDockAreaWidget* after );
+ DockInDockWidget* createGroup( const QString& groupName, QIcon icon, ads::CDockAreaWidget*& insertPos );
+
+ QString getGroupNameError( const QString& groupName );
+ void destroyGroup( DockInDockWidget* widget );
+
+ /** Manually fill a given view menu */
+ void setupViewMenu( QMenu* menu );
+
+ /** Attach a view menu that will be automatically fill */
+ void attachViewMenu( QMenu* menu );
+
+ bool isTopLevel();
+ void setupMenu( QMenu* menu, const std::vector& moveTo );
+
+ inline DockInDockManager* getManager() { return m_mgr; }
+ inline DockInDockWidget* getTopLevelDockWidget() { return m_topLevelDockWidget; }
+
+ inline bool canCreateNewGroups() const { return m_canCreateNewGroups; }
+
+ void dumpStatus( std::ostream& str, std::string tab = "" );
+
+ inline PerspectivesManager* getPerspectivesManager() { return m_perspectivesManager; }
+
+ void setNewPerspectiveDefaultName( const QString& defaultName );
+
+private slots:
+ void autoFillAttachedViewMenu();
+ void createPerspective();
+
+private:
+ DockInDockManager* m_mgr;
+ DockInDockWidget* m_topLevelDockWidget;
+
+ bool m_canCreateNewGroups;
+
+ DockInDockWidget( QWidget* parent, DockInDockWidget* topLevelDockWidget, PerspectivesManager* perspectivesManager );
+
+ PerspectivesManager* m_perspectivesManager;
+ QString m_newPerspectiveDefaultName;
+
+ void fillPerspectivesMenu( QMenu* menu );
+};
+
+}
+
diff --git a/QtADS/examples/dockindock/dockindock.pro b/QtADS/examples/dockindock/dockindock.pro
new file mode 100644
index 0000000..45242d1
--- /dev/null
+++ b/QtADS/examples/dockindock/dockindock.pro
@@ -0,0 +1,35 @@
+ADS_OUT_ROOT = $${OUT_PWD}/../..
+
+QT += core gui widgets
+
+TARGET = DockInDock
+DESTDIR = $${ADS_OUT_ROOT}/lib
+TEMPLATE = app
+CONFIG += c++14
+CONFIG += debug_and_release
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += \
+ dockindock.cpp \
+ dockindockmanager.cpp \
+ perspectiveactions.cpp \
+ perspectives.cpp \
+ main.cpp \
+ mainframe.cpp
+
+HEADERS += \
+ dockindock.h \
+ dockindockmanager.h \
+ perspectiveactions.h \
+ perspectives.h \
+ mainframe.h
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+include(../../ads.pri)
+INCLUDEPATH += ../../src
+DEPENDPATH += ../../src
+
diff --git a/QtADS/examples/dockindock/dockindock.py b/QtADS/examples/dockindock/dockindock.py
new file mode 100644
index 0000000..5d64fe1
--- /dev/null
+++ b/QtADS/examples/dockindock/dockindock.py
@@ -0,0 +1,203 @@
+import sys
+
+from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QMessageBox,
+ QInputDialog, QMenu, QLineEdit)
+from PyQt5.QtGui import QIcon
+import PyQtAds as QtAds
+
+from dockindockmanager import DockInDockManager
+from perspectiveactions import LoadPerspectiveAction, RemovePerspectiveAction
+
+
+class DockInDockWidget(QWidget):
+ def __init__(self, parent, perspectives_manager: 'PerspectivesManager', can_create_new_groups: bool = False, top_level_widget = None):
+ super().__init__(parent)
+
+ if top_level_widget is not None:
+ self.__can_create_new_groups = top_level_widget.can_create_new_groups
+ else:
+ self.__can_create_new_groups = can_create_new_groups
+ self.__top_level_dock_widget = top_level_widget if top_level_widget else self
+ self.__perspectives_manager = perspectives_manager
+ self.__new_perspective_default_name: str = ''
+
+ layout = QVBoxLayout(self)
+ layout.setContentsMargins(0,0,0,0)
+ self.__mgr = DockInDockManager(self)
+ layout.addWidget(self.__mgr)
+
+ def getManager(self) -> 'DockInDockManager':
+ return self.__mgr
+
+ def getTopLevelDockWidget(self) -> 'DockInDockWidget':
+ return self.__top_level_dock_widget
+
+ def canCreateNewGroups(self) -> bool:
+ return self.__can_create_new_groups
+
+ def getPerspectivesManager(self) -> 'PerspectivesManager':
+ return self.__perspectives_manager
+
+ def addTabWidget(self, widget: QWidget, name: str, after: QtAds.CDockAreaWidget, icon = QIcon()) -> QtAds.CDockAreaWidget:
+ for existing in self.getTopLevelDockWidget().getManager().allDockWidgets(True, True):
+ if existing[1].objectName() == name:
+ QMessageBox.critical(self, "Error", "Name '" + name + "' already in use")
+ return
+
+ dock_widget = QtAds.CDockWidget(name)
+ dock_widget.setWidget(widget)
+ dock_widget.setIcon(icon)
+
+ # Add the dock widget to the top dock widget area
+ return self.__mgr.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, after)
+
+ def isTopLevel(self) -> bool:
+ return not self.objectName()
+
+ def getGroupNameError(self, group_name: str) -> str:
+ if not group_name:
+ return "Group must have a non-empty name"
+
+ dock_managers = self.__mgr.allManagers(True, True)
+ for mgr in dock_managers:
+ if mgr.getGroupName() == group_name:
+ return "Group name '" + group_name + "' already used"
+
+ return ""
+
+ def createGroup(self, group_name: str, insert_pos: QtAds.CDockAreaWidget, icon = QIcon()) -> 'DockInDockWidget':
+ error = self.getGroupNameError(group_name)
+ if error:
+ QMessageBox.critical(None, "Error", error)
+ return
+
+ child = DockInDockWidget(self, self.__top_level_dock_widget, self.__perspectives_manager)
+ child.setObjectName(group_name)
+
+ dock_widget = QtAds.CDockWidget(group_name)
+ dock_widget.setWidget(child)
+ dock_widget.setIcon(icon)
+
+ insert_pos = self.__mgr.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, insert_pos)
+
+ return child, insert_pos
+
+ def destroyGroup(self, widget_to_remove: 'DockInDockWidget') -> None:
+ top_level_widget = widget_to_remove.getTopLevelDockWidget()
+
+ if top_level_widget and top_level_widget != widget_to_remove:
+ for dock_widget in widget_to_remove.getManager().getWidgetsInGUIOrder(): #don't use allDockWidgets to preserve sub-groups
+ MoveDockWidgetAction.move(dock_widget, top_level_widget.getManager())
+ assert not widget_to_remove.getManager().allDockWidgets(True, True)
+
+ # find widget's parent:
+ for dock_widget in top_level_widget.getManager().allDockWidgets(True, True):
+ if dockwidget[1].widget() == widget_to_remove:
+ dockwidget[0].removeDockWidget(dockwidget[1])
+ del dockwidget[1]
+ # delete widgetToRemove; automatically deleted when dockWidget is deleted
+ widget_to_remove = None
+ break
+
+ assert widget_to_remove == None
+ else:
+ assert False
+
+ def attachViewMenu(self, menu: QMenu) -> None:
+ menu.aboutToShow.connect(self.autoFillAttachedViewMenu)
+
+ def autoFillAttachedViewMenu(self) -> None:
+ menu = self.sender()
+
+ if menu:
+ menu.clear()
+ self.setupViewMenu(menu)
+ else:
+ assert False
+
+ def setupViewMenu(self, menu):
+ dock_managers = self.__mgr.allManagers(True, True)
+
+ has_perspectives_menu = False
+ if self.getTopLevelDockWidget() == self:
+ has_perspectives_menu = (self.__perspectives_manager != None)
+ else:
+ assert False
+
+ organize = menu
+ if has_perspectives_menu:
+ organize = menu.addMenu("Organize")
+
+ self.setupMenu(organize, dock_managers)
+
+ if has_perspectives_menu:
+ perspectives = menu.addMenu("Perspectives")
+ self.fillPerspectivesMenu(perspectives)
+
+ def setupMenu(self, menu: QMenu, move_to: 'list[DockInDockManager]') -> None:
+ self.__mgr.fillViewMenu(menu, move_to)
+ menu.addSeparator()
+ move_menu = menu.addMenu("Move")
+ self.__mgr.fillMoveMenu(move_menu, move_to)
+
+ def fillPerspectivesMenu(self, menu: QMenu):
+ menu.addAction("Create perspective...", self.createPerspective)
+ perspectives_names = []
+ if self.__perspectives_manager:
+ perspectives_names = self.__perspectives_manager.perspectiveNames()
+
+ if perspectives_names:
+ load = menu.addMenu("Load perspective")
+ for name in perspectives_names:
+ load.addAction(LoadPerspectiveAction(load, name, self))
+ remove = menu.addMenu("Remove perspective")
+ for name in perspectives_names:
+ remove.addAction(RemovePerspectiveAction(remove, name, self))
+
+ def setNewPerspectiveDefaultName(default_name: str) -> None:
+ self.__new_perspective_default_name = default_name
+
+ def createPerspective(self) -> None:
+ if not self.__perspectives_manager:
+ return
+
+ name = self.__new_perspective_default_name
+ if self.__new_perspective_default_name:
+ index = 2
+ while name in self.__perspectives_manager.perspectiveNames():
+ name = f"{self.__new_perspective_default_name}({index})"
+ index += 1
+
+ while True:
+ name, ok = QInputDialog.getText(None, "Create perspective", "Enter perspective name", QLineEdit.Normal, name)
+ if ok:
+ if not name:
+ QMessageBox.critical(None, "Error", "Perspective name cannot be empty")
+ continue
+ elif name in self.__perspectives_manager.perspectiveNames():
+ if QMessageBox.critical(None, "Error", f"Perspective '{name}' already exists, overwrite it?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.No:
+ continue
+
+ self.__perspectives_manager.addPerspective(name, self)
+ break
+ else:
+ break
+
+ def dumpStatus(self, echo: callable = print, widget: QtAds.CDockWidget = None, tab: str = '', suffix: str = '') -> str:
+ if widget is not None:
+ as_mgr = DockInDockManager.dockInAManager(widget)
+ if as_mgr:
+ as_mgr.parent().dumpStatus(tab=tab)
+ else:
+ echo(tab + widget.objectName() + suffix)
+ else:
+ echo(tab + "Group: " + self.getManager().getGroupName())
+ tab += " "
+ visible_widgets = set()
+ for widget in self.getManager().getWidgetsInGUIOrder():
+ visible_widgets.add(widget)
+ self.dumpStatus(widget=widget, tab=tab)
+
+ for closed in self.getManager().dockWidgetsMap().values():
+ if not closed in visible_widgets:
+ self.dumpStatus(widget=closed, tab=tab, suffix=" (closed)")
diff --git a/QtADS/examples/dockindock/dockindockmanager.cpp b/QtADS/examples/dockindock/dockindockmanager.cpp
new file mode 100644
index 0000000..160318c
--- /dev/null
+++ b/QtADS/examples/dockindock/dockindockmanager.cpp
@@ -0,0 +1,334 @@
+#include "dockindockmanager.h"
+#include "dockindock.h"
+
+#include "DockAreaWidget.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+using namespace QtAdsUtl;
+
+/////////////////////////////////////
+// DockInDockManager
+/////////////////////////////////////
+DockInDockManager::DockInDockManager( DockInDockWidget& parent ) :
+ baseClass( &parent ),
+ m_parent( parent )
+{
+
+}
+
+DockInDockManager::~DockInDockManager()
+{
+
+}
+
+void DockInDockManager::fillViewMenu( QMenu* menu, const std::vector& moveTo )
+{
+ auto widgetsMap = dockWidgetsMap();
+ for ( auto iter = widgetsMap.begin(); iter != widgetsMap.end(); ++iter )
+ {
+ auto widget = iter.value()->widget();
+ auto action = iter.value()->toggleViewAction();
+
+ DockInDockWidget* asMgr = dynamic_cast( widget );
+ if ( asMgr )
+ {
+ auto subMenu = menu->addMenu( iter.key() );
+
+ subMenu->addAction( action );
+ subMenu->addSeparator();
+
+ asMgr->setupMenu( subMenu, moveTo );
+ }
+ else
+ {
+ menu->addAction(action);
+ }
+ }
+
+ if ( parent().canCreateNewGroups() )
+ {
+ // see how this works, to create it in the right place,
+ // and also to have load perspective work when some groups are missing
+ menu->addSeparator();
+ menu->addAction( new QtAdsUtl::CreateChildDockAction( m_parent, menu ) );
+
+ if ( parent().getTopLevelDockWidget()->getManager() != this )
+ menu->addAction( new QtAdsUtl::DestroyGroupAction( &m_parent, menu ) );
+ }
+}
+
+void DockInDockManager::fillMoveMenu( QMenu* menu, const std::vector& moveTo )
+{
+ auto widgetsMap = dockWidgetsMap();
+ for ( auto iter = widgetsMap.begin(); iter != widgetsMap.end(); ++iter )
+ {
+ auto subMenu = menu->addMenu( iter.key() );
+
+ for ( auto mgr : moveTo )
+ {
+ // iterate over all possible target managers
+ if ( mgr == this )
+ {
+ // if dock is already in mgr, no reason to move it there
+ }
+ else if ( mgr == dockInAManager( iter.value() ) )
+ {
+ // if target is the group itself, can't move it there, would make no sense
+ }
+ else
+ {
+ subMenu->addAction( new MoveDockWidgetAction( iter.value(), mgr, subMenu ) );
+ }
+ }
+ }
+}
+
+void DockInDockManager::addPerspectiveRec( const QString& name )
+{
+ std::vector managers = allManagers( true, true );
+
+ for ( auto child : managers )
+ child->addPerspective( name );
+}
+
+void DockInDockManager::openPerspectiveRec( const QString& name )
+{
+ std::vector managers = allManagers( true, true );
+
+ for ( auto child : managers )
+ child->openPerspective( name );
+}
+
+QString DockInDockManager::getGroupName()
+{
+ return parent().objectName();
+}
+
+#define CHILD_PREFIX QString("Child-")
+QString DockInDockManager::getPersistGroupName()
+{
+ QString group = "Top";
+ if ( !getGroupName().isEmpty() )
+ group = CHILD_PREFIX + getGroupName();
+ return group;
+}
+
+QString DockInDockManager::getGroupNameFromPersistGroupName( QString persistGroupName )
+{
+ if ( persistGroupName.startsWith( CHILD_PREFIX ) )
+ {
+ persistGroupName = persistGroupName.mid( CHILD_PREFIX.size() );
+ }
+ else
+ {
+ assert( false );
+ }
+ return persistGroupName;
+}
+
+void DockInDockManager::loadPerspectivesRec(QSettings& Settings)
+{
+ std::vector children = allManagers( true, true );
+
+ for ( auto mgr : children )
+ {
+ Settings.beginGroup(mgr->getPersistGroupName());
+ mgr->loadPerspectives( Settings );
+ Settings.endGroup();
+ }
+}
+
+void DockInDockManager::savePerspectivesRec(QSettings& Settings) const
+{
+ std::vector children = allManagers( true, true );
+
+ for ( auto mgr : children )
+ {
+ Settings.beginGroup(mgr->getPersistGroupName());
+ mgr->savePerspectives( Settings );
+ Settings.endGroup();
+ }
+}
+
+void DockInDockManager::removePerspectivesRec()
+{
+ std::vector managers = allManagers( true, true );
+
+ for ( auto child : managers )
+ child->removePerspectives( child->perspectiveNames() );
+}
+
+DockInDockManager* DockInDockManager::dockInAManager( ads::CDockWidget* widget )
+{
+ DockInDockWidget* dockWidget = widget ? dynamic_cast( widget->widget() ) : NULL;
+ return ( dockWidget ) ? dockWidget->getManager() : NULL;
+}
+
+void DockInDockManager::childManagers( std::vector& managers, bool rec ) const
+{
+ auto widgets = getWidgetsInGUIOrder();
+ for ( auto widget : widgets )
+ {
+ DockInDockManager* asMgr = dockInAManager( widget );
+ if ( asMgr )
+ {
+ managers.push_back( asMgr );
+ if ( rec )
+ asMgr->childManagers( managers, rec );
+ }
+ }
+}
+
+std::vector DockInDockManager::allManagers( bool includeThis, bool rec ) const
+{
+ std::vector managers;
+ if ( includeThis )
+ managers.push_back( const_cast(this) );
+ childManagers( managers, rec );
+ return managers;
+}
+
+std::vector> DockInDockManager::allDockWidgets( bool includeThis, bool rec ) const
+{
+ std::vector> widgets;
+ for ( auto mgr : allManagers( includeThis, rec ) )
+ {
+ for ( auto widget : mgr->getWidgetsInGUIOrder() )
+ widgets.push_back( std::make_pair(mgr, widget) );
+ }
+ return widgets;
+}
+
+QMap DockInDockManager::getGroupContents()
+{
+ QMap result;
+ std::vector managers = allManagers( true, true );
+ for ( auto mgr : managers )
+ {
+ result[mgr->getPersistGroupName()] = mgr->dockWidgetsMap().keys();
+ }
+ return result;
+}
+
+ads::CDockAreaWidget* DockInDockManager::getInsertDefaultPos()
+{
+ ads::CDockAreaWidget* defaultPos = NULL;
+ if ( dockAreaCount() != 0 )
+ defaultPos = dockArea(dockAreaCount()-1);
+ return defaultPos;
+}
+
+std::vector DockInDockManager::getWidgetsInGUIOrder() const
+{
+ std::vector result;
+ result.reserve( dockWidgetsMap().size() );
+ for ( int i = 0; i != dockAreaCount(); ++i )
+ {
+ for ( auto widget : dockArea(i)->dockWidgets() )
+ result.push_back( widget );
+ }
+ return result;
+}
+
+/////////////////////////////////////
+// CreateChildDockAction
+/////////////////////////////////////
+CreateChildDockAction::CreateChildDockAction( DockInDockWidget& dockInDock, QMenu* menu ) :
+ QAction("New group...", menu),
+ m_dockInDock( dockInDock )
+{
+ connect( this, SIGNAL(triggered()), this, SLOT(createGroup()) );
+}
+
+void CreateChildDockAction::createGroup()
+{
+ QString name = "";
+ while ( true )
+ {
+ bool ok = false;
+ name = QInputDialog::getText( NULL, this->text(), "Enter group name", QLineEdit::Normal, name, &ok );
+ if ( ok )
+ {
+ QString error = "";
+ if ( m_dockInDock.getTopLevelDockWidget() )
+ error = m_dockInDock.getTopLevelDockWidget()->getGroupNameError( name );
+ else
+ assert( false );
+
+ if ( error.isEmpty() )
+ {
+ ads::CDockAreaWidget* insertPos = NULL;
+ m_dockInDock.createGroup( name, insertPos );
+ break;
+ }
+ else
+ {
+ QMessageBox::critical( NULL, "Error", error );
+ continue;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/////////////////////////////////////
+// DestroyGroupAction
+/////////////////////////////////////
+DestroyGroupAction::DestroyGroupAction( DockInDockWidget* widget, QMenu* menu ) :
+ QAction("Destroy " + widget->getManager()->getGroupName(), menu),
+ m_widget( widget )
+{
+ connect( this, SIGNAL(triggered()), this, SLOT(destroyGroup()) );
+}
+
+void DestroyGroupAction::destroyGroup()
+{
+ m_widget->getTopLevelDockWidget()->destroyGroup( m_widget );
+}
+
+
+/////////////////////////////////////
+// MoveDockWidgetAction
+/////////////////////////////////////
+MoveDockWidgetAction::MoveDockWidgetAction( ads::CDockWidget* widget, DockInDockManager* moveTo, QMenu* menu ) :
+ QAction(menu),
+ m_widget( widget ),
+ m_moveTo( moveTo )
+{
+ if ( moveTo->parent().isTopLevel() )
+ {
+ setText( "To top" );
+ }
+ else
+ {
+ setText( "To " + moveTo->parent().objectName() );
+ }
+ connect( this, SIGNAL(triggered()), this, SLOT(move()) );
+}
+
+void MoveDockWidgetAction::move()
+{
+ move( m_widget, m_moveTo );
+}
+
+void MoveDockWidgetAction::move( ads::CDockWidget* widget, DockInDockManager* moveTo )
+{
+ if ( widget && moveTo )
+ {
+ widget->dockManager()->removeDockWidget( widget );
+ moveTo->addDockWidget(ads::CenterDockWidgetArea, widget, moveTo->getInsertDefaultPos());
+ }
+ else
+ {
+ assert( false );
+ }
+}
diff --git a/QtADS/examples/dockindock/dockindockmanager.h b/QtADS/examples/dockindock/dockindockmanager.h
new file mode 100644
index 0000000..886cb82
--- /dev/null
+++ b/QtADS/examples/dockindock/dockindockmanager.h
@@ -0,0 +1,96 @@
+#pragma once
+
+#include "DockManager.h"
+
+#include
+#include
+
+namespace QtAdsUtl
+{
+
+class DockInDockWidget;
+class DockInDockManager : public ads::CDockManager
+{
+ Q_OBJECT
+
+ typedef ads::CDockManager baseClass;
+
+public:
+ DockInDockManager( DockInDockWidget& parent );
+ ~DockInDockManager() override;
+
+ void fillViewMenu( QMenu* menu, const std::vector& moveTo );
+ void fillMoveMenu( QMenu* menu, const std::vector& moveTo );
+
+ void addPerspectiveRec( const QString& name );
+ void openPerspectiveRec( const QString& name );
+ void removePerspectivesRec();
+ void loadPerspectivesRec(QSettings& Settings);
+ void savePerspectivesRec(QSettings& Settings) const;
+
+ static DockInDockManager* dockInAManager( ads::CDockWidget* widget );
+
+ inline DockInDockWidget& parent() { return m_parent; }
+
+ void childManagers( std::vector& managers, bool rec ) const;
+ std::vector allManagers( bool includeThis, bool rec ) const;
+ std::vector> allDockWidgets( bool includeThis, bool rec ) const;
+
+ QString getGroupName();
+ QString getPersistGroupName();
+ static QString getGroupNameFromPersistGroupName( QString persistGroupName );
+
+ QMap getGroupContents();
+
+ ads::CDockAreaWidget* getInsertDefaultPos();
+
+ std::vector getWidgetsInGUIOrder() const;
+
+private:
+ DockInDockWidget& m_parent;
+};
+
+class CreateChildDockAction : public QAction
+{
+ Q_OBJECT
+public:
+ CreateChildDockAction( DockInDockWidget& dockInDock, QMenu* menu );
+
+public slots:
+ void createGroup();
+
+private:
+ DockInDockWidget& m_dockInDock;
+};
+
+class DestroyGroupAction : public QAction
+{
+ Q_OBJECT
+public:
+ DestroyGroupAction( DockInDockWidget* widget, QMenu* menu );
+
+public slots:
+ void destroyGroup();
+
+private:
+ DockInDockWidget* m_widget;
+};
+
+class MoveDockWidgetAction : public QAction
+{
+ Q_OBJECT
+public:
+ MoveDockWidgetAction( ads::CDockWidget* widget, DockInDockManager* moveTo, QMenu* menu );
+
+ static void move( ads::CDockWidget* widget, DockInDockManager* moveTo );
+
+public slots:
+ void move();
+
+private:
+ ads::CDockWidget* m_widget;
+ DockInDockManager* m_moveTo;
+};
+
+}
+
diff --git a/QtADS/examples/dockindock/dockindockmanager.py b/QtADS/examples/dockindock/dockindockmanager.py
new file mode 100644
index 0000000..224d719
--- /dev/null
+++ b/QtADS/examples/dockindock/dockindockmanager.py
@@ -0,0 +1,214 @@
+from PyQt5.QtWidgets import QAction, QMenu, QInputDialog, QLineEdit
+from PyQt5.QtCore import QSettings
+
+import PyQtAds as QtAds
+
+CHILD_PREFIX = "Child-"
+
+class DockInDockManager(QtAds.CDockManager):
+ def __init__(self, parent: 'DockInDockWidget'):
+ super().__init__()
+ self.__parent = parent
+
+ def parent(self) -> 'DockInDockWidget':
+ return self.__parent
+
+ def fillViewMenu(self, menu: QMenu, move_to: 'dict[DockInDockManager]') -> None:
+ from dockindock import DockInDockWidget # Prevent cyclic import
+
+ widgets_map = self.dockWidgetsMap()
+ for key, value in widgets_map.items():
+ widget = value.widget()
+ action = value.toggleViewAction()
+
+ if isinstance(widget, DockInDockWidget):
+ sub_menu = menu.addMenu(key)
+
+ sub_menu.addAction(action)
+ sub_menu.addSeparator()
+
+ widget.setupMenu(sub_menu, move_to)
+ else:
+ menu.addAction(action)
+
+ if self.parent().canCreateNewGroups():
+ # see how this works, to create it in the right place,
+ # and also to have load perspective work when some groups are missing
+ menu.addSeparator()
+ menu.addAction(CreateChildDockAction(self.__parent, menu))
+
+ if self.parent().getTopLevelDockWidget().getManager() != self:
+ menu.addAction(DestroyGroupAction( self.parent, menu))
+
+ def fillMoveMenu(self, menu: QMenu, move_to: 'list[DockInDockManager]') -> None:
+ widgets_map = self.dockWidgetsMap()
+ for key, value in widgets_map.items():
+ sub_menu = menu.addMenu(key)
+
+ for mgr in move_to:
+ # iterate over all possible target managers
+ if mgr == self:
+ pass # if dock is already in mgr, no reason to move it there
+ elif mgr == DockInDockManager.dockInAManager(value):
+ pass # if target is the group itself, can't move it there, would make no sense
+ else:
+ sub_menu.addAction(MoveDockWidgetAction(value, mgr, sub_menu))
+
+ def addPerspectiveRec(self, name: str) -> None:
+ managers = self.allManagers(True, True)
+
+ for child in managers:
+ child.addPerspective(name)
+
+ def openPerspectiveRec(self, name: str) -> None:
+ managers = self.allManagers(True, True)
+
+ for child in managers:
+ child.openPerspective(name)
+
+ def getGroupName(self) -> str:
+ return self.parent().objectName()
+
+ def getPersistGroupName(self) -> str:
+ group = "Top"
+ if self.getGroupName():
+ group = CHILD_PREFIX + self.getGroupName()
+ return group
+
+ def getGroupNameFromPersistGroupName(self, persist_group_name) -> str:
+ if persist_group_name.startswith(CHILD_PREFIX):
+ persist_group_name = persist_group_name[len(CHILD_PREFIX):]
+ else:
+ assert False
+ return persist_group_name
+
+ def loadPerspectivesRec(self, settings: QSettings) -> None:
+ children = self.allManagers(True, True)
+
+ for mgr in children:
+ settings.beginGroup(mgr.getPersistGroupName())
+ mgr.loadPerspectives(settings)
+ settings.endGroup()
+
+ def savePerspectivesRec(self, settings: QSettings) -> None:
+ children = self.allManagers(True, True)
+
+ for mgr in children:
+ settings.beginGroup(mgr.getPersistGroupName())
+ mgr.savePerspectives(settings)
+ settings.endGroup()
+
+ def removePerspectivesRec(self, settings: QSettings) -> None:
+ children = self.allManagers(True, True)
+
+ for mgr in children:
+ child.removePerspectives(child.perspectiveNames())
+
+ @staticmethod
+ def dockInAManager(widget) -> 'DockInDockManager':
+ from dockindock import DockInDockWidget # Prevent cyclic import
+
+ dock_widget = widget.widget() if widget else None
+ return dock_widget.getManager() if isinstance(dock_widget, DockInDockWidget) else None
+
+ def childManagers(self, managers: 'list[DockInDockManager]', rec: bool) -> None:
+ widgets = self.getWidgetsInGUIOrder()
+ for widget in widgets:
+ as_mgr = DockInDockManager.dockInAManager(widget)
+ if as_mgr:
+ managers.append(as_mgr)
+ if rec:
+ as_mgr.childManagers(managers, rec)
+
+ def allManagers(self, include_self: bool, rec: bool) -> 'list[DockInDockManager]':
+ managers = []
+ if include_self:
+ managers.append(self)
+ self.childManagers(managers, rec)
+ return managers
+
+ def allDockWidgets(self, include_self: bool, rec: bool) -> 'list[tuple[DockInDockManager, QtAds.CDockWidget]]':
+ widgets = []
+ for mgr in self.allManagers(include_self, rec):
+ for widget in mgr.getWidgetsInGUIOrder():
+ widgets.append((mgr, widget))
+ return widgets
+
+ def getGroupContents(self) -> 'dict[str, list[str]]':
+ result = {}
+ managers = self.allManagers(True, True)
+ for mgr in managers:
+ result[mgr.getPersistGroupName()] = mgr.dockWidgetsMap().keys()
+ return result
+
+ def getInsertDefaultPos(self) -> QtAds.CDockAreaWidget:
+ default_pos = None
+ if self.dockAreaCount() != 0:
+ default_pos = self.dockArea(self.dockAreaCount()-1)
+ return default_pos
+
+ def getWidgetsInGUIOrder(self) -> 'list[QtAds.CDockWidget]':
+ result = []
+ for i in range(self.dockAreaCount()):
+ for widget in self.dockArea(i).dockWidgets():
+ result.append(widget)
+ return result
+
+
+class CreateChildDockAction(QAction):
+ def __init__(self, dock_in_dock: 'DockInDockWidget', menu: QMenu):
+ super().__init__("New group...", menu)
+ self.__dock_in_dock = dock_in_dock
+ self.triggered.connect(self.createGroup)
+
+ def createGroup(self) -> None:
+ name = ""
+ while True:
+ name, ok = QInputDialog.getText(None, self.text(), "Enter group name", QLineEdit.Normal, name)
+ if ok:
+ error = ""
+ if self.__dock_in_dock.getTopLevelDockWidget():
+ error = self.__dock_in_dock.getTopLevelDockWidget().getGroupNameError(name)
+ else:
+ assert False
+
+ if not error:
+ self.__dock_in_dock.createGroup(name, None)
+ break
+ else:
+ QMessageBox.critical(None, "Error", error)
+ continue
+ else:
+ break
+
+class DestroyGroupAction(QAction):
+ def __init__(self, widget: 'DockInDockWidget', menu: QMenu):
+ super().__init__("Destroy" + widget.getManager().getGroupName(), menu)
+ self.__widget = widget
+ self.triggered.connect(self.destroyGroup)
+
+ def destroyGroup(self) -> None:
+ self.__widget.getTopLevelDockWidget().destroyGroup(self.__widget)
+
+
+class MoveDockWidgetAction(QAction):
+ def __init__(self, widget: 'DockInDockWidget', move_to: DockInDockManager, menu: QMenu):
+ super().__init__(menu)
+ self.__widget = widget
+ self.__move_to = move_to
+
+ if move_to.parent().isTopLevel():
+ self.setText("To top")
+ else:
+ self.setText(f"To {move_to.parent().objectName()}")
+ self.triggered.connect(self._move)
+
+ def _move(self) -> None:
+ self.move(self.__widget, self.__move_to)
+
+ def move(self, widget: QtAds.CDockWidget, move_to: QtAds.CDockManager) -> None:
+ if widget and move_to:
+ widget.dockManager().removeDockWidget(widget)
+ move_to.addDockWidget(QtAds.CenterDockWidgetArea, widget, move_to.getInsertDefaultPos())
+ else:
+ assert False
diff --git a/QtADS/examples/dockindock/main.cpp b/QtADS/examples/dockindock/main.cpp
new file mode 100644
index 0000000..9ae3539
--- /dev/null
+++ b/QtADS/examples/dockindock/main.cpp
@@ -0,0 +1,11 @@
+#include
+#include "mainframe.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/QtADS/examples/dockindock/main.py b/QtADS/examples/dockindock/main.py
new file mode 100644
index 0000000..be32b08
--- /dev/null
+++ b/QtADS/examples/dockindock/main.py
@@ -0,0 +1,72 @@
+import sys
+import os
+import atexit
+
+from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
+from PyQt5.QtCore import Qt
+import PyQtAds as QtAds
+
+from perspectives import PerspectivesManager
+from dockindock import DockInDockWidget
+
+class MainWindow(QMainWindow):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.perspectives_manager = PerspectivesManager("persist")
+ self.resize(400, 400)
+ self.dock_manager = DockInDockWidget(self, self.perspectives_manager, can_create_new_groups=True)
+ self.setCentralWidget(self.dock_manager)
+ self.dock_manager.attachViewMenu(self.menuBar().addMenu("View"))
+
+ previous_dock_widget = None
+ for i in range(3):
+ l = QLabel()
+ l.setWordWrap(True)
+ l.setAlignment(Qt.AlignTop | Qt.AlignLeft)
+ l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
+
+ previous_dock_widget = self.dock_manager.addTabWidget(l, f"Top label {i}", previous_dock_widget)
+
+ last_top_level_dock = previous_dock_widget
+
+ for j in range(2):
+ group_manager, _ = self.dock_manager.createGroup(f"Group {j}", last_top_level_dock)
+
+ previous_dock_widget = None
+
+ for i in range(3):
+ # Create example content label - this can be any application specific widget
+ l = QLabel()
+ l.setWordWrap(True)
+ l.setAlignment(Qt.AlignTop | Qt.AlignLeft)
+ l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
+
+ previous_dock_widget = group_manager.addTabWidget(l, f"ZInner {j}/{i}", previous_dock_widget)
+
+ # create sub-group
+ sub_group, _ = group_manager.createGroup(f"SubGroup {j}", previous_dock_widget)
+ previous_dock_widget = None
+ for i in range(3):
+ # Create example content label - this can be any application specific widget
+ l = QLabel()
+ l.setWordWrap(True)
+ l.setAlignment(Qt.AlignTop | Qt.AlignLeft)
+ l.setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ")
+
+ previous_dock_widget = sub_group.addTabWidget(l, f"SubInner {j}/{i}", previous_dock_widget)
+
+ self.perspectives_manager.loadPerspectives()
+
+ atexit.register(self.cleanup)
+
+ def cleanup(self):
+ self.perspectives_manager.savePerspectives()
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+
+ w = MainWindow()
+ w.show()
+ app.exec_()
diff --git a/QtADS/examples/dockindock/mainframe.cpp b/QtADS/examples/dockindock/mainframe.cpp
new file mode 100644
index 0000000..3e8f26f
--- /dev/null
+++ b/QtADS/examples/dockindock/mainframe.cpp
@@ -0,0 +1,76 @@
+#include "mainframe.h"
+
+#include "dockindock.h"
+#include "perspectives.h"
+
+#include
+#include
+#include
+#include
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ m_perspectivesManager( new QtAdsUtl::PerspectivesManager( "persist" ) )
+{
+ resize( 400, 400 );
+
+ setCentralWidget( m_dockManager = new QtAdsUtl::DockInDockWidget(this,true,m_perspectivesManager.get()) );
+
+ m_dockManager->attachViewMenu( menuBar()->addMenu( "View" ) );
+
+ ads::CDockAreaWidget* previousDockWidget = NULL;
+ for ( int i = 0; i != 3; ++i )
+ {
+ // Create example content label - this can be any application specific
+ // widget
+ QLabel* l = new QLabel();
+ l->setWordWrap(true);
+ l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
+
+ previousDockWidget = m_dockManager->addTabWidget( l, "Top label " + QString::number(i), previousDockWidget );
+ }
+
+ auto lastTopLevelDock = previousDockWidget;
+
+ for ( int j = 0; j != 2; ++j )
+ {
+ QtAdsUtl::DockInDockWidget* groupManager = m_dockManager->createGroup( "Group " + QString::number(j), lastTopLevelDock );
+
+ previousDockWidget = NULL;
+ for ( int i = 0; i != 3; ++i )
+ {
+ // Create example content label - this can be any application specific
+ // widget
+ QLabel* l = new QLabel();
+ l->setWordWrap(true);
+ l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
+
+ previousDockWidget = groupManager->addTabWidget( l, "ZInner " + QString::number(j) + "/" + QString::number(i), previousDockWidget );
+ }
+
+ // create sub-group
+ auto subGroup = groupManager->createGroup( "SubGroup " + QString::number(j), previousDockWidget );
+ previousDockWidget = NULL;
+ for ( int i = 0; i != 3; ++i )
+ {
+ // Create example content label - this can be any application specific
+ // widget
+ QLabel* l = new QLabel();
+ l->setWordWrap(true);
+ l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
+
+ previousDockWidget = subGroup->addTabWidget( l, "SubInner " + QString::number(j) + "/" + QString::number(i), previousDockWidget );
+ }
+ }
+
+ m_perspectivesManager->loadPerspectives();
+}
+
+MainWindow::~MainWindow()
+{
+ m_perspectivesManager->savePerspectives();
+}
+
diff --git a/QtADS/examples/dockindock/mainframe.h b/QtADS/examples/dockindock/mainframe.h
new file mode 100644
index 0000000..0305b36
--- /dev/null
+++ b/QtADS/examples/dockindock/mainframe.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+namespace QtAdsUtl
+{
+ class DockInDockWidget;
+ class PerspectivesManager;
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+ QtAdsUtl::DockInDockWidget* m_dockManager;
+ std::unique_ptr m_perspectivesManager;
+};
+
+
+
+
+
+
diff --git a/QtADS/examples/dockindock/perspectiveactions.cpp b/QtADS/examples/dockindock/perspectiveactions.cpp
new file mode 100644
index 0000000..1e088c8
--- /dev/null
+++ b/QtADS/examples/dockindock/perspectiveactions.cpp
@@ -0,0 +1,39 @@
+#include "perspectiveactions.h"
+#include "dockindock.h"
+#include "perspectives.h"
+
+#include
+
+using namespace QtAdsUtl;
+
+//////////////////////////////
+// LoadPerspectiveAction
+//////////////////////////////
+LoadPerspectiveAction::LoadPerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager ) :
+ QAction( name, parent ),
+ name( name ),
+ dockManager( dockManager )
+{
+ connect( this, SIGNAL(triggered()), this, SLOT(load()) );
+}
+
+void LoadPerspectiveAction::load()
+{
+ dockManager.getPerspectivesManager()->openPerspective( name, dockManager );
+}
+
+//////////////////////////////
+// RemovePerspectiveAction
+//////////////////////////////
+RemovePerspectiveAction::RemovePerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager ) :
+ QAction( name, parent ),
+ name( name ),
+ dockManager( dockManager )
+{
+ connect( this, SIGNAL(triggered()), this, SLOT(remove()) );
+}
+
+void RemovePerspectiveAction::remove()
+{
+ dockManager.getPerspectivesManager()->removePerspective( name );
+}
diff --git a/QtADS/examples/dockindock/perspectiveactions.h b/QtADS/examples/dockindock/perspectiveactions.h
new file mode 100644
index 0000000..1614eab
--- /dev/null
+++ b/QtADS/examples/dockindock/perspectiveactions.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include
+
+namespace QtAdsUtl
+{
+
+class DockInDockWidget;
+class LoadPerspectiveAction : public QAction
+{
+ Q_OBJECT
+public:
+ LoadPerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager );
+
+public slots:
+ void load();
+
+private:
+ QString name;
+ QtAdsUtl::DockInDockWidget& dockManager;
+};
+
+class RemovePerspectiveAction : public QAction
+{
+ Q_OBJECT
+public:
+ RemovePerspectiveAction( QMenu* parent, const QString& name, QtAdsUtl::DockInDockWidget& dockManager );
+
+public slots:
+ void remove();
+
+private:
+ QString name;
+ QtAdsUtl::DockInDockWidget& dockManager;
+};
+
+}
+
diff --git a/QtADS/examples/dockindock/perspectiveactions.py b/QtADS/examples/dockindock/perspectiveactions.py
new file mode 100644
index 0000000..9328855
--- /dev/null
+++ b/QtADS/examples/dockindock/perspectiveactions.py
@@ -0,0 +1,25 @@
+from PyQt5.QtWidgets import QAction, QMenu
+
+
+class LoadPerspectiveAction(QAction):
+ def __init__(self, parent: QMenu, name: str, dock_manager: 'DockInDockWidget'):
+ super().__init__(name, parent)
+ self.name = name
+ self.dock_manager = dock_manager
+
+ self.triggered.connect(self.load)
+
+ def load(self):
+ self.dock_manager.getPerspectivesManager().openPerspective(self.name, self.dock_manager)
+
+
+class RemovePerspectiveAction(QAction):
+ def __init__(self, parent: QMenu, name: str, dock_manager: 'DockInDockWidget'):
+ super().__init__(name, parent)
+ self.name = name
+ self.dock_manager = dock_manager
+
+ self.triggered.connect(self.remove)
+
+ def remove(self):
+ self.dock_manager.getPerspectivesManager().removePerspective(self.name)
\ No newline at end of file
diff --git a/QtADS/examples/dockindock/perspectives.cpp b/QtADS/examples/dockindock/perspectives.cpp
new file mode 100644
index 0000000..e788c22
--- /dev/null
+++ b/QtADS/examples/dockindock/perspectives.cpp
@@ -0,0 +1,280 @@
+#include "perspectives.h"
+#include "dockindock.h"
+#include "dockindockmanager.h"
+
+#include
+#include
+#include
+
+#include
+
+#define GROUP_PREFIX QString("Group")
+
+using namespace QtAdsUtl;
+
+PerspectivesManager::PerspectivesManager( const QString& perspectivesFolder ) :
+ m_perspectivesFolder( perspectivesFolder )
+{
+
+}
+
+PerspectivesManager::~PerspectivesManager()
+{
+ // remove temp files:
+ for ( auto perspective : m_perspectives )
+ {
+ QString fileName = perspective.settings->fileName();
+ perspective.settings.reset();
+ QFile::remove(fileName);
+ }
+}
+
+
+QStringList PerspectivesManager::perspectiveNames() const
+{
+ return m_perspectives.keys();
+}
+
+void PerspectivesManager::addPerspective( const QString& name, DockInDockWidget& widget )
+{
+ if ( !m_perspectivesFolder.isEmpty() )
+ {
+ m_perspectives[name].settings = getSettingsObject( getSettingsFileName( name, true ) );
+ m_perspectives[name].groups = widget.getManager()->getGroupContents();
+
+ // save perspective internally
+ widget.getManager()->addPerspectiveRec( name );
+ // store it in QSettings object
+ widget.getManager()->savePerspectivesRec( *(m_perspectives[name].settings) );
+ // remove internal perspectives
+ widget.getManager()->removePerspectives( widget.getManager()->perspectiveNames() );
+ }
+ else
+ {
+ assert( false );
+ }
+
+ emit perspectivesListChanged();
+}
+
+
+ads::CDockWidget* findWidget( QString name, const std::vector& managers )
+{
+ for ( auto mgr : managers )
+ {
+ auto widget = mgr->findDockWidget(name);
+ if ( widget )
+ return widget;
+ }
+ return NULL;
+}
+
+void PerspectivesManager::openPerspective( const QString& name, DockInDockWidget& widget )
+{
+ assert( widget.getTopLevelDockWidget() == &widget );
+
+ if ( !m_perspectivesFolder.isEmpty() )
+ {
+ if ( m_perspectives.contains( name ) )
+ {
+ emit openingPerspective();
+
+ if ( widget.canCreateNewGroups() )
+ {
+ auto curGroups = widget.getManager()->allManagers(true,true);
+ for ( auto group : m_perspectives[name].groups.keys() )
+ {
+ bool found = false;
+ for ( auto curgroup : curGroups )
+ {
+ if ( curgroup->getPersistGroupName() == group )
+ {
+ found = true;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ group = DockInDockManager::getGroupNameFromPersistGroupName( group );
+
+ // restore group in file but not in GUI yet
+ ads::CDockAreaWidget* insertPos = NULL;
+ widget.createGroup( group, insertPos );
+ }
+ }
+
+ curGroups = widget.getManager()->allManagers(false,true);
+ for ( auto curgroup : curGroups )
+ {
+ if ( !m_perspectives[name].groups.keys().contains( curgroup->getPersistGroupName() ) )
+ {
+ widget.destroyGroup( &curgroup->parent() );
+ }
+ }
+ }
+
+ auto managers = widget.getManager()->allManagers(true,true);
+ for ( auto group : m_perspectives[name].groups.keys() )
+ {
+ for ( auto mgr : managers )
+ {
+ if ( mgr->getPersistGroupName() == group )
+ {
+ for ( QString widgetName : m_perspectives[name].groups[group] )
+ {
+ ads::CDockWidget* widget = findWidget( widgetName, { mgr } );
+ if ( widget )
+ {
+ // OK, widget is already in the good manager!
+ }
+ else
+ {
+ widget = findWidget( widgetName, managers );
+ if ( widget )
+ {
+ // move dock widget in the same group as it used to be when perspective was saved
+ // this guarantee load/open perspectives will work smartly
+ MoveDockWidgetAction::move( widget, mgr );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // internally load perspectives from QSettings
+ widget.getManager()->loadPerspectivesRec( *(m_perspectives[name].settings) );
+ // load perspective (update GUI)
+ widget.getManager()->openPerspectiveRec( name );
+ // remove internal perspectives
+ widget.getManager()->removePerspectives( widget.getManager()->perspectiveNames() );
+
+ emit openedPerspective();
+ }
+ }
+ else
+ {
+ assert( false );
+ }
+}
+
+void PerspectivesManager::removePerspectives()
+{
+ m_perspectives.clear();
+ emit perspectivesListChanged();
+}
+
+void PerspectivesManager::removePerspective( const QString& name )
+{
+ m_perspectives.remove( name );
+ emit perspectivesListChanged();
+}
+
+QString PerspectivesManager::getSettingsFileName( const QString& perspective, bool temp ) const
+{
+ auto name = ( perspective.isEmpty() ) ? "perspectives.ini" : "perspective_" + perspective + (temp?".tmp":".ini");
+
+ return m_perspectivesFolder + "/" + name;
+}
+
+std::shared_ptr PerspectivesManager::getSettingsObject( const QString& filePath ) const
+{
+ return std::make_shared(filePath, QSettings::IniFormat);
+}
+
+void PerspectivesManager::loadPerspectives()
+{
+ if ( !m_perspectivesFolder.isEmpty() )
+ {
+ QDir().mkpath( m_perspectivesFolder );
+
+ m_perspectives.clear();
+
+ auto mainSettings = getSettingsObject( getSettingsFileName( "", false ) );
+ std::string debug = mainSettings->fileName().toStdString();
+
+ int Size = mainSettings->beginReadArray("Perspectives");
+
+ for (int i = 0; i < Size; ++i)
+ {
+ mainSettings->setArrayIndex(i);
+ QString perspective = mainSettings->value("Name").toString();
+
+ if ( !perspective.isEmpty() )
+ {
+ // load perspective file:
+ auto toLoad = getSettingsFileName( perspective, false );
+ auto loaded = getSettingsFileName( perspective, true );
+
+#ifdef _DEBUG
+ std::string debug1 = loaded.toStdString();
+ std::string debug2 = toLoad.toStdString();
+#endif
+
+ QFile::remove( loaded );
+ if ( !QFile::copy( toLoad, loaded ) )
+ assert( false );
+
+ m_perspectives[perspective].settings = getSettingsObject( loaded );
+
+ // load group info:
+ mainSettings->beginGroup(GROUP_PREFIX);
+ for (const auto& key : mainSettings->allKeys())
+ {
+ m_perspectives[perspective].groups[key] = mainSettings->value( key ).toStringList();
+ }
+ mainSettings->endGroup();
+ }
+ else
+ {
+ assert( false );
+ }
+ }
+
+ mainSettings->endArray();
+ }
+
+ emit perspectivesListChanged();
+}
+
+void PerspectivesManager::savePerspectives() const
+{
+ if ( !m_perspectivesFolder.isEmpty() )
+ {
+ auto mainSettings = getSettingsObject( getSettingsFileName( "", false ) );
+
+ // Save list of perspective and group organization
+ mainSettings->beginWriteArray("Perspectives", m_perspectives.size());
+ int i = 0;
+ for ( auto perspective : m_perspectives.keys() )
+ {
+ mainSettings->setArrayIndex(i);
+ mainSettings->setValue("Name", perspective);
+ mainSettings->beginGroup(GROUP_PREFIX);
+ for ( auto group : m_perspectives[perspective].groups.keys() )
+ {
+ mainSettings->setValue( group, m_perspectives[perspective].groups[group] );
+ }
+ mainSettings->endGroup();
+ ++i;
+ }
+ mainSettings->endArray();
+
+ // Save perspectives themselves
+ for ( auto perspectiveName : m_perspectives.keys() )
+ {
+ auto toSave = getSettingsFileName( perspectiveName, false );
+ QSettings& settings = *(m_perspectives[perspectiveName].settings);
+ settings.sync();
+
+#ifdef _DEBUG
+ std::string debug1 = settings.fileName().toStdString();
+ std::string debug2 = toSave.toStdString();
+#endif
+
+ QFile::remove( toSave );
+ if ( !QFile::copy( settings.fileName(), toSave ) )
+ assert( false );
+ }
+ }
+}
diff --git a/QtADS/examples/dockindock/perspectives.h b/QtADS/examples/dockindock/perspectives.h
new file mode 100644
index 0000000..42592fb
--- /dev/null
+++ b/QtADS/examples/dockindock/perspectives.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include
+
+class QMenu;
+class QSettings;
+
+namespace QtAdsUtl
+{
+
+class DockInDockWidget;
+class PerspectivesManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ PerspectivesManager( const QString& perspectivesFolder );
+ virtual ~PerspectivesManager();
+
+ QStringList perspectiveNames() const;
+
+ void addPerspective( const QString& name, DockInDockWidget& widget );
+ void openPerspective( const QString& name, DockInDockWidget& widget );
+ void removePerspectives();
+ void removePerspective( const QString& name );
+
+ void loadPerspectives();
+ void savePerspectives() const;
+
+signals:
+ void perspectivesListChanged();
+ void openingPerspective();
+ void openedPerspective();
+
+private:
+
+ // Partially bypass ADS perspective management, store list here
+ // and then ADS will only have one perspective loaded
+ // this is because all docking widgets must exist when a perspective is loaded
+ // we will guarantee that!
+ class PerspectiveInfo
+ {
+ public:
+ std::shared_ptr settings;
+ QMap groups;
+ };
+ QMap m_perspectives;
+
+ QString m_perspectivesFolder;
+ QString getSettingsFileName( const QString& perspective, bool temp ) const;
+ std::shared_ptr getSettingsObject( const QString& filePath ) const;
+};
+
+}
+
diff --git a/QtADS/examples/dockindock/perspectives.py b/QtADS/examples/dockindock/perspectives.py
new file mode 100644
index 0000000..9b6c00d
--- /dev/null
+++ b/QtADS/examples/dockindock/perspectives.py
@@ -0,0 +1,203 @@
+import os
+import tempfile
+import shutil
+import atexit
+
+from PyQt5.QtCore import pyqtSignal, QSettings, QObject
+import PyQtAds as QtAds
+
+from dockindockmanager import DockInDockManager
+from dockindock import DockInDockWidget
+
+GROUP_PREFIX = "Group"
+
+def findWidget(name, managers: 'list[DockInDockManager]') -> QtAds.CDockWidget:
+ for mgr in managers:
+ widget = mgr.findDockWidget(name)
+ if widget:
+ return widget
+
+
+class PerspectiveInfo:
+ # Partially bypass ADS perspective management, store list here
+ # and then ADS will only have one perspective loaded
+ # this is because all docking widgets must exist when a perspective is loaded
+ # we will guarantee that!
+
+ settings = QSettings()
+ groups: 'dict[str, list[str]]' = {}
+
+
+class PerspectivesManager(QObject):
+ perspectivesListChanged = pyqtSignal()
+ openingPerspective = pyqtSignal()
+ openedPerspective = pyqtSignal()
+
+ def __init__(self, perspectives_folder):
+ super().__init__()
+ self.__perspectives_folder = perspectives_folder
+ self.__perspectives = {}
+ atexit.register(self.cleanup)
+
+ def cleanup(self):
+ for perspective in self.__perspectives.values():
+ filename = perspective.settings.fileName()
+ try:
+ os.remove(filename)
+ except FileNotFoundError:
+ pass
+
+ def perspectiveNames(self) -> 'list[str]':
+ return self.__perspectives.keys()
+
+ def addPerspective(self, name: str, widget: DockInDockWidget) -> None:
+ if self.__perspectives_folder:
+ self.__perspectives[name] = perspective = PerspectiveInfo()
+ perspective.settings = self.getSettingsObject(self.getSettingsFileName(name, True))
+ perspective.groups = widget.getManager().getGroupContents()
+
+ # save perspective internally
+ widget.getManager().addPerspectiveRec(name)
+ # store it in QSettings object
+ widget.getManager().savePerspectivesRec(perspective.settings)
+ # remove internal perspectives
+ widget.getManager().removePerspectives(widget.getManager().perspectiveNames())
+
+ self.perspectivesListChanged.emit()
+
+ def openPerspective(name: str, widget: DockInDockWidget) -> None:
+ assert widget.getTopLevelDockWidget() == widget
+
+ if self.__perspectives_folder:
+ if name in self.__perspectives:
+ self.openingPerspective.emit()
+
+ if widget.canCreateNewGroups():
+ cur_groups = widget.getManager().allManagers(True, True)
+ for group in self.__perspectives[name].groups.keys():
+ found = False
+ for curgroup in cur_groups:
+ if curgroup.getPerspectiveGroupName() == group:
+ found = True
+ break
+ if not found:
+ group = DockInDockManager.getGroupNameFromPersistGroupName(group)
+
+ # restore group in file but not in GUI yet
+ widget.createGroup(group, None)
+
+ cur_groups = widget.getManager().allManagers(False, True)
+ for curgroup in cur_groups:
+ if curgroup.getPersistGroupName() not in self.__perspectives[name].groups.keys():
+ widget.destroyGroup(curgroup.parent())
+
+ managers = widget.getManager().allManagers(True, True)
+ for group in self.__perspectives[name].groups().keys():
+ for mgr in managers:
+ if mgr.getPersistGroupName() == group:
+ for widget_name in self.__perspectives[name].groups[group]:
+ widget = findWidget(widget_name, [mgr])
+ if widget:
+ pass # OK, widget is already in the good manager!
+ else:
+ widget = findWidget(widget_name, managers)
+ if widget:
+ # move dock widget in the same group as it used to be when perspective was saved
+ # this guarantee load/open perspectives will work smartly
+ MoveDockWidgetAction.move(widget, mgr)
+
+ # internally load perspectives from QSettings
+ widget.getManager().loadPerspectivesRec(self.__perspectives[name].settings)
+ # load perspective (update GUI)
+ widget.getManager().openPerspectiveRec(name)
+ # remove internal perspectives
+ widget.getManager().removePerspectives(widget.getManager().perspectiveNames())
+
+ self.openedPerspective().emit()
+ else:
+ assert False
+
+ def removePerspectives(self) -> None:
+ self.__perspectives.clear()
+ self.perspectivesListChanged.emit()
+
+ def removePerspective(self, name: str) -> None:
+ del self.__perspectives[name]
+ self.perspectivesListChanged.emit()
+
+ def getSettingsFileName(self, perspective: str, temp: bool) -> str:
+ name = "perspectives.ini" if not perspective else f"perspectives_{perspective + '.tmp' if temp else perspective + '.ini'}"
+
+ return os.path.join(self.__perspectives_folder, name)
+
+ def getSettingsObject(self, file_path: str) -> QSettings:
+ return QSettings(file_path, QSettings.IniFormat)
+
+ def loadPerspectives(self) -> None:
+ if self.__perspectives_folder:
+ tempfile.mktemp(dir=self.__perspectives_folder)
+
+ self.__perspectives.clear()
+
+ main_settings = self.getSettingsObject(self.getSettingsFileName("", False))
+ debug = main_settings.fileName()
+
+ size = main_settings.beginReadArray("Perspectives")
+
+ for i in range(0, size):
+ main_settings.setArrayIndex(i)
+ perspective = main_settings.value("Name")
+
+ if perspective:
+ to_load = self.getSettingsFileName(perspective, False)
+ loaded = self.getSettingsFileName(perspective, True)
+
+ try:
+ os.remove(loaded)
+ except FileNotFoundError:
+ pass
+ if not shutil.copy(to_load, loaded):
+ assert False
+
+ self.__perspectives[perspective] = PerspectiveInfo()
+ self.__perspectives[perspective].settings = self.getSettingsObject(loaded)
+
+ # load group info:
+ main_settings.beginGroup(GROUP_PREFIX)
+ for key in main_settings.allKeys():
+ self.__perspectives[perspective].groups[key] = main_settings.value(key)
+ main_settings.endGroup()
+ else:
+ assert False
+
+ main_settings.endArray()
+
+ self.perspectivesListChanged.emit()
+
+ def savePerspectives(self) -> None:
+ if self.__perspectives_folder:
+ main_settings = self.getSettingsObject(self.getSettingsFileName("", False))
+
+ # Save list of perspective and group organization
+ main_settings.beginWriteArray("Perspectives", len(self.__perspectives))
+ for i, perspective in enumerate(self.__perspectives.keys()):
+ main_settings.setArrayIndex(i)
+ main_settings.setValue("Name", perspective)
+ main_settings.beginGroup(GROUP_PREFIX)
+ for group in self.__perspectives[perspective].groups.keys():
+ main_settings.setValue(group, list(self.__perspectives[perspective].groups[group]))
+ main_settings.endGroup()
+ main_settings.endArray()
+
+ # Save perspectives themselves
+ for perspective_name in self.__perspectives.keys():
+ to_save = self.getSettingsFileName(perspective_name, False)
+ settings = self.__perspectives[perspective_name].settings
+ settings.sync()
+
+ try:
+ os.remove(to_save)
+ except FileNotFoundError:
+ pass
+ if not shutil.copy(settings.fileName(), to_save):
+ assert False
diff --git a/QtADS/examples/emptydockarea/CMakeLists.txt b/QtADS/examples/emptydockarea/CMakeLists.txt
new file mode 100644
index 0000000..c9b02f2
--- /dev/null
+++ b/QtADS/examples/emptydockarea/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_centralwidget VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(EmptyDockAreaExample WIN32
+ main.cpp
+ mainwindow.cpp
+ mainwindow.ui
+)
+target_include_directories(EmptyDockAreaExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(EmptyDockAreaExample PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(EmptyDockAreaExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(EmptyDockAreaExample PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Empty Dock Area Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/emptydockarea/emptydockarea.pro b/QtADS/examples/emptydockarea/emptydockarea.pro
new file mode 100644
index 0000000..b45979b
--- /dev/null
+++ b/QtADS/examples/emptydockarea/emptydockarea.pro
@@ -0,0 +1,34 @@
+ADS_OUT_ROOT = $${OUT_PWD}/../..
+
+QT += core gui widgets
+
+TARGET = EmptyDockareaExample
+DESTDIR = $${ADS_OUT_ROOT}/lib
+TEMPLATE = app
+CONFIG += c++14
+CONFIG += debug_and_release
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp
+
+HEADERS += \
+ mainwindow.h
+
+FORMS += \
+ mainwindow.ui
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+include(../../ads.pri)
+INCLUDEPATH += ../../src
+DEPENDPATH += ../../src
+
diff --git a/QtADS/examples/emptydockarea/main.cpp b/QtADS/examples/emptydockarea/main.cpp
new file mode 100644
index 0000000..fa4c4fd
--- /dev/null
+++ b/QtADS/examples/emptydockarea/main.cpp
@@ -0,0 +1,10 @@
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ CMainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/QtADS/examples/emptydockarea/main.py b/QtADS/examples/emptydockarea/main.py
new file mode 100644
index 0000000..475cc2e
--- /dev/null
+++ b/QtADS/examples/emptydockarea/main.py
@@ -0,0 +1,108 @@
+import sys
+import os
+
+from PyQt5 import uic
+from PyQt5.QtCore import Qt, QSignalBlocker
+from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QComboBox, QTableWidget,
+ QAction, QWidgetAction, QSizePolicy, QInputDialog)
+from PyQt5.QtGui import QCloseEvent
+import PyQtAds as QtAds
+
+
+UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
+MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
+
+
+class CMainWindow(MainWindowUI, MainWindowBase):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.setupUi(self)
+
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.OpaqueSplitterResize, True)
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.XmlCompressionEnabled, False)
+ QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True)
+ self.dock_manager = QtAds.CDockManager(self)
+
+ # Set central widget
+ label = QLabel()
+ label.setText("This is a DockArea which is always visible, even if it does not contain any DockWidgets.")
+ label.setAlignment(Qt.AlignCenter)
+ central_dock_widget = QtAds.CDockWidget("CentralWidget")
+ central_dock_widget.setWidget(label)
+ central_dock_widget.setFeature(QtAds.CDockWidget.NoTab, True)
+ central_dock_area = self.dock_manager.setCentralWidget(central_dock_widget)
+
+ # create other dock widgets
+ table = QTableWidget()
+ table.setColumnCount(3)
+ table.setRowCount(10)
+ table_dock_widget = QtAds.CDockWidget("Table 1")
+ table_dock_widget.setWidget(table)
+ table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ table_dock_widget.resize(250, 150)
+ table_dock_widget.setMinimumSize(200,150)
+ self.dock_manager.addDockWidgetTabToArea(table_dock_widget, central_dock_area)
+ table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, table_dock_widget)
+ self.menuView.addAction(table_dock_widget.toggleViewAction())
+
+ table = QTableWidget()
+ table.setColumnCount(5)
+ table.setRowCount(1020)
+ table_dock_widget = QtAds.CDockWidget("Table 2")
+ table_dock_widget.setWidget(table)
+ table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ table_dock_widget.resize(250, 150)
+ table_dock_widget.setMinimumSize(200,150)
+ self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, table_area)
+ self.menuView.addAction(table_dock_widget.toggleViewAction())
+
+ properties_table = QTableWidget()
+ properties_table.setColumnCount(3)
+ properties_table.setRowCount(10)
+ properties_dock_widget = QtAds.CDockWidget("Properties")
+ properties_dock_widget.setWidget(properties_table)
+ properties_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
+ properties_dock_widget.resize(250, 150)
+ properties_dock_widget.setMinimumSize(200,150)
+ self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, properties_dock_widget, central_dock_area)
+ self.menuView.addAction(properties_dock_widget.toggleViewAction())
+
+ self.createPerspectiveUi()
+
+ def createPerspectiveUi(self):
+ save_perspective_action = QAction("Create Perspective", self)
+ save_perspective_action.triggered.connect(self.savePerspective)
+ perspective_list_action = QWidgetAction(self)
+ self.perspective_combo_box = QComboBox(self)
+ self.perspective_combo_box.setSizeAdjustPolicy(QComboBox.AdjustToContents)
+ self.perspective_combo_box.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+ self.perspective_combo_box.activated[str].connect(self.dock_manager.openPerspective)
+ perspective_list_action.setDefaultWidget(self.perspective_combo_box)
+ self.toolBar.addSeparator()
+ self.toolBar.addAction(perspective_list_action)
+ self.toolBar.addAction(save_perspective_action)
+
+ def savePerspective(self):
+ perspective_name, ok = QInputDialog.getText(self, "Save Perspective", "Enter unique name:")
+ if not perspective_name or not ok:
+ return
+
+ self.dock_manager.addPerspective(perspective_name)
+ blocker = QSignalBlocker(self.perspective_combo_box)
+ self.perspective_combo_box.clear()
+ self.perspective_combo_box.addItems(self.dock_manager.perspectiveNames())
+ self.perspective_combo_box.setCurrentText(perspective_name)
+
+ def closeEvent(self, event: QCloseEvent):
+ # Delete dock manager here to delete all floating widgets. This ensures
+ # that all top level windows of the dock manager are properly closed
+ self.dock_manager.deleteLater()
+ super().closeEvent(event)
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+
+ w = CMainWindow()
+ w.show()
+ app.exec_()
diff --git a/QtADS/examples/emptydockarea/mainwindow.cpp b/QtADS/examples/emptydockarea/mainwindow.cpp
new file mode 100644
index 0000000..2dbe99c
--- /dev/null
+++ b/QtADS/examples/emptydockarea/mainwindow.cpp
@@ -0,0 +1,135 @@
+#include "mainwindow.h"
+
+#include "ui_mainwindow.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "DockAreaWidget.h"
+#include "DockAreaTitleBar.h"
+#include "DockAreaTabBar.h"
+#include "FloatingDockContainer.h"
+#include "DockComponentsFactory.h"
+
+using namespace ads;
+
+
+CMainWindow::CMainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::CMainWindow)
+{
+ ui->setupUi(this);
+ CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true);
+ CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false);
+ CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true);
+ DockManager = new CDockManager(this);
+
+ // Set central widget
+ QLabel* label = new QLabel();
+ label->setText("This is a DockArea which is always visible, even if it does not contain any DockWidgets.");
+ label->setAlignment(Qt::AlignCenter);
+ CDockWidget* CentralDockWidget = new CDockWidget("CentralWidget");
+ CentralDockWidget->setWidget(label);
+ CentralDockWidget->setFeature(ads::CDockWidget::NoTab, true);
+ auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget);
+
+ // create other dock widgets
+ QTableWidget* table = new QTableWidget();
+ table->setColumnCount(3);
+ table->setRowCount(10);
+ CDockWidget* TableDockWidget = new CDockWidget("Table 1");
+ TableDockWidget->setWidget(table);
+ TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ TableDockWidget->resize(250, 150);
+ TableDockWidget->setMinimumSize(200,150);
+ DockManager->addDockWidgetTabToArea(TableDockWidget, CentralDockArea);
+ auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget);
+ ui->menuView->addAction(TableDockWidget->toggleViewAction());
+
+ table = new QTableWidget();
+ table->setColumnCount(5);
+ table->setRowCount(1020);
+ TableDockWidget = new CDockWidget("Table 2");
+ TableDockWidget->setWidget(table);
+ TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ TableDockWidget->resize(250, 150);
+ TableDockWidget->setMinimumSize(200,150);
+ DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea);
+ ui->menuView->addAction(TableDockWidget->toggleViewAction());
+
+ QTableWidget* propertiesTable = new QTableWidget();
+ propertiesTable->setColumnCount(3);
+ propertiesTable->setRowCount(10);
+ CDockWidget* PropertiesDockWidget = new CDockWidget("Properties");
+ PropertiesDockWidget->setWidget(propertiesTable);
+ PropertiesDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget);
+ PropertiesDockWidget->resize(250, 150);
+ PropertiesDockWidget->setMinimumSize(200,150);
+ DockManager->addDockWidget(DockWidgetArea::RightDockWidgetArea, PropertiesDockWidget, CentralDockArea);
+ ui->menuView->addAction(PropertiesDockWidget->toggleViewAction());
+
+ createPerspectiveUi();
+}
+
+CMainWindow::~CMainWindow()
+{
+ delete ui;
+}
+
+
+void CMainWindow::createPerspectiveUi()
+{
+ SavePerspectiveAction = new QAction("Create Perspective", this);
+ connect(SavePerspectiveAction, SIGNAL(triggered()), SLOT(savePerspective()));
+ PerspectiveListAction = new QWidgetAction(this);
+ PerspectiveComboBox = new QComboBox(this);
+ PerspectiveComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+ PerspectiveComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ connect(PerspectiveComboBox, SIGNAL(activated(const QString&)),
+ DockManager, SLOT(openPerspective(const QString&)));
+ PerspectiveListAction->setDefaultWidget(PerspectiveComboBox);
+ ui->toolBar->addSeparator();
+ ui->toolBar->addAction(PerspectiveListAction);
+ ui->toolBar->addAction(SavePerspectiveAction);
+}
+
+
+void CMainWindow::savePerspective()
+{
+ QString PerspectiveName = QInputDialog::getText(this, "Save Perspective", "Enter unique name:");
+ if (PerspectiveName.isEmpty())
+ {
+ return;
+ }
+
+ DockManager->addPerspective(PerspectiveName);
+ QSignalBlocker Blocker(PerspectiveComboBox);
+ PerspectiveComboBox->clear();
+ PerspectiveComboBox->addItems(DockManager->perspectiveNames());
+ PerspectiveComboBox->setCurrentText(PerspectiveName);
+}
+
+
+//============================================================================
+void CMainWindow::closeEvent(QCloseEvent* event)
+{
+ // Delete dock manager here to delete all floating widgets. This ensures
+ // that all top level windows of the dock manager are properly closed
+ DockManager->deleteLater();
+ QMainWindow::closeEvent(event);
+}
+
+
diff --git a/QtADS/examples/emptydockarea/mainwindow.h b/QtADS/examples/emptydockarea/mainwindow.h
new file mode 100644
index 0000000..75869da
--- /dev/null
+++ b/QtADS/examples/emptydockarea/mainwindow.h
@@ -0,0 +1,43 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include
+
+#include "DockManager.h"
+#include "DockAreaWidget.h"
+#include "DockWidget.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class CMainWindow; }
+QT_END_NAMESPACE
+
+class CMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ CMainWindow(QWidget *parent = nullptr);
+ ~CMainWindow();
+
+protected:
+ virtual void closeEvent(QCloseEvent* event) override;
+
+private:
+ QAction* SavePerspectiveAction = nullptr;
+ QWidgetAction* PerspectiveListAction = nullptr;
+ QComboBox* PerspectiveComboBox = nullptr;
+
+ Ui::CMainWindow *ui;
+
+ ads::CDockManager* DockManager;
+ ads::CDockAreaWidget* StatusDockArea;
+ ads::CDockWidget* TimelineDockWidget;
+
+ void createPerspectiveUi();
+
+private slots:
+ void savePerspective();
+};
+#endif // MAINWINDOW_H
diff --git a/QtADS/examples/emptydockarea/mainwindow.ui b/QtADS/examples/emptydockarea/mainwindow.ui
new file mode 100644
index 0000000..f7d3b09
--- /dev/null
+++ b/QtADS/examples/emptydockarea/mainwindow.ui
@@ -0,0 +1,47 @@
+
+
+ CMainWindow
+
+
+
+ 0
+ 0
+ 1284
+ 757
+
+
+
+ MainWindow
+
+
+
+
+
+ 0
+ 0
+ 1284
+ 21
+
+
+
+
+ View
+
+
+
+
+
+
+ toolBar
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
diff --git a/QtADS/examples/examples.pro b/QtADS/examples/examples.pro
new file mode 100644
index 0000000..e2b0705
--- /dev/null
+++ b/QtADS/examples/examples.pro
@@ -0,0 +1,12 @@
+TEMPLATE = subdirs
+
+SUBDIRS = \
+ autohide \
+ centralwidget \
+ simple \
+ hideshow \
+ sidebar \
+ deleteonclose \
+ emptydockarea \
+ dockindock \
+ configflags
diff --git a/QtADS/examples/hideshow/CMakeLists.txt b/QtADS/examples/hideshow/CMakeLists.txt
new file mode 100644
index 0000000..becab35
--- /dev/null
+++ b/QtADS/examples/hideshow/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_hideshow VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(HideShowExample WIN32
+ main.cpp
+ MainWindow.cpp
+ MainWindow.ui
+)
+target_include_directories(HideShowExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(HideShowExample PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(HideShowExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(HideShowExample PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Hide,Show Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/hideshow/MainWindow.cpp b/QtADS/examples/hideshow/MainWindow.cpp
new file mode 100644
index 0000000..44ce672
--- /dev/null
+++ b/QtADS/examples/hideshow/MainWindow.cpp
@@ -0,0 +1,80 @@
+#include "../../examples/hideshow/MainWindow.h"
+
+#include "ui_MainWindow.h"
+
+#include
+#include
+
+using namespace ads;
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ ui->centralWidget->setLayout( m_layout = new QStackedLayout() );
+
+ m_welcomeWidget = new QWidget(this);
+ auto welcomeLayout = new QVBoxLayout(m_welcomeWidget);
+ welcomeLayout->addStretch();
+ QPushButton* openButton = new QPushButton("Open project");
+ welcomeLayout->addWidget( openButton );
+ welcomeLayout->addStretch();
+
+ connect( openButton, SIGNAL(clicked()), this, SLOT(openProject()) );
+
+ m_DockManager = new ads::CDockManager(ui->centralWidget);
+
+ // Create example content label - this can be any application specific
+ // widget
+ QLabel* l = new QLabel();
+ l->setWordWrap(true);
+ l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
+
+ // Create a dock widget with the title Label 1 and set the created label
+ // as the dock widget content
+ ads::CDockWidget* DockWidget = new ads::CDockWidget("Label 1");
+ DockWidget->setWidget(l);
+
+ // Add the toggleViewAction of the dock widget to the menu to give
+ // the user the possibility to show the dock widget if it has been closed
+ ui->menuView->addAction(DockWidget->toggleViewAction());
+
+ connect( ui->actionOpen, SIGNAL(triggered()), this, SLOT(openProject()) );
+ connect( ui->actionClose, SIGNAL(triggered()), this, SLOT(closeProject()) );
+
+ // Add the dock widget to the top dock widget area
+ m_DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget);
+
+ ui->centralWidget->layout()->addWidget( m_welcomeWidget );
+ ui->centralWidget->layout()->addWidget( m_DockManager );
+
+ closeProject();
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::openProject()
+{
+ ui->actionOpen->setEnabled(false);
+ ui->actionClose->setEnabled(true);
+ ui->menuView->setEnabled(true);
+
+ m_layout->setCurrentWidget( m_DockManager );
+}
+
+void MainWindow::closeProject()
+{
+ ui->actionOpen->setEnabled(true);
+ ui->actionClose->setEnabled(false);
+ ui->menuView->setEnabled(false);
+
+ m_DockManager->hideManagerAndFloatingWidgets();
+ m_layout->setCurrentWidget( m_welcomeWidget );
+}
+
diff --git a/QtADS/examples/hideshow/MainWindow.h b/QtADS/examples/hideshow/MainWindow.h
new file mode 100644
index 0000000..6668387
--- /dev/null
+++ b/QtADS/examples/hideshow/MainWindow.h
@@ -0,0 +1,33 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include "DockManager.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class MainWindow;
+}
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+private slots:
+ void openProject();
+ void closeProject();
+
+private:
+ Ui::MainWindow *ui;
+ QWidget* m_welcomeWidget;
+ ads::CDockManager* m_DockManager;
+ QStackedLayout* m_layout;
+};
+
+#endif // MAINWINDOW_H
diff --git a/QtADS/examples/hideshow/MainWindow.ui b/QtADS/examples/hideshow/MainWindow.ui
new file mode 100644
index 0000000..260b1f4
--- /dev/null
+++ b/QtADS/examples/hideshow/MainWindow.ui
@@ -0,0 +1,56 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ MainWindow
+
+
+
+
+
+ 0
+ 0
+ 400
+ 26
+
+
+
+
+ View
+
+
+
+
+ File
+
+
+
+
+
+
+
+
+
+
+ Open project
+
+
+
+
+ Close project
+
+
+
+
+
+
+
diff --git a/QtADS/examples/hideshow/hideshow.pro b/QtADS/examples/hideshow/hideshow.pro
new file mode 100644
index 0000000..86782d9
--- /dev/null
+++ b/QtADS/examples/hideshow/hideshow.pro
@@ -0,0 +1,31 @@
+ADS_OUT_ROOT = $${OUT_PWD}/../..
+
+QT += core gui widgets
+
+TARGET = HideShowExample
+DESTDIR = $${ADS_OUT_ROOT}/lib
+TEMPLATE = app
+CONFIG += c++14
+CONFIG += debug_and_release
+adsBuildStatic {
+ DEFINES += ADS_STATIC
+}
+
+DEFINES += QT_DEPRECATED_WARNINGS
+
+SOURCES += \
+ main.cpp \
+ MainWindow.cpp
+
+HEADERS += \
+ MainWindow.h
+
+FORMS += \
+ MainWindow.ui
+
+
+LIBS += -L$${ADS_OUT_ROOT}/lib
+include(../../ads.pri)
+INCLUDEPATH += ../../src
+DEPENDPATH += ../../src
+
diff --git a/QtADS/examples/hideshow/main.cpp b/QtADS/examples/hideshow/main.cpp
new file mode 100644
index 0000000..e62035c
--- /dev/null
+++ b/QtADS/examples/hideshow/main.cpp
@@ -0,0 +1,11 @@
+#include
+#include "../../examples/hideshow/MainWindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/QtADS/examples/sidebar/CMakeLists.txt b/QtADS/examples/sidebar/CMakeLists.txt
new file mode 100644
index 0000000..a2e05e6
--- /dev/null
+++ b/QtADS/examples/sidebar/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.5)
+project(ads_example_sidebar VERSION ${VERSION_SHORT})
+find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
+find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+add_executable(SidebarExample WIN32
+ main.cpp
+ MainWindow.cpp
+ MainWindow.ui
+)
+target_include_directories(SidebarExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
+target_link_libraries(SidebarExample PRIVATE qt${QT_VERSION_MAJOR}advanceddocking)
+target_link_libraries(SidebarExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
+ Qt${QT_VERSION_MAJOR}::Gui
+ Qt${QT_VERSION_MAJOR}::Widgets)
+set_target_properties(SidebarExample PROPERTIES
+ AUTOMOC ON
+ AUTORCC ON
+ AUTOUIC ON
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+ CXX_EXTENSIONS OFF
+ VERSION ${VERSION_SHORT}
+ EXPORT_NAME "Qt Advanced Docking System Sidebar Example"
+ ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib"
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin"
+)
diff --git a/QtADS/examples/sidebar/MainWindow.cpp b/QtADS/examples/sidebar/MainWindow.cpp
new file mode 100644
index 0000000..9d93908
--- /dev/null
+++ b/QtADS/examples/sidebar/MainWindow.cpp
@@ -0,0 +1,64 @@
+#include "MainWindow.h"
+
+#include "ui_MainWindow.h"
+
+#include
+#include
+#include
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ // Create the dock manager. Because the parent parameter is a QMainWindow
+ // the dock manager registers itself as the central widget.
+ QVBoxLayout* Layout = new QVBoxLayout(ui->dockContainer);
+ Layout->setContentsMargins(QMargins(0, 0, 0, 0));
+ m_DockManager = new ads::CDockManager(ui->dockContainer);
+ Layout->addWidget(m_DockManager);
+
+ // Create example content label - this can be any application specific
+ // widget
+ QLabel* l = new QLabel();
+ l->setWordWrap(true);
+ l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ l->setText("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. ");
+
+ // Create a dock widget with the title Label 1 and set the created label
+ // as the dock widget content
+ ads::CDockWidget* DockWidget = new ads::CDockWidget("Label 1");
+ DockWidget->setWidget(l);
+
+ // Add the toggleViewAction of the dock widget to the menu to give
+ // the user the possibility to show the dock widget if it has been closed
+ ui->menuView->addAction(DockWidget->toggleViewAction());
+
+
+ // Add the dock widget to the top dock widget area
+ m_DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget);
+
+ // Create an example editor
+ QPlainTextEdit* te = new QPlainTextEdit();
+ te->setPlaceholderText("Please enter your text here into this QPlainTextEdit...");
+ DockWidget = new ads::CDockWidget("Editor 1");
+ DockWidget->setWidget(te);
+ ui->menuView->addAction(DockWidget->toggleViewAction());
+ m_DockManager->addDockWidget(ads::BottomDockWidgetArea, DockWidget);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ QMainWindow::closeEvent(event);
+ if (m_DockManager)
+ {
+ m_DockManager->deleteLater();
+ }
+}
diff --git a/QtADS/examples/sidebar/MainWindow.h b/QtADS/examples/sidebar/MainWindow.h
new file mode 100644
index 0000000..d371a41
--- /dev/null
+++ b/QtADS/examples/sidebar/MainWindow.h
@@ -0,0 +1,33 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include "DockManager.h"
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class MainWindow;
+}
+QT_END_NAMESPACE
+
+/**
+ * This example shows, how to place a dock widget container and a static
+ * sidebar into a QMainWindow
+ */
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+protected:
+ virtual void closeEvent(QCloseEvent *event) override;
+
+private:
+ Ui::MainWindow *ui;
+ ads::CDockManager* m_DockManager;
+};
+
+#endif // MAINWINDOW_H
diff --git a/QtADS/examples/sidebar/MainWindow.ui b/QtADS/examples/sidebar/MainWindow.ui
new file mode 100644
index 0000000..9bcac64
--- /dev/null
+++ b/QtADS/examples/sidebar/MainWindow.ui
@@ -0,0 +1,85 @@
+
+
+