diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b0a2a665..f9b1d7f4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,11 +16,13 @@ if(NOT ADS_VERSION) 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}") + set(VERSION_SONAME "${VERSION_MAJOR}") 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}) + string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" VERSION_SONAME "${ADS_VERSION}") else() message(FATAL_ERROR "ADS_VERSION must be in major.minor.patch format, e.g. 3.8.1. Got ${ADS_VERSION}") endif() diff --git a/README.md b/README.md index 3d034f9c4..97ee54432 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,7 @@ know it from Visual Studio. - [DREAM3D-NX](#dream3d-nx) - [LabPlot](#labplot) - [Scrutiny Debugger](#scrutiny-debugger) + - [PySoWorks](#pysoworks) - [Alternative Docking System Implementations](#alternative-docking-system-implementations) - [KDDockWidgets](#kddockwidgets) - [QtitanDocking](#qtitandocking) @@ -729,6 +730,15 @@ ADS powers Scrutiny’s flexible interface, letting users organize views and dat [![Scrutiny Debugger UI](doc/showcase_scrutiny-dark.png)](https://www.youtube.com/watch?v=Dd3osxW-Clo) + +### [PySoWorks](https://pypi.org/project/pysoworks/) + +PySoWorks is an application for controlling the piezo amplifiers, such as the [NV200/D](https://www.piezosystem.com/product/nv-200-d-compact-amplifier/), from [piezosystem jena](https://www.piezosystem.com/) GmbH. + +![LabPlot](doc/showcase_pysoworks.png) + +[read more...](https://piezosystemjena.github.io/PySoWorks/) + ## 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. diff --git a/cmake/modules/FileVersionInfo.rc.in b/cmake/modules/FileVersionInfo.rc.in new file mode 100644 index 000000000..812b1ae92 --- /dev/null +++ b/cmake/modules/FileVersionInfo.rc.in @@ -0,0 +1,29 @@ +#include + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 + PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "My Company\0" + VALUE "FileDescription", "@PROJECT_NAME@\0" + VALUE "FileVersion", "@PROJECT_VERSION_STRING@\0" + VALUE "ProductVersion", "@PROJECT_VERSION_STRING@\0" + VALUE "GitCommitFull", "@PROJECT_GIT_HASH@\0" + VALUE "GitCommitShort", "@PROJECT_GIT_HASH_SHORT@\0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END +END diff --git a/cmake/modules/Versioning.cmake b/cmake/modules/Versioning.cmake new file mode 100644 index 000000000..e492370a4 --- /dev/null +++ b/cmake/modules/Versioning.cmake @@ -0,0 +1,95 @@ +# ============================================================ +# Versioning.cmake (Reusable Version + Resource Generator) +# ============================================================ + +# Freeze the directory where this module lives +# This is critical — it prevents paths from breaking when the +# function is invoked from other CMakeLists.txt files. +set(_VERSIONING_MODULE_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "Versioning module directory") + +# ------------------------------------------------------------ +# Extract version information from Git +# ------------------------------------------------------------ + +# Get tag (expected: v1.2.3 or 1.2.3 or 1.2.3-12-gHASH) +execute_process( + COMMAND git describe --tags --dirty + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_DESC_RAW + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Remove leading "v" if present +string(REGEX REPLACE "^v" "" GIT_DESC "${GIT_DESC_RAW}") + +# Extract major.minor.patch +string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" _ "${GIT_DESC}") +set(PROJECT_VERSION_MAJOR "${CMAKE_MATCH_1}") +set(PROJECT_VERSION_MINOR "${CMAKE_MATCH_2}") +set(PROJECT_VERSION_PATCH "${CMAKE_MATCH_3}") + +set(PROJECT_VERSION_STRING + "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}" +) + +# Commit hash (full + short) +execute_process( + COMMAND git rev-parse HEAD + OUTPUT_VARIABLE PROJECT_GIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( + COMMAND git rev-parse --short HEAD + OUTPUT_VARIABLE PROJECT_GIT_HASH_SHORT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# Export variables to parent scope +set(PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}" PARENT_SCOPE) +set(PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}" PARENT_SCOPE) +set(PROJECT_VERSION_PATCH "${PROJECT_VERSION_PATCH}" PARENT_SCOPE) +set(PROJECT_VERSION_STRING "${PROJECT_VERSION_STRING}" PARENT_SCOPE) +set(PROJECT_GIT_HASH "${PROJECT_GIT_HASH}" PARENT_SCOPE) +set(PROJECT_GIT_HASH_SHORT "${PROJECT_GIT_HASH_SHORT}" PARENT_SCOPE) + +# Public variable for users +set(PROJECT_AUTO_VERSION "${PROJECT_VERSION_STRING}" PARENT_SCOPE) + +# ------------------------------------------------------------ +# Reusable function: Attach Windows version resources to target +# ------------------------------------------------------------ +function(add_windows_version_resources target) + if(NOT WIN32) + return() + endif() + + if(NOT TARGET "${target}") + message(FATAL_ERROR "add_windows_version_resources: target '${target}' not found.") + endif() + + # Absolute path to the template (never changes) + get_filename_component(_rc_in + "${_VERSIONING_MODULE_DIR}/FileVersionInfo.rc.in" + ABSOLUTE + ) + + if(NOT EXISTS "${_rc_in}") + message(FATAL_ERROR + "FileVersionInfo.rc.in missing at: ${_rc_in}" + ) + endif() + + # Output in the caller's binary dir + set(_rc_out "${CMAKE_CURRENT_BINARY_DIR}/${target}_version.rc") + get_filename_component(_rc_out "${_rc_out}" ABSOLUTE) + + # Ensure directory exists + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + + # Configure the template + configure_file("${_rc_in}" "${_rc_out}" @ONLY) + + # Add to the target + target_sources(${target} PRIVATE "${_rc_out}") +endfunction() diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 77c3af2e7..e5b910c14 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -396,7 +396,7 @@ struct MainWindowPrivate 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, [=]() + QObject::connect(Action, &QAction::triggered, [DockWidget]() { if (DockWidget->isFullScreen()) { @@ -510,7 +510,7 @@ void MainWindowPrivate::createContent() auto TitleBar = DockArea->titleBar(); int Index = TitleBar->indexOf(TitleBar->tabBar()); TitleBar->insertWidget(Index + 1, CustomButton); - QObject::connect(CustomButton, &QToolButton::clicked, [=]() + QObject::connect(CustomButton, &QToolButton::clicked, [DockArea, this]() { auto DockWidget = createEditorWidget(); DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true); diff --git a/doc/cfg_flag_TabsAtBottom.png b/doc/cfg_flag_TabsAtBottom.png new file mode 100644 index 000000000..724987a95 Binary files /dev/null and b/doc/cfg_flag_TabsAtBottom.png differ diff --git a/doc/showcase_pysoworks.png b/doc/showcase_pysoworks.png new file mode 100644 index 000000000..9e06aa77c Binary files /dev/null and b/doc/showcase_pysoworks.png differ diff --git a/doc/user-guide.md b/doc/user-guide.md index 97519f225..e6634f977 100644 --- a/doc/user-guide.md +++ b/doc/user-guide.md @@ -1,79 +1,81 @@ # 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) - - [`DoubleClickUndocksWidget`](#doubleclickundockswidget) -- [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) -- [Auto-Hide Configuration Flags](#auto-hide-configuration-flags) - - [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) - - [`AutoHideOpenOnDragHover`](#autohideopenondraghover) - - [`AutoHideCloseOnOutsideMouseClick`](#autohidecloseonoutsidemouseclick) -- [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) -- [Globally Lock Docking Features](#globally-lock-docking-features) -- [Dock Widget Size / Minimum Size Handling](#dock-widget-size--minimum-size-handling) -- [Styling](#styling) - - [Disabling the Internal Style Sheet](#disabling-the-internal-style-sheet) -- [Using ADS on Linux](#using-ads-on-linux) - - [Supported Distributions](#supported-distributions) - - [Requirements](#requirements) - - [Manjaro xfce 25.0.1 and Xubuntu 24.04.2 issues](#manjaro-xfce-2501-and-xubuntu-24042-issues) -- [OpenGl + ADS](#opengl--ads) +- [User Guide](#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) + - [`DoubleClickUndocksWidget`](#doubleclickundockswidget) + - [`TabsAtBottom`](#tabsatbottom) + - [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) + - [Auto-Hide Configuration Flags](#auto-hide-configuration-flags) + - [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) + - [`AutoHideOpenOnDragHover`](#autohideopenondraghover) + - [`AutoHideCloseOnOutsideMouseClick`](#autohidecloseonoutsidemouseclick) + - [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) + - [Globally Lock Docking Features](#globally-lock-docking-features) + - [Dock Widget Size / Minimum Size Handling](#dock-widget-size--minimum-size-handling) + - [Styling](#styling) + - [Disabling the Internal Style Sheet](#disabling-the-internal-style-sheet) + - [Using ADS on Linux](#using-ads-on-linux) + - [Supported Distributions](#supported-distributions) + - [Requirements](#requirements) + - [Manjaro xfce 25.0.1 and Xubuntu 24.04.2 issues](#manjaro-xfce-2501-and-xubuntu-24042-issues) + - [OpenGl + ADS](#opengl--ads) ## Configuration Flags @@ -510,6 +512,12 @@ for active tabs. Inactive tabs only show their icon: If the flag is set (default), a double click on a tab undocks the dock widget. If you would like to disable undocking, just clear this flag. +### `TabsAtBottom` + +If the flag is set, tabs will be shown at the bottom instead of in the title bar. + +![TabsAtBottom true](cfg_flag_TabsAtBottom.png) + ## Auto Hide Dock Widgets The Advanced Docking System supports "Auto-Hide" functionality for **all** diff --git a/examples/autohidedragndrop/mainwindow.cpp b/examples/autohidedragndrop/mainwindow.cpp index fb5017daa..774fca2ce 100644 --- a/examples/autohidedragndrop/mainwindow.cpp +++ b/examples/autohidedragndrop/mainwindow.cpp @@ -27,6 +27,7 @@ CMainWindow::CMainWindow(QWidget *parent) CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true); CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false); CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + CDockManager::setConfigFlag(CDockManager::TabsAtBottom, true); CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); CDockManager::setAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover, true); CDockManager::setConfigParam(CDockManager::AutoHideOpenOnDragHoverDelay_ms, 500); diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 66d1277d7..f6f3ad93c 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -139,7 +139,7 @@ struct AutoHideTabPrivate IFloatingWidget* createFloatingWidget(T* Widget) { auto w = new CFloatingDragPreview(Widget); - _this->connect(w, &CFloatingDragPreview::draggingCanceled, [=]() + _this->connect(w, &CFloatingDragPreview::draggingCanceled, [this]() { DragState = DraggingInactive; }); diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index 20ee70a91..f3b528518 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -93,7 +93,7 @@ private Q_SLOTS: /** * Virtual Destructor */ - virtual ~CAutoHideTab(); + ~CAutoHideTab() override; /** * Update stylesheet style if a property changes diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index da0244b8b..e291cddc5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.16) project(QtAdvancedDockingSystem LANGUAGES CXX VERSION ${VERSION_SHORT}) include(GNUInstallDirs) +include(Versioning) if (${QT_VERSION_MAJOR}) message(STATUS "Forced to use Qt version ${QT_VERSION_MAJOR}") find_package(QT NAMES Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) @@ -13,8 +14,8 @@ if (UNIX AND NOT APPLE AND QT_VERSION_MAJOR STREQUAL "6" AND QT_VERSION_MINOR GR set(ads_DEP_LIBS Core Gui GuiPrivate Widgets) endif() find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${ads_DEP_LIBS} REQUIRED) -if (UNIX AND NOT APPLE AND QT_VERSION_MAJOR STREQUAL "6" AND QT_VERSION_MINOR GREATER 8) - include_directories(${Qt${QT_VERSION_MAJOR}Gui_PRIVATE_INCLUDE_DIRS}) +if (UNIX AND NOT APPLE AND ((QT_VERSION_MAJOR STREQUAL "6" AND QT_VERSION_MINOR GREATER 8) OR QT_VERSION_MAJOR STREQUAL "5")) + include_directories(${Qt${QT_VERSION_MAJOR}Gui_PRIVATE_INCLUDE_DIRS}) endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -83,6 +84,7 @@ if(BUILD_STATIC) target_compile_definitions( ${library_name} PUBLIC ADS_STATIC) else() add_library( ${library_name} SHARED ${ads_SRCS} ${ads_HEADERS}) + add_windows_version_resources(${library_name}) target_compile_definitions( ${library_name} PRIVATE ADS_SHARED_EXPORT) endif() @@ -92,7 +94,7 @@ target_link_libraries(${library_name} PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets) -if(QT_VERSION_MAJOR STREQUAL "6") +if(UNIX AND NOT APPLE AND QT_VERSION_MAJOR STREQUAL "6") target_link_libraries(${library_name} PRIVATE Qt6::GuiPrivate) #needed for endif() @@ -109,6 +111,7 @@ set_target_properties(${library_name} PROPERTIES AUTORCC ON CXX_EXTENSIONS OFF VERSION ${VERSION_SHORT} + SOVERSION ${VERSION_SONAME} EXPORT_NAME ${library_name} DEBUG_POSTFIX "d" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 9470682bc..7dd261f89 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -260,10 +260,10 @@ void DockAreaTitleBarPrivate::createAutoHideTitleLabel() { AutoHideTitleLabel = new CElidingLabel(""); AutoHideTitleLabel->setObjectName("autoHideTitleLabel"); - // At position 0 is the tab bar - insert behind tab bar - Layout->insertWidget(1, AutoHideTitleLabel); - AutoHideTitleLabel->setVisible(false); // Default hidden - Layout->insertWidget(2 ,new CSpacerWidget(_this)); + // When the tabs are at the top, they will be at position 0, insert the label behind them, and hide it. + Layout->addWidget(AutoHideTitleLabel); + AutoHideTitleLabel->setVisible(CDockManager::testConfigFlag(CDockManager::TabsAtBottom)); + Layout->addWidget(new CSpacerWidget(_this)); } @@ -272,7 +272,9 @@ void DockAreaTitleBarPrivate::createTabBar() { TabBar = componentsFactory()->createDockAreaTabBar(DockArea); TabBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); - Layout->addWidget(TabBar); + if (!CDockManager::testConfigFlag(CDockManager::TabsAtBottom)) + Layout->addWidget(TabBar); + _this->connect(TabBar, SIGNAL(tabClosed(int)), SLOT(markTabsMenuOutdated())); _this->connect(TabBar, SIGNAL(tabOpened(int)), SLOT(markTabsMenuOutdated())); _this->connect(TabBar, SIGNAL(tabInserted(int)), SLOT(markTabsMenuOutdated())); @@ -303,7 +305,7 @@ IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset, else { auto w = new CFloatingDragPreview(DockArea); - QObject::connect(w, &CFloatingDragPreview::draggingCanceled, [=]() + QObject::connect(w, &CFloatingDragPreview::draggingCanceled, [this]() { this->DragState = DraggingInactive; }); @@ -351,8 +353,8 @@ CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) : setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); d->createTabBar(); - d->createButtons(); d->createAutoHideTitleLabel(); + d->createButtons(); setFocusPolicy(Qt::NoFocus); } @@ -900,9 +902,12 @@ QString CDockAreaTitleBar::titleBarButtonToolTip(TitleBarButton Button) const //============================================================================ void CDockAreaTitleBar::showAutoHideControls(bool Show) { - d->TabBar->setVisible(!Show); // Auto hide toolbar never has tabs + if (Show) + d->TabBar->setVisible(false); // Auto hide toolbar never has tabs + d->MinimizeButton->setVisible(Show); - d->AutoHideTitleLabel->setVisible(Show); + if (!CDockManager::testConfigFlag(CDockManager::TabsAtBottom)) + d->AutoHideTitleLabel->setVisible(Show); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 917638744..dfcb4ee08 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -179,14 +179,17 @@ class CDockAreaLayout parent->setUpdatesEnabled(false); } - auto LayoutItem = m_ParentLayout->takeAt(1); - if (LayoutItem) + if (m_CurrentWidget) { - LayoutItem->widget()->setParent(nullptr); + auto LayoutItem = m_ParentLayout->takeAt(1); + if (LayoutItem) + { + LayoutItem->widget()->setParent(nullptr); + } + delete LayoutItem; } - delete LayoutItem; - m_ParentLayout->addWidget(next); + m_ParentLayout->insertWidget(1, next); if (prev) { prev->hide(); @@ -362,6 +365,14 @@ void DockAreaWidgetPrivate::createTitleBar() { TitleBar = componentsFactory()->createDockAreaTitleBar(_this); Layout->addWidget(TitleBar); + if (CDockManager::testConfigFlag(CDockManager::TabsAtBottom)) + { + // Title bar will be index 0, container widgets will be index 1, + // so tabs will always be at the end of the layout. + Layout->addWidget(tabBar()); + tabBar()->setVisible(CDockManager::testConfigFlag(CDockManager::AlwaysShowTabs)); + } + QObject::connect(tabBar(), &CDockAreaTabBar::tabCloseRequested, _this, &CDockAreaWidget::onTabCloseRequested); QObject::connect(TitleBar, &CDockAreaTitleBar::tabBarClicked, _this, &CDockAreaWidget::setCurrentIndex); QObject::connect(tabBar(), &CDockAreaTabBar::tabMoved, _this, &CDockAreaWidget::reorderDockWidget); @@ -726,6 +737,7 @@ void CDockAreaWidget::setCurrentIndex(int index) TabBar->setCurrentIndex(index); d->ContentsLayout->setCurrentIndex(index); d->ContentsLayout->currentWidget()->show(); + d->TitleBar->autoHideTitleLabel()->setText(d->ContentsLayout->currentWidget()->windowTitle()); Q_EMIT currentChanged(index); } @@ -879,7 +891,22 @@ void CDockAreaWidget::updateTitleBarVisibility() { // Always show title bar if it contains title bar actions if (CDockWidget* TopLevelWidget = Container->topLevelDockWidget()) + { Hidden |= TopLevelWidget->titleBarActions().empty(); + } + else if (CDockManager::testConfigFlag(CDockManager::TabsAtBottom)) + { + Hidden = true; + + for (CDockWidget* DockWidget : Container->openedDockWidgets()) + { + if (!DockWidget->titleBarActions().empty()) + { + Hidden = false; + break; + } + } + } } if (!Hidden && d->Flags.testFlag(HideSingleWidgetTitleBar)) { @@ -889,6 +916,8 @@ void CDockAreaWidget::updateTitleBarVisibility() } } d->TitleBar->setVisible(!Hidden); + if (CDockManager::testConfigFlag(CDockManager::TabsAtBottom)) + d->TitleBar->tabBar()->setVisible(openDockWidgetsCount() > 1); } if (isAutoHideFeatureEnabled()) diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index e0c39c73c..1deda6b0b 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -199,7 +199,7 @@ protected Q_SLOTS: /** * Virtual Destructor */ - virtual ~CDockAreaWidget(); + ~CDockAreaWidget() override; /** * Returns the dock manager object this dock area belongs to diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index f55855a3d..d32824b39 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -219,7 +219,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Virtual Destructor */ - virtual ~CDockContainerWidget(); + ~CDockContainerWidget() override; /** * Adds dockwidget into the given area. diff --git a/src/DockManager.cpp b/src/DockManager.cpp index f31e675a2..91598660f 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -530,15 +531,30 @@ CDockManager::CDockManager(QWidget *parent) : window()->installEventFilter(this); #if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) - connect(qApp, &QApplication::focusWindowChanged, [this](QWindow* focusWindow) + connect(qApp, &QApplication::focusWindowChanged, this, [this](QWindow* focusWindow) { if (!focusWindow) { return; } - // bring the main application window that hosts the dock manager and all floating - // widgets in front of any other application + auto widget = QWidget::find(focusWindow->winId()); + if (!widget) + { + return; + } + + // If the user clicks the main window or drags a floating widget or works with a + // dialog, then raise the main window, all floating widgets and the focus window + // itself to bring it into foregreound of any other application + bool raise = qobject_cast(widget) + || qobject_cast(widget) + || qobject_cast(widget); + if (!raise) + { + return; + } + this->raise(); for (auto FloatingWidget : d->FloatingWidgets) { diff --git a/src/DockManager.h b/src/DockManager.h index 92744f72b..fcc5ce315 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -216,6 +216,7 @@ public Q_SLOTS: DisableTabTextEliding = 0x4000000, //! Set this flag to disable eliding of tab texts in dock area tabs ShowTabTextOnlyForActiveTab =0x8000000, //! Set this flag to show label texts in dock area tabs only for active tabs DoubleClickUndocksWidget = 0x10000000, //!< If the flag is set, a double click on a tab undocks the widget + TabsAtBottom = 0x20000000, //!< If the flag is set, tabs will be shown at the bottom instead of in the title bar. DefaultDockAreaButtons = DockAreaHasCloseButton diff --git a/src/DockWidget.h b/src/DockWidget.h index 04d10f8b9..47c015d79 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -289,7 +289,7 @@ private Q_SLOTS: /** * Virtual Destructor */ - virtual ~CDockWidget(); + ~CDockWidget() override; /** * We return a fixed minimum size hint or the size hint of the content diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index d633c5a20..943a8c614 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -169,7 +169,7 @@ struct DockWidgetTabPrivate else { auto w = new CFloatingDragPreview(Widget); - _this->connect(w, &CFloatingDragPreview::draggingCanceled, [=]() + _this->connect(w, &CFloatingDragPreview::draggingCanceled, [this]() { DragState = DraggingInactive; }); @@ -539,7 +539,7 @@ QMenu* CDockWidgetTab::buildContextMenu(QMenu *Menu) Menu = new QMenu(this); } - qDebug() << "CDockWidgetTab::buildContextMenu"; + ADS_PRINT("CDockWidgetTab::buildContextMenu"); const bool isFloatable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable); const bool isTopLevelArea = d->DockArea->isTopLevelArea(); const bool isFloating = d->DockWidget->isFloating(); diff --git a/src/FloatingDockContainer.h b/src/FloatingDockContainer.h index 2dd9d499f..284e30ad5 100644 --- a/src/FloatingDockContainer.h +++ b/src/FloatingDockContainer.h @@ -220,7 +220,7 @@ private Q_SLOTS: /** * Virtual Destructor */ - virtual ~CFloatingDockContainer(); + ~CFloatingDockContainer() override; /** * Access function for the internal dock container diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 19c5ab1dd..5a737012b 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -82,6 +82,10 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } +#autoHideTitleLabel { + padding-left: 4px; + color: palette(foreground); +} #tabCloseButton { margin-top: 2px; @@ -278,7 +282,7 @@ ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaT } -#autoHideTitleLabel { +ads--CAutoHideDockContainer #autoHideTitleLabel { padding-left: 4px; color: palette(light); } diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index d9bc03d99..058352628 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -39,6 +39,12 @@ ads--CTitleBarButton { } +#autoHideTitleLabel { + padding-left: 4px; + color: palette(foreground); +} + + #tabsMenuButton { qproperty-icon: url(:/ads/images/tabs-menu-button.svg); qproperty-iconSize: 16px; @@ -88,6 +94,12 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { } +#autoHideTitleLabel { + padding-left: 4px; + color: palette(foreground); +} + + #tabCloseButton { margin-top: 2px; background: none; @@ -314,7 +326,7 @@ ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaT } -#autoHideTitleLabel { +ads--CAutoHideDockContainer #autoHideTitleLabel { padding-left: 4px; color: palette(light); } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 758f58613..9c2f8ed85 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -95,6 +95,10 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } +#autoHideTitleLabel { + padding-left: 4px; + color: palette(foreground); +} #tabCloseButton { margin-top: 2px; @@ -316,7 +320,7 @@ ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaT } -#autoHideTitleLabel { +ads--CAutoHideDockContainer #autoHideTitleLabel { padding-left: 4px; color: palette(light); } diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index cfedf8f77..48ec71a22 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -40,6 +40,12 @@ ads--CTitleBarButton { } +#autoHideTitleLabel { + padding-left: 4px; + color: palette(foreground); +} + + #tabsMenuButton { qproperty-icon: url(:/ads/images/tabs-menu-button.svg); qproperty-iconSize: 16px; @@ -391,7 +397,7 @@ ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaT } -#autoHideTitleLabel { +ads--CAutoHideDockContainer #autoHideTitleLabel { padding-left: 4px; color: palette(light); }