mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-12-25 15:41:34 +08:00
Merge branch 'githubuser0xFFFF:master' into master
This commit is contained in:
commit
4b27af959b
4
.github/workflows/linux-builds.yml
vendored
4
.github/workflows/linux-builds.yml
vendored
@ -6,7 +6,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, ubuntu-18.04, ubuntu-16.04]
|
os: [ubuntu-latest, ubuntu-20.04, ubuntu-18.04]
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get update --fix-missing
|
sudo apt-get update --fix-missing
|
||||||
sudo apt-get install qt5-default
|
sudo apt-get install qt5-default
|
||||||
sudo apt-get install libqt5x11extras5-dev
|
sudo apt-get install qtbase5-private-dev
|
||||||
- name: qmake
|
- name: qmake
|
||||||
run: qmake
|
run: qmake
|
||||||
- name: make
|
- name: make
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -383,3 +383,4 @@ FodyWeavers.xsd
|
|||||||
/ build
|
/ build
|
||||||
/Settings.ini
|
/Settings.ini
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
/.settings
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<project>
|
|
||||||
<configuration id="cdt.managedbuild.toolchain.gnu.mingw.base.1119687795" name="Default">
|
|
||||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
|
||||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
|
||||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
|
||||||
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(g?cc)|([gc]\+\+)|(clang)" prefer-non-shared="true"/>
|
|
||||||
<provider class="org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorMinGW" console="false" env-hash="-703253235712566569" id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetectorMinGW" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings MinGW" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
|
||||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
|
||||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
|
||||||
</provider>
|
|
||||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
|
||||||
</extension>
|
|
||||||
</configuration>
|
|
||||||
</project>
|
|
20
.travis.yml
20
.travis.yml
@ -9,8 +9,6 @@ matrix:
|
|||||||
os: linux
|
os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
group: stable
|
group: stable
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y install libqt5x11extras5-dev
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@ -20,8 +18,6 @@ matrix:
|
|||||||
packages:
|
packages:
|
||||||
- qt55base
|
- qt55base
|
||||||
- qt55tools
|
- qt55tools
|
||||||
- qt55x11extras
|
|
||||||
- libqt5x11extras5-dev
|
|
||||||
- gcc-9
|
- gcc-9
|
||||||
- g++-9
|
- g++-9
|
||||||
script:
|
script:
|
||||||
@ -39,8 +35,6 @@ matrix:
|
|||||||
services:
|
services:
|
||||||
- xvfb
|
- xvfb
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y install libqt5x11extras5-dev
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@ -50,8 +44,6 @@ matrix:
|
|||||||
packages:
|
packages:
|
||||||
- qt514base
|
- qt514base
|
||||||
- qt514tools
|
- qt514tools
|
||||||
- qt514x11extras
|
|
||||||
- libqt5x11extras5-dev
|
|
||||||
- gcc-9
|
- gcc-9
|
||||||
- g++-9
|
- g++-9
|
||||||
- libc6-i386
|
- libc6-i386
|
||||||
@ -73,8 +65,6 @@ matrix:
|
|||||||
services:
|
services:
|
||||||
- xvfb
|
- xvfb
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y install libqt5x11extras5-dev
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@ -84,8 +74,6 @@ matrix:
|
|||||||
packages:
|
packages:
|
||||||
- qt514base
|
- qt514base
|
||||||
- qt514tools
|
- qt514tools
|
||||||
- qt514x11extras
|
|
||||||
- libqt5x11extras5-dev
|
|
||||||
- gcc-9
|
- gcc-9
|
||||||
- g++-9
|
- g++-9
|
||||||
- libc6-i386
|
- libc6-i386
|
||||||
@ -107,8 +95,6 @@ matrix:
|
|||||||
services:
|
services:
|
||||||
- xvfb
|
- xvfb
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y install libqt5x11extras5-dev
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@ -118,8 +104,6 @@ matrix:
|
|||||||
packages:
|
packages:
|
||||||
- qt514base
|
- qt514base
|
||||||
- qt514tools
|
- qt514tools
|
||||||
- qt514x11extras
|
|
||||||
- libqt5x11extras5-dev
|
|
||||||
- gcc-9
|
- gcc-9
|
||||||
- g++-9
|
- g++-9
|
||||||
- libc6-i386
|
- libc6-i386
|
||||||
@ -147,8 +131,6 @@ matrix:
|
|||||||
services:
|
services:
|
||||||
- xvfb
|
- xvfb
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
before_install:
|
|
||||||
- sudo apt-get -y install libqt5x11extras5-dev
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
@ -158,8 +140,6 @@ matrix:
|
|||||||
packages:
|
packages:
|
||||||
- qt514base
|
- qt514base
|
||||||
- qt514tools
|
- qt514tools
|
||||||
- qt514x11extras
|
|
||||||
- libqt5x11extras5-dev
|
|
||||||
- gcc-9
|
- gcc-9
|
||||||
- g++-9
|
- g++-9
|
||||||
- libc6-i386
|
- libc6-i386
|
||||||
|
52
README.md
52
README.md
@ -15,6 +15,13 @@ integrated development environments (IDEs) such as Visual Studio.
|
|||||||
|
|
||||||
## New and Noteworthy
|
## New and Noteworthy
|
||||||
|
|
||||||
|
The [release 3.8](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.8.0)
|
||||||
|
adds the following features:
|
||||||
|
|
||||||
|
- option to close tabs with the middle mouse button
|
||||||
|
- `DeleteContentOnClose` flag for dynamic deletion and creation of dock widget
|
||||||
|
content
|
||||||
|
|
||||||
The [release 3.7](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.7.0)
|
The [release 3.7](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/tag/3.7.0)
|
||||||
adds the following features:
|
adds the following features:
|
||||||
|
|
||||||
@ -81,6 +88,8 @@ know it from Visual Studio.
|
|||||||
- [ezEditor](#ezeditor)
|
- [ezEditor](#ezeditor)
|
||||||
- [D-Tect X](#d-tect-x)
|
- [D-Tect X](#d-tect-x)
|
||||||
- [HiveWE](#hivewe)
|
- [HiveWE](#hivewe)
|
||||||
|
- [Ramses Composer](#ramses-composer)
|
||||||
|
- [Plot Juggler](#plot-juggler)
|
||||||
|
|
||||||
### Docking everywhere - no central widget
|
### Docking everywhere - no central widget
|
||||||
|
|
||||||
@ -219,7 +228,13 @@ Screenshot Ubuntu:
|
|||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Open the `ads.pro` with QtCreator and start the build, that's it.
|
The Linux build requires private header files. Make sure that they are installed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install qtbase5-private-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open the `ads.pro` file with QtCreator and start the build, that's it.
|
||||||
You can run the demo project and test it yourself.
|
You can run the demo project and test it yourself.
|
||||||
|
|
||||||
## Getting started / Example
|
## Getting started / Example
|
||||||
@ -391,3 +406,38 @@ of the open editor windows.
|
|||||||
[learn more...](https://github.com/stijnherfst/HiveWE)
|
[learn more...](https://github.com/stijnherfst/HiveWE)
|
||||||
|
|
||||||
![HiveWE](doc/showcase_hivewe.png)
|
![HiveWE](doc/showcase_hivewe.png)
|
||||||
|
|
||||||
|
### [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)
|
||||||
|
|
||||||
|
![RamsesComposer](doc/showcase_ramses_composer.png)
|
||||||
|
|
||||||
|
### [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)
|
||||||
|
|
||||||
|
[![Plot Juggler](doc/showcase_plot_juggler.png)](https://vimeo.com/480588113#t=46s)
|
13
ads.pri
13
ads.pri
@ -1,9 +1,13 @@
|
|||||||
|
|
||||||
lessThan(QT_MAJOR_VERSION, 6) {
|
|
||||||
CONFIG(debug, debug|release){
|
CONFIG(debug, debug|release){
|
||||||
win32 {
|
win32 {
|
||||||
|
versionAtLeast(QT_VERSION, 5.15.0) {
|
||||||
|
LIBS += -lqtadvanceddocking
|
||||||
|
}
|
||||||
|
else {
|
||||||
LIBS += -lqtadvanceddockingd
|
LIBS += -lqtadvanceddockingd
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else:mac {
|
else:mac {
|
||||||
LIBS += -lqtadvanceddocking_debug
|
LIBS += -lqtadvanceddocking_debug
|
||||||
}
|
}
|
||||||
@ -14,15 +18,8 @@ lessThan(QT_MAJOR_VERSION, 6) {
|
|||||||
else{
|
else{
|
||||||
LIBS += -lqtadvanceddocking
|
LIBS += -lqtadvanceddocking
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
# qt$$qtLibraryTarget(qtadvanceddocking) does not produce an advanceddockingd.dll file on Windows
|
|
||||||
# for Qt6 - I don't know if this is a bug and I have to investigate
|
|
||||||
LIBS += -lqtadvanceddocking
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unix:!macx {
|
unix:!macx {
|
||||||
LIBS += -lxcb
|
LIBS += -lxcb
|
||||||
QT += x11extras
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,4 @@ include(CMakeFindDependencyMacro)
|
|||||||
find_dependency(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
|
find_dependency(Qt5Core ${REQUIRED_QT_VERSION} REQUIRED)
|
||||||
find_dependency(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
|
find_dependency(Qt5Gui ${REQUIRED_QT_VERSION} REQUIRED)
|
||||||
find_dependency(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
|
find_dependency(Qt5Widgets ${REQUIRED_QT_VERSION} REQUIRED)
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
find_dependency(Qt5X11Extras ${REQUIRED_QT_VERSION} REQUIRED)
|
|
||||||
endif()
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/adsTargets.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/adsTargets.cmake")
|
@ -1,9 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ads_demo VERSION ${VERSION_SHORT})
|
project(ads_demo VERSION ${VERSION_SHORT})
|
||||||
|
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
|
||||||
if(WIN32)
|
find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
||||||
find_package(Qt5 5.5 COMPONENTS AxContainer REQUIRED)
|
if(WIN32 AND QT_VERSION_MAJOR LESS 6)
|
||||||
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS AxContainer REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
set(ads_demo_SRCS
|
set(ads_demo_SRCS
|
||||||
@ -16,9 +17,11 @@ set(ads_demo_SRCS
|
|||||||
)
|
)
|
||||||
add_executable(AdvancedDockingSystemDemo WIN32 ${ads_demo_SRCS})
|
add_executable(AdvancedDockingSystemDemo WIN32 ${ads_demo_SRCS})
|
||||||
target_include_directories(AdvancedDockingSystemDemo PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src")
|
target_include_directories(AdvancedDockingSystemDemo PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src")
|
||||||
target_link_libraries(AdvancedDockingSystemDemo PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
target_link_libraries(AdvancedDockingSystemDemo PUBLIC Qt${QT_VERSION_MAJOR}::Core
|
||||||
if(WIN32)
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
target_link_libraries(AdvancedDockingSystemDemo PUBLIC Qt5::AxContainer)
|
Qt${QT_VERSION_MAJOR}::Widgets)
|
||||||
|
if(WIN32 AND QT_VERSION_MAJOR LESS 6)
|
||||||
|
target_link_libraries(AdvancedDockingSystemDemo PUBLIC Qt${QT_VERSION_MAJOR}::AxContainer)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(AdvancedDockingSystemDemo PRIVATE qtadvanceddocking)
|
target_link_libraries(AdvancedDockingSystemDemo PRIVATE qtadvanceddocking)
|
||||||
set_target_properties(AdvancedDockingSystemDemo PROPERTIES
|
set_target_properties(AdvancedDockingSystemDemo PROPERTIES
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
#include "FloatingDockContainer.h"
|
#include "FloatingDockContainer.h"
|
||||||
#include "DockComponentsFactory.h"
|
#include "DockComponentsFactory.h"
|
||||||
#include "StatusDialog.h"
|
#include "StatusDialog.h"
|
||||||
|
#include "DockSplitter.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -417,6 +417,22 @@ void MainWindowPrivate::createContent()
|
|||||||
DockWidget = createCalendarDockWidget();
|
DockWidget = createCalendarDockWidget();
|
||||||
DockWidget->setTabToolTip(QString("Tab ToolTip\nHodie est dies magna"));
|
DockWidget->setTabToolTip(QString("Tab ToolTip\nHodie est dies magna"));
|
||||||
auto DockArea = DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, TopDockArea);
|
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<ads::CDockSplitter*>(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});
|
||||||
|
});
|
||||||
|
|
||||||
// Now we add a custom button to the dock area title bar that will create
|
// Now we add a custom button to the dock area title bar that will create
|
||||||
// new editor widgets when clicked
|
// new editor widgets when clicked
|
||||||
@ -443,13 +459,14 @@ void MainWindowPrivate::createContent()
|
|||||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
|
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
|
||||||
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), BottomDockArea);
|
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), BottomDockArea);
|
||||||
|
|
||||||
auto Action = ui.menuTests->addAction(QString("Set %1 Floating").arg(DockWidget->windowTitle()));
|
Action = ui.menuTests->addAction(QString("Set %1 Floating").arg(DockWidget->windowTitle()));
|
||||||
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setFloating()));
|
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setFloating()));
|
||||||
Action = ui.menuTests->addAction(QString("Set %1 As Current Tab").arg(DockWidget->windowTitle()));
|
Action = ui.menuTests->addAction(QString("Set %1 As Current Tab").arg(DockWidget->windowTitle()));
|
||||||
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setAsCurrentTab()));
|
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(setAsCurrentTab()));
|
||||||
Action = ui.menuTests->addAction(QString("Raise %1").arg(DockWidget->windowTitle()));
|
Action = ui.menuTests->addAction(QString("Raise %1").arg(DockWidget->windowTitle()));
|
||||||
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(raise()));
|
DockWidget->connect(Action, SIGNAL(triggered()), SLOT(raise()));
|
||||||
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||||
if (!ads::CDockManager::testConfigFlag(ads::CDockManager::OpaqueUndocking))
|
if (!ads::CDockManager::testConfigFlag(ads::CDockManager::OpaqueUndocking))
|
||||||
@ -614,6 +631,9 @@ CMainWindow::CMainWindow(QWidget *parent) :
|
|||||||
// available size of a splitter to all contained dock widgets
|
// available size of a splitter to all contained dock widgets
|
||||||
// CDockManager::setConfigFlag(CDockManager::EqualSplitOnInsertion, true);
|
// 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
|
// Now create the dock manager and its content
|
||||||
d->DockManager = new CDockManager(this);
|
d->DockManager = new CDockManager(this);
|
||||||
|
|
||||||
|
@ -215,6 +215,17 @@ class MainWindow(MainWindowUI, MainWindowBase):
|
|||||||
dock_widget = self.create_calendar_dock_widget()
|
dock_widget = self.create_calendar_dock_widget()
|
||||||
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
|
dock_widget.setTabToolTip("Tab ToolTip\nHodie est dies magna")
|
||||||
dock_area = self.dock_manager.addDockWidget(QtAds.CenterDockWidgetArea, dock_widget, top_dock_area)
|
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
|
# Now we add a custom button to the dock area title bar that will create
|
||||||
# new editor widgets when clicked
|
# new editor widgets when clicked
|
BIN
doc/cfg_flag_MiddleMouseButtonClosesTab.gif
Normal file
BIN
doc/cfg_flag_MiddleMouseButtonClosesTab.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 257 KiB |
BIN
doc/showcase_plot_juggler.png
Normal file
BIN
doc/showcase_plot_juggler.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 264 KiB |
BIN
doc/showcase_ramses_composer.png
Normal file
BIN
doc/showcase_ramses_composer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 450 KiB |
@ -27,6 +27,17 @@
|
|||||||
- [`EqualSplitOnInsertion`](#equalsplitoninsertion)
|
- [`EqualSplitOnInsertion`](#equalsplitoninsertion)
|
||||||
- [`FloatingContainerForceNativeTitleBar` (Linux only)](#floatingcontainerforcenativetitlebar-linux-only)
|
- [`FloatingContainerForceNativeTitleBar` (Linux only)](#floatingcontainerforcenativetitlebar-linux-only)
|
||||||
- [`FloatingContainerForceQWidgetTitleBar` (Linux only)](#floatingcontainerforceqwidgettitlebar-linux-only)
|
- [`FloatingContainerForceQWidgetTitleBar` (Linux only)](#floatingcontainerforceqwidgettitlebar-linux-only)
|
||||||
|
- [`MiddleMouseButtonClosesTab`](#middlemousebuttonclosestab)
|
||||||
|
- [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)
|
- [Central Widget](#central-widget)
|
||||||
- [Empty Dock Area](#empty-dock-area)
|
- [Empty Dock Area](#empty-dock-area)
|
||||||
- [Custom Close Handling](#custom-close-handling)
|
- [Custom Close Handling](#custom-close-handling)
|
||||||
@ -464,6 +475,69 @@ 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
|
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.
|
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.
|
||||||
|
|
||||||
|
![MiddleMouseButtonClosesTab true](cfg_flag_MiddleMouseButtonClosesTab.gif)
|
||||||
|
|
||||||
|
## 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. If the `OpaqueUndocking` configuration flag is set, then dock widgets
|
||||||
|
are immediately undocked into floating widgets. That means, moving is only
|
||||||
|
possible in this case, if the dock widget is also floatable (feature flag
|
||||||
|
`DockWidgetFloatable` is set).
|
||||||
|
|
||||||
|
### `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
|
## Central Widget
|
||||||
|
|
||||||
The Advanced Docking System has been developed to overcome the limitations of
|
The Advanced Docking System has been developed to overcome the limitations of
|
||||||
|
@ -5,3 +5,4 @@ add_subdirectory(sidebar)
|
|||||||
add_subdirectory(deleteonclose)
|
add_subdirectory(deleteonclose)
|
||||||
add_subdirectory(centralwidget)
|
add_subdirectory(centralwidget)
|
||||||
add_subdirectory(emptydockarea)
|
add_subdirectory(emptydockarea)
|
||||||
|
add_subdirectory(dockindock)
|
@ -1,6 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ads_example_centralwidget VERSION ${VERSION_SHORT})
|
project(ads_example_centralwidget VERSION ${VERSION_SHORT})
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
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)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_executable(CentralWidgetExample WIN32
|
add_executable(CentralWidgetExample WIN32
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -9,7 +10,9 @@ add_executable(CentralWidgetExample WIN32
|
|||||||
)
|
)
|
||||||
target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
||||||
target_link_libraries(CentralWidgetExample PRIVATE qtadvanceddocking)
|
target_link_libraries(CentralWidgetExample PRIVATE qtadvanceddocking)
|
||||||
target_link_libraries(CentralWidgetExample PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
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
|
set_target_properties(CentralWidgetExample PROPERTIES
|
||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
AUTORCC ON
|
AUTORCC ON
|
||||||
|
@ -13,18 +13,6 @@ from PyQtAds import QtAds
|
|||||||
UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
|
UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui')
|
||||||
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
|
MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE)
|
||||||
|
|
||||||
import demo_rc # pyrcc5 demo\demo.qrc -o examples\centralWidget\demo_rc.py
|
|
||||||
|
|
||||||
|
|
||||||
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 MainWindow(MainWindowUI, MainWindowBase):
|
class MainWindow(MainWindowUI, MainWindowBase):
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
@ -46,27 +34,26 @@ class MainWindow(MainWindowUI, MainWindowBase):
|
|||||||
central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
|
central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas)
|
||||||
|
|
||||||
# create other dock widgets
|
# create other dock widgets
|
||||||
file_tree = QTreeView()
|
|
||||||
file_tree.setFrameShape(QFrame.NoFrame)
|
|
||||||
file_model = QFileSystemModel(file_tree)
|
|
||||||
file_model.setRootPath(QDir.currentPath())
|
|
||||||
file_tree.setModel(file_model)
|
|
||||||
data_dock_widget = QtAds.CDockWidget("File system")
|
|
||||||
data_dock_widget.setWidget(file_tree)
|
|
||||||
data_dock_widget.resize(150, 250)
|
|
||||||
data_dock_widget.setMinimumSize(100, 250)
|
|
||||||
file_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, data_dock_widget, central_dock_area)
|
|
||||||
self.menuView.addAction(data_dock_widget.toggleViewAction())
|
|
||||||
|
|
||||||
table = QTableWidget()
|
table = QTableWidget()
|
||||||
table.setColumnCount(3)
|
table.setColumnCount(3)
|
||||||
table.setRowCount(10)
|
table.setRowCount(10)
|
||||||
table_dock_widget = QtAds.CDockWidget("Table")
|
table_dock_widget = QtAds.CDockWidget("Table 1")
|
||||||
table_dock_widget.setWidget(table)
|
table_dock_widget.setWidget(table)
|
||||||
table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget)
|
||||||
table_dock_widget.resize(250, 150)
|
table_dock_widget.resize(250, 150)
|
||||||
table_dock_widget.setMinimumSize(200, 150)
|
table_dock_widget.setMinimumSize(200, 150)
|
||||||
self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, file_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)
|
||||||
|
table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, table_area)
|
||||||
self.menuView.addAction(table_dock_widget.toggleViewAction())
|
self.menuView.addAction(table_dock_widget.toggleViewAction())
|
||||||
|
|
||||||
properties_table = QTableWidget()
|
properties_table = QTableWidget()
|
||||||
@ -84,7 +71,6 @@ class MainWindow(MainWindowUI, MainWindowBase):
|
|||||||
|
|
||||||
def create_perspective_ui(self):
|
def create_perspective_ui(self):
|
||||||
save_perspective_action = QAction("Create Perspective", self)
|
save_perspective_action = QAction("Create Perspective", self)
|
||||||
save_perspective_action.setIcon(svg_icon(":/adsdemo/images/picture_in_picture.svg"))
|
|
||||||
save_perspective_action.triggered.connect(self.save_perspective)
|
save_perspective_action.triggered.connect(self.save_perspective)
|
||||||
perspective_list_action = QWidgetAction(self)
|
perspective_list_action = QWidgetAction(self)
|
||||||
self.perspective_combobox = QComboBox(self)
|
self.perspective_combobox = QComboBox(self)
|
@ -1,13 +1,16 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ads_example_deleteonclose VERSION ${VERSION_SHORT})
|
project(ads_example_deleteonclose VERSION ${VERSION_SHORT})
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
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)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_executable(DeleteOnCloseTest WIN32
|
add_executable(DeleteOnCloseTest WIN32
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
target_include_directories(DeleteOnCloseTest PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
target_include_directories(DeleteOnCloseTest PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
||||||
target_link_libraries(DeleteOnCloseTest PRIVATE qtadvanceddocking)
|
target_link_libraries(DeleteOnCloseTest PRIVATE qtadvanceddocking)
|
||||||
target_link_libraries(DeleteOnCloseTest PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
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
|
set_target_properties(DeleteOnCloseTest PROPERTIES
|
||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
CXX_STANDARD 14
|
CXX_STANDARD 14
|
||||||
|
@ -41,12 +41,12 @@ int main(int argc, char *argv[])
|
|||||||
now->widget()->setFocus();
|
now->widget()->setFocus();
|
||||||
});
|
});
|
||||||
|
|
||||||
QAction *action = new QAction("New Delete On Close", &w);
|
QAction *action = new QAction("New [DockWidgetDeleteOnClose]", &w);
|
||||||
w.menuBar()->addAction(action);
|
w.menuBar()->addAction(action);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
QObject::connect(action, &QAction::triggered, [&]() {
|
QObject::connect(action, &QAction::triggered, [&]() {
|
||||||
auto dw = new ads::CDockWidget(QStringLiteral("test doc %1").arg(i++), &w);
|
auto dw = new ads::CDockWidget(QStringLiteral("test %1 [DockWidgetDeleteOnClose]").arg(i++), &w);
|
||||||
auto editor = new QTextEdit(QStringLiteral("lorem ipsum..."), dw);
|
auto editor = new QTextEdit(QStringLiteral("lorem ipsum..."), dw);
|
||||||
dw->setWidget(editor);
|
dw->setWidget(editor);
|
||||||
dw->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
|
dw->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true);
|
||||||
@ -54,6 +54,26 @@ int main(int argc, char *argv[])
|
|||||||
qDebug() << "doc dock widget created!" << dw << area;
|
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);
|
action = new QAction("New", &w);
|
||||||
w.menuBar()->addAction(action);
|
w.menuBar()->addAction(action);
|
||||||
QObject::connect(action, &QAction::triggered, [&]() {
|
QObject::connect(action, &QAction::triggered, [&]() {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ads_example_simple VERSION ${VERSION_SHORT})
|
project(ads_example_dockindock VERSION ${VERSION_SHORT})
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
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)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_executable(DockInDock WIN32
|
add_executable(DockInDockExample WIN32
|
||||||
dockindock.cpp
|
dockindock.cpp
|
||||||
dockindockmanager.cpp
|
dockindockmanager.cpp
|
||||||
perspectiveactions.cpp
|
perspectiveactions.cpp
|
||||||
@ -10,10 +11,12 @@ add_executable(DockInDock WIN32
|
|||||||
main.cpp
|
main.cpp
|
||||||
mainframe.cpp
|
mainframe.cpp
|
||||||
)
|
)
|
||||||
target_include_directories(SimpleExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
target_include_directories(DockInDockExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
||||||
target_link_libraries(SimpleExample PRIVATE qtadvanceddocking)
|
target_link_libraries(DockInDockExample PRIVATE qtadvanceddocking)
|
||||||
target_link_libraries(SimpleExample PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
target_link_libraries(DockInDockExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
|
||||||
set_target_properties(SimpleExample PROPERTIES
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
|
Qt${QT_VERSION_MAJOR}::Widgets)
|
||||||
|
set_target_properties(DockInDockExample PROPERTIES
|
||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
AUTORCC ON
|
AUTORCC ON
|
||||||
AUTOUIC ON
|
AUTOUIC ON
|
||||||
|
203
examples/dockindock/dockindock.py
Normal file
203
examples/dockindock/dockindock.py
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QMessageBox,
|
||||||
|
QInputDialog, QMenu, QLineEdit)
|
||||||
|
from PyQt5.QtGui import QIcon
|
||||||
|
from PyQtAds import 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)")
|
214
examples/dockindock/dockindockmanager.py
Normal file
214
examples/dockindock/dockindockmanager.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
from PyQt5.QtWidgets import QAction, QMenu, QInputDialog, QLineEdit
|
||||||
|
from PyQt5.QtCore import QSettings
|
||||||
|
|
||||||
|
from PyQtAds import 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
|
72
examples/dockindock/main.py
Normal file
72
examples/dockindock/main.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQtAds import 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_()
|
25
examples/dockindock/perspectiveactions.py
Normal file
25
examples/dockindock/perspectiveactions.py
Normal file
@ -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)
|
203
examples/dockindock/perspectives.py
Normal file
203
examples/dockindock/perspectives.py
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import atexit
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtSignal, QSettings, QObject
|
||||||
|
from PyQtAds import 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
|
@ -1,6 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ads_example_centralwidget VERSION ${VERSION_SHORT})
|
project(ads_example_centralwidget VERSION ${VERSION_SHORT})
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
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)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_executable(EmptyDockAreaExample WIN32
|
add_executable(EmptyDockAreaExample WIN32
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -9,7 +10,9 @@ add_executable(EmptyDockAreaExample WIN32
|
|||||||
)
|
)
|
||||||
target_include_directories(EmptyDockAreaExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
target_include_directories(EmptyDockAreaExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
||||||
target_link_libraries(EmptyDockAreaExample PRIVATE qtadvanceddocking)
|
target_link_libraries(EmptyDockAreaExample PRIVATE qtadvanceddocking)
|
||||||
target_link_libraries(EmptyDockAreaExample PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
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
|
set_target_properties(EmptyDockAreaExample PROPERTIES
|
||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
AUTORCC ON
|
AUTORCC ON
|
||||||
|
108
examples/emptydockarea/main.py
Normal file
108
examples/emptydockarea/main.py
Normal file
@ -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
|
||||||
|
from PyQtAds import 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_()
|
@ -1,6 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ads_example_sidebar VERSION ${VERSION_SHORT})
|
project(ads_example_sidebar VERSION ${VERSION_SHORT})
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
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)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_executable(SidebarExample WIN32
|
add_executable(SidebarExample WIN32
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -9,7 +10,9 @@ add_executable(SidebarExample WIN32
|
|||||||
)
|
)
|
||||||
target_include_directories(SidebarExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
target_include_directories(SidebarExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
||||||
target_link_libraries(SidebarExample PRIVATE qtadvanceddocking)
|
target_link_libraries(SidebarExample PRIVATE qtadvanceddocking)
|
||||||
target_link_libraries(SidebarExample PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
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
|
set_target_properties(SidebarExample PROPERTIES
|
||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
AUTORCC ON
|
AUTORCC ON
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(ads_example_simple VERSION ${VERSION_SHORT})
|
project(ads_example_simple VERSION ${VERSION_SHORT})
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
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)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
add_executable(SimpleExample WIN32
|
add_executable(SimpleExample WIN32
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -9,7 +10,9 @@ add_executable(SimpleExample WIN32
|
|||||||
)
|
)
|
||||||
target_include_directories(SimpleExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
target_include_directories(SimpleExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src")
|
||||||
target_link_libraries(SimpleExample PRIVATE qtadvanceddocking)
|
target_link_libraries(SimpleExample PRIVATE qtadvanceddocking)
|
||||||
target_link_libraries(SimpleExample PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
target_link_libraries(SimpleExample PUBLIC Qt${QT_VERSION_MAJOR}::Core
|
||||||
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
|
Qt${QT_VERSION_MAJOR}::Widgets)
|
||||||
set_target_properties(SimpleExample PROPERTIES
|
set_target_properties(SimpleExample PROPERTIES
|
||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
AUTORCC ON
|
AUTORCC ON
|
||||||
|
4
setup.py
4
setup.py
@ -227,9 +227,7 @@ class build_ext(sipdistutils.build_ext):
|
|||||||
extension.extra_link_args += ['-F' + self.qtconfig.QT_INSTALL_LIBS,
|
extension.extra_link_args += ['-F' + self.qtconfig.QT_INSTALL_LIBS,
|
||||||
'-mmacosx-version-min=10.9']
|
'-mmacosx-version-min=10.9']
|
||||||
elif sys.platform == 'linux':
|
elif sys.platform == 'linux':
|
||||||
extension.extra_compile_args += ['-D', 'QT_X11EXTRAS_LIB', '-std=c++11']
|
extension.extra_compile_args += ['-std=c++11']
|
||||||
extension.include_dirs += [os.path.join(self.qt_include_dir, 'QtX11Extras')]
|
|
||||||
extension.libraries += ['Qt5X11Extras' + self.qt_libinfix]
|
|
||||||
|
|
||||||
return super().swig_sources(sources, extension)
|
return super().swig_sources(sources, extension)
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ public:
|
|||||||
void notifyWidgetOrAreaRelocation(QWidget* RelocatedWidget);
|
void notifyWidgetOrAreaRelocation(QWidget* RelocatedWidget);
|
||||||
void notifyFloatingWidgetDrop(ads::CFloatingDockContainer* FloatingWidget);
|
void notifyFloatingWidgetDrop(ads::CFloatingDockContainer* FloatingWidget);
|
||||||
ads::CDockWidget* focusedDockWidget() const;
|
ads::CDockWidget* focusedDockWidget() const;
|
||||||
|
void setDockWidgetTabFocused(ads::CDockWidgetTab* Tab);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setDockWidgetFocused(ads::CDockWidget* focusedNow);
|
void setDockWidgetFocused(ads::CDockWidget* focusedNow);
|
||||||
|
@ -33,8 +33,10 @@ public:
|
|||||||
CustomCloseHandling,
|
CustomCloseHandling,
|
||||||
DockWidgetFocusable,
|
DockWidgetFocusable,
|
||||||
DockWidgetForceCloseWithArea,
|
DockWidgetForceCloseWithArea,
|
||||||
|
NoTab,
|
||||||
DefaultDockWidgetFeatures,
|
DefaultDockWidgetFeatures,
|
||||||
AllDockWidgetFeatures,
|
AllDockWidgetFeatures,
|
||||||
|
DockWidgetAlwaysCloseAndDelete,
|
||||||
NoDockWidgetFeatures
|
NoDockWidgetFeatures
|
||||||
};
|
};
|
||||||
typedef QFlags<ads::CDockWidget::DockWidgetFeature> DockWidgetFeatures;
|
typedef QFlags<ads::CDockWidget::DockWidgetFeature> DockWidgetFeatures;
|
||||||
|
@ -2,6 +2,40 @@
|
|||||||
|
|
||||||
%If (Qt_5_0_0 -)
|
%If (Qt_5_0_0 -)
|
||||||
|
|
||||||
|
%ModuleHeaderCode
|
||||||
|
PyObject *qtads_FindParent(PyObject* type, const QWidget *child);
|
||||||
|
%End
|
||||||
|
|
||||||
|
%ModuleCode
|
||||||
|
PyObject *qtads_FindParent(PyObject* type, const QWidget *w)
|
||||||
|
{
|
||||||
|
// Check that the types checking was successful.
|
||||||
|
if (!type)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
QWidget* parentWidget = w->parentWidget();
|
||||||
|
|
||||||
|
while (parentWidget)
|
||||||
|
{
|
||||||
|
PyObject *ParentImpl = sipConvertFromType(parentWidget, sipType_QObject, 0);
|
||||||
|
if (!ParentImpl)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyObject_IsInstance(ParentImpl, type))
|
||||||
|
return ParentImpl;
|
||||||
|
|
||||||
|
Py_DECREF(ParentImpl);
|
||||||
|
|
||||||
|
parentWidget = parentWidget->parentWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
%End
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
%TypeHeaderCode
|
%TypeHeaderCode
|
||||||
@ -55,6 +89,50 @@ namespace ads
|
|||||||
BitwiseOr
|
BitwiseOr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace internal
|
||||||
|
{
|
||||||
|
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To);
|
||||||
|
void hideEmptyParentSplitters(ads::CDockSplitter* FirstParentSplitter);
|
||||||
|
|
||||||
|
class CDockInsertParam
|
||||||
|
{
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include <ads_globals.h>
|
||||||
|
%End
|
||||||
|
|
||||||
|
public:
|
||||||
|
Qt::Orientation orientation() const;
|
||||||
|
bool append() const;
|
||||||
|
int insertOffset() const;
|
||||||
|
};
|
||||||
|
ads::internal::CDockInsertParam dockAreaInsertParameters(ads::DockWidgetArea Area);
|
||||||
|
|
||||||
|
SIP_PYOBJECT findParent(SIP_PYTYPE type, const QWidget *w) const /TypeHint="QObject"/;
|
||||||
|
%MethodCode
|
||||||
|
sipRes = qtads_FindParent(a0, a1);
|
||||||
|
|
||||||
|
if (!sipRes)
|
||||||
|
{
|
||||||
|
sipIsErr = 1;
|
||||||
|
}
|
||||||
|
%End
|
||||||
|
|
||||||
|
QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity);
|
||||||
|
|
||||||
|
QPoint globalPositionOf(QMouseEvent* ev);
|
||||||
|
|
||||||
|
void setButtonIcon(QAbstractButton* Button, QStyle::StandardPixmap StandarPixmap, ads::eIcon CustomIconId);
|
||||||
|
|
||||||
|
enum eRepolishChildOptions
|
||||||
|
{
|
||||||
|
RepolishIgnoreChildren,
|
||||||
|
RepolishDirectChildren,
|
||||||
|
RepolishChildrenRecursively
|
||||||
|
};
|
||||||
|
|
||||||
|
void repolishStyle(QWidget* w, ads::internal::eRepolishChildOptions Options = ads::internal::RepolishIgnoreChildren);
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
%End
|
%End
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(QtAdvancedDockingSystem LANGUAGES CXX VERSION ${VERSION_SHORT})
|
project(QtAdvancedDockingSystem LANGUAGES CXX VERSION ${VERSION_SHORT})
|
||||||
find_package(Qt5 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
|
||||||
|
find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED)
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
find_package(Qt5 5.5 COMPONENTS X11Extras REQUIRED)
|
include_directories(${Qt${QT_VERSION_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
if(BUILD_STATIC)
|
if(BUILD_STATIC)
|
||||||
@ -60,11 +61,9 @@ else()
|
|||||||
add_library(qtadvanceddocking SHARED ${ads_SRCS} ${ads_HEADERS})
|
add_library(qtadvanceddocking SHARED ${ads_SRCS} ${ads_HEADERS})
|
||||||
target_compile_definitions(qtadvanceddocking PRIVATE ADS_SHARED_EXPORT)
|
target_compile_definitions(qtadvanceddocking PRIVATE ADS_SHARED_EXPORT)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(qtadvanceddocking PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
|
target_link_libraries(qtadvanceddocking PUBLIC Qt${QT_VERSION_MAJOR}::Core
|
||||||
if(UNIX AND NOT APPLE)
|
Qt${QT_VERSION_MAJOR}::Gui
|
||||||
target_link_libraries(qtadvanceddocking PUBLIC Qt5::X11Extras)
|
Qt${QT_VERSION_MAJOR}::Widgets)
|
||||||
target_link_libraries(qtadvanceddocking PRIVATE xcb)
|
|
||||||
endif()
|
|
||||||
set_target_properties(qtadvanceddocking PROPERTIES
|
set_target_properties(qtadvanceddocking PROPERTIES
|
||||||
AUTOMOC ON
|
AUTOMOC ON
|
||||||
AUTORCC ON
|
AUTORCC ON
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "DockAreaTabBar.h"
|
#include "DockAreaTabBar.h"
|
||||||
#include "IconProvider.h"
|
#include "IconProvider.h"
|
||||||
#include "DockComponentsFactory.h"
|
#include "DockComponentsFactory.h"
|
||||||
|
#include "DockFocusController.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -471,7 +472,8 @@ void CDockAreaTitleBar::mousePressEvent(QMouseEvent* ev)
|
|||||||
|
|
||||||
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
|
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
|
||||||
{
|
{
|
||||||
d->TabBar->currentTab()->setFocus(Qt::OtherFocusReason);
|
//d->TabBar->currentTab()->setFocus(Qt::OtherFocusReason);
|
||||||
|
d->dockManager()->dockFocusController()->setDockWidgetTabFocused(d->TabBar->currentTab());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1030,6 +1030,21 @@ void CDockAreaWidget::onDockWidgetFeaturesChanged()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
//============================================================================
|
||||||
|
bool CDockAreaWidget::event(QEvent *e)
|
||||||
|
{
|
||||||
|
switch (e->type())
|
||||||
|
{
|
||||||
|
case QEvent::PlatformSurface: return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Super::event(e);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -77,6 +77,17 @@ private Q_SLOTS:
|
|||||||
void reorderDockWidget(int fromIndex, int toIndex);
|
void reorderDockWidget(int fromIndex, int toIndex);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
/**
|
||||||
|
* Reimplements QWidget::event to handle QEvent::PlatformSurface
|
||||||
|
* This is here to fix issue #294 Tab refresh problem with a QGLWidget
|
||||||
|
* that exists since Qt version 5.12.7. So this function is here to
|
||||||
|
* work around a Qt issue.
|
||||||
|
*/
|
||||||
|
virtual bool event(QEvent *event) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a dock widget into dock area.
|
* Inserts a dock widget into dock area.
|
||||||
* All dockwidgets in the dock area tabified in a stacked layout with tabs.
|
* All dockwidgets in the dock area tabified in a stacked layout with tabs.
|
||||||
@ -356,7 +367,8 @@ Q_SIGNALS:
|
|||||||
*/
|
*/
|
||||||
void viewToggled(bool Open);
|
void viewToggled(bool Open);
|
||||||
}; // class DockAreaWidget
|
}; // class DockAreaWidget
|
||||||
}
|
} // namespace ads
|
||||||
// namespace ads
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(ads::CDockAreaWidget::DockAreaFlags)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#endif // DockAreaWidgetH
|
#endif // DockAreaWidgetH
|
||||||
|
@ -1566,7 +1566,8 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
|
|||||||
|
|
||||||
if (Dropped)
|
if (Dropped)
|
||||||
{
|
{
|
||||||
FloatingWidget->deleteLater();
|
// Fix https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/351
|
||||||
|
FloatingWidget->hideAndDeleteLater();
|
||||||
|
|
||||||
// If we dropped a floating widget with only one single dock widget, then we
|
// If we dropped a floating widget with only one single dock widget, then we
|
||||||
// drop a top level widget that changes from floating to docked now
|
// drop a top level widget that changes from floating to docked now
|
||||||
@ -1679,9 +1680,12 @@ bool CDockContainerWidget::restoreState(CDockingStateReader& s, bool Testing)
|
|||||||
if (!Testing)
|
if (!Testing)
|
||||||
{
|
{
|
||||||
CFloatingDockContainer* FloatingWidget = floatingWidget();
|
CFloatingDockContainer* FloatingWidget = floatingWidget();
|
||||||
|
if (FloatingWidget)
|
||||||
|
{
|
||||||
FloatingWidget->restoreGeometry(Geometry);
|
FloatingWidget->restoreGeometry(Geometry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!d->restoreChildNodes(s, NewRootSplitter, Testing))
|
if (!d->restoreChildNodes(s, NewRootSplitter, Testing))
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QAbstractButton>
|
#include <QAbstractButton>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
#include "DockWidget.h"
|
#include "DockWidget.h"
|
||||||
#include "DockAreaWidget.h"
|
#include "DockAreaWidget.h"
|
||||||
@ -31,6 +32,8 @@
|
|||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
|
static const char* const FocusedDockWidgetProperty = "FocusedDockWidget";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data class of CDockFocusController class (pimpl)
|
* Private data class of CDockFocusController class (pimpl)
|
||||||
*/
|
*/
|
||||||
@ -56,8 +59,8 @@ struct DockFocusControllerPrivate
|
|||||||
* the dock area that it belongs to
|
* the dock area that it belongs to
|
||||||
*/
|
*/
|
||||||
void updateDockWidgetFocus(CDockWidget* DockWidget);
|
void updateDockWidgetFocus(CDockWidget* DockWidget);
|
||||||
};
|
}; // struct DockFocusControllerPrivate
|
||||||
// struct DockFocusControllerPrivate
|
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@ -115,6 +118,17 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWindow* Window = nullptr;
|
||||||
|
auto DockContainer = DockWidget->dockContainer();
|
||||||
|
if (DockContainer)
|
||||||
|
{
|
||||||
|
Window = DockContainer->window()->windowHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Window)
|
||||||
|
{
|
||||||
|
Window->setProperty(FocusedDockWidgetProperty, QVariant::fromValue(QPointer<CDockWidget>(DockWidget)));
|
||||||
|
}
|
||||||
CDockAreaWidget* NewFocusedDockArea = nullptr;
|
CDockAreaWidget* NewFocusedDockArea = nullptr;
|
||||||
if (FocusedDockWidget)
|
if (FocusedDockWidget)
|
||||||
{
|
{
|
||||||
@ -139,21 +153,25 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto NewFloatingWidget = FocusedDockWidget->dockContainer()->floatingWidget();
|
|
||||||
|
CFloatingDockContainer* NewFloatingWidget = nullptr;
|
||||||
|
DockContainer = FocusedDockWidget->dockContainer();
|
||||||
|
if (DockContainer)
|
||||||
|
{
|
||||||
|
NewFloatingWidget = DockContainer->floatingWidget();
|
||||||
|
}
|
||||||
|
|
||||||
if (NewFloatingWidget)
|
if (NewFloatingWidget)
|
||||||
{
|
{
|
||||||
NewFloatingWidget->setProperty("FocusedDockWidget", QVariant::fromValue(DockWidget));
|
NewFloatingWidget->setProperty(FocusedDockWidgetProperty, QVariant::fromValue(QPointer<CDockWidget>(DockWidget)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
// This code is required for styling the floating widget titlebar for linux
|
// This code is required for styling the floating widget titlebar for linux
|
||||||
// depending on the current focus state
|
// depending on the current focus state
|
||||||
if (FloatingWidget == NewFloatingWidget)
|
if (FloatingWidget != NewFloatingWidget)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FloatingWidget)
|
if (FloatingWidget)
|
||||||
{
|
{
|
||||||
updateFloatingWidgetFocusStyle(FloatingWidget, false);
|
updateFloatingWidgetFocusStyle(FloatingWidget, false);
|
||||||
@ -164,6 +182,7 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget)
|
|||||||
{
|
{
|
||||||
updateFloatingWidgetFocusStyle(FloatingWidget, true);
|
updateFloatingWidgetFocusStyle(FloatingWidget, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (old == DockWidget && !ForceFocusChangedSignal)
|
if (old == DockWidget && !ForceFocusChangedSignal)
|
||||||
@ -206,6 +225,8 @@ CDockFocusController::CDockFocusController(CDockManager* DockManager) :
|
|||||||
d->DockManager = DockManager;
|
d->DockManager = DockManager;
|
||||||
connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)),
|
connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)),
|
||||||
this, SLOT(onApplicationFocusChanged(QWidget*, QWidget*)));
|
this, SLOT(onApplicationFocusChanged(QWidget*, QWidget*)));
|
||||||
|
connect(QApplication::instance(), SIGNAL(focusWindowChanged(QWindow*)),
|
||||||
|
this, SLOT(onFocusWindowChanged(QWindow*)));
|
||||||
connect(d->DockManager, SIGNAL(stateRestored()), SLOT(onStateRestored()));
|
connect(d->DockManager, SIGNAL(stateRestored()), SLOT(onStateRestored()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,9 +237,35 @@ CDockFocusController::~CDockFocusController()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockFocusController::onFocusWindowChanged(QWindow *focusWindow)
|
||||||
|
{
|
||||||
|
if (!focusWindow)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vDockWidget = focusWindow->property(FocusedDockWidgetProperty);
|
||||||
|
if (!vDockWidget.isValid())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto DockWidget = vDockWidget.value<QPointer<CDockWidget>>();
|
||||||
|
if (!DockWidget)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->updateDockWidgetFocus(DockWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
void CDockFocusController::onApplicationFocusChanged(QWidget* focusedOld, QWidget* focusedNow)
|
void CDockFocusController::onApplicationFocusChanged(QWidget* focusedOld, QWidget* focusedNow)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(focusedOld);
|
||||||
|
|
||||||
if (d->DockManager->isRestoringState())
|
if (d->DockManager->isRestoringState())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -231,47 +278,7 @@ void CDockFocusController::onApplicationFocusChanged(QWidget* focusedOld, QWidge
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the close button in another tab steals the focus from the current
|
CDockWidget* DockWidget = qobject_cast<CDockWidget*>(focusedNow);
|
||||||
// active dock widget content, i.e. if the user clicks its close button,
|
|
||||||
// then we immediately give the focus back to the previous focused widget
|
|
||||||
// focusedOld
|
|
||||||
if (CDockManager::testConfigFlag(CDockManager::AllTabsHaveCloseButton))
|
|
||||||
{
|
|
||||||
auto OtherDockWidgetTab = internal::findParent<CDockWidgetTab*>(focusedNow);
|
|
||||||
if (OtherDockWidgetTab && focusedOld)
|
|
||||||
{
|
|
||||||
auto OldFocusedDockWidget = internal::findParent<CDockWidget*>(focusedOld);
|
|
||||||
if (OldFocusedDockWidget)
|
|
||||||
{
|
|
||||||
focusedOld->setFocus();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CDockWidget* DockWidget = nullptr;
|
|
||||||
auto DockWidgetTab = qobject_cast<CDockWidgetTab*>(focusedNow);
|
|
||||||
if (DockWidgetTab)
|
|
||||||
{
|
|
||||||
DockWidget = DockWidgetTab->dockWidget();
|
|
||||||
// If the DockWidgetTab "steals" the focus from a widget in the same
|
|
||||||
// DockWidget, then we immediately give the focus back to the previous
|
|
||||||
// focused widget focusedOld
|
|
||||||
if (focusedOld)
|
|
||||||
{
|
|
||||||
auto OldFocusedDockWidget = internal::findParent<CDockWidget*>(focusedOld);
|
|
||||||
if (OldFocusedDockWidget && OldFocusedDockWidget == DockWidget)
|
|
||||||
{
|
|
||||||
focusedOld->setFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DockWidget)
|
|
||||||
{
|
|
||||||
DockWidget = qobject_cast<CDockWidget*>(focusedNow);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DockWidget)
|
if (!DockWidget)
|
||||||
{
|
{
|
||||||
DockWidget = internal::findParent<CDockWidget*>(focusedNow);
|
DockWidget = internal::findParent<CDockWidget*>(focusedNow);
|
||||||
@ -293,6 +300,17 @@ void CDockFocusController::onApplicationFocusChanged(QWidget* focusedOld, QWidge
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockFocusController::setDockWidgetTabFocused(CDockWidgetTab* Tab)
|
||||||
|
{
|
||||||
|
auto DockWidget = Tab->dockWidget();
|
||||||
|
if (DockWidget)
|
||||||
|
{
|
||||||
|
d->updateDockWidgetFocus(DockWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
void CDockFocusController::setDockWidgetFocused(CDockWidget* focusedNow)
|
void CDockFocusController::setDockWidgetFocused(CDockWidget* focusedNow)
|
||||||
{
|
{
|
||||||
@ -320,7 +338,7 @@ void CDockFocusController::onFocusedDockAreaViewToggled(bool Open)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDockManager::setWidgetFocus(OpenedDockAreas[0]->currentDockWidget()->tabWidget());
|
d->updateDockWidgetFocus(OpenedDockAreas[0]->currentDockWidget());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -348,7 +366,7 @@ void CDockFocusController::notifyWidgetOrAreaRelocation(QWidget* DroppedWidget)
|
|||||||
}
|
}
|
||||||
|
|
||||||
d->ForceFocusChangedSignal = true;
|
d->ForceFocusChangedSignal = true;
|
||||||
CDockManager::setWidgetFocus(DockWidget->tabWidget());
|
CDockManager::setWidgetFocus(DockWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -360,18 +378,17 @@ void CDockFocusController::notifyFloatingWidgetDrop(CFloatingDockContainer* Floa
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vDockWidget = FloatingWidget->property("FocusedDockWidget");
|
auto vDockWidget = FloatingWidget->property(FocusedDockWidgetProperty);
|
||||||
if (!vDockWidget.isValid())
|
if (!vDockWidget.isValid())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DockWidget = vDockWidget.value<CDockWidget*>();
|
auto DockWidget = vDockWidget.value<QPointer<CDockWidget>>();
|
||||||
if (DockWidget)
|
if (DockWidget)
|
||||||
{
|
{
|
||||||
d->FocusedDockWidget = nullptr;
|
|
||||||
DockWidget->dockAreaWidget()->setCurrentDockWidget(DockWidget);
|
DockWidget->dockAreaWidget()->setCurrentDockWidget(DockWidget);
|
||||||
CDockManager::setWidgetFocus(DockWidget->tabWidget());
|
CDockManager::setWidgetFocus(DockWidget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ private:
|
|||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onApplicationFocusChanged(QWidget *old, QWidget *now);
|
void onApplicationFocusChanged(QWidget *old, QWidget *now);
|
||||||
|
void onFocusWindowChanged(QWindow *focusWindow);
|
||||||
void onFocusedDockAreaViewToggled(bool Open);
|
void onFocusedDockAreaViewToggled(bool Open);
|
||||||
void onStateRestored();
|
void onStateRestored();
|
||||||
void onDockWidgetVisibilityChanged(bool Visible);
|
void onDockWidgetVisibilityChanged(bool Visible);
|
||||||
@ -48,21 +49,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual ~CDockFocusController();
|
virtual ~CDockFocusController();
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function to set focus depending on the configuration of the
|
|
||||||
* FocusStyling flag
|
|
||||||
*/
|
|
||||||
template <class QWidgetPtr>
|
|
||||||
static void setWidgetFocus(QWidgetPtr widget)
|
|
||||||
{
|
|
||||||
if (!CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
widget->setFocus(Qt::OtherFocusReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container needs to call this function if a widget has been dropped
|
* A container needs to call this function if a widget has been dropped
|
||||||
* into it
|
* into it
|
||||||
@ -83,6 +69,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
CDockWidget* focusedDockWidget() const;
|
CDockWidget* focusedDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request focus highlighting for the given dock widget assigned to the tab
|
||||||
|
* given in Tab parameter
|
||||||
|
*/
|
||||||
|
void setDockWidgetTabFocused(CDockWidgetTab* Tab);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
/**
|
/**
|
||||||
* Request a focus change to the given dock widget
|
* Request a focus change to the given dock widget
|
||||||
|
@ -1140,6 +1140,13 @@ void CDockManager::setSplitterSizes(CDockAreaWidget *ContainedArea, const QList<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CDockFocusController* CDockManager::dockFocusController() const
|
||||||
|
{
|
||||||
|
return d->FocusController;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -53,6 +53,7 @@ struct DockWidgetTabPrivate;
|
|||||||
struct DockAreaWidgetPrivate;
|
struct DockAreaWidgetPrivate;
|
||||||
class CIconProvider;
|
class CIconProvider;
|
||||||
class CDockComponentsFactory;
|
class CDockComponentsFactory;
|
||||||
|
class CDockFocusController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The central dock manager that maintains the complete docking system.
|
* The central dock manager that maintains the complete docking system.
|
||||||
@ -134,12 +135,18 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget);
|
void notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the floating widgets that has been created floating
|
* Show the floating widgets that has been created floating
|
||||||
*/
|
*/
|
||||||
virtual void showEvent(QShowEvent *event) override;
|
virtual void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acces for the internal dock focus controller.
|
||||||
|
* This function only returns a valid object, if the FocusHighlighting
|
||||||
|
* flag is set.
|
||||||
|
*/
|
||||||
|
CDockFocusController* dockFocusController() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Super = CDockContainerWidget;
|
using Super = CDockContainerWidget;
|
||||||
|
|
||||||
@ -188,6 +195,7 @@ public:
|
|||||||
FloatingContainerForceQWidgetTitleBar = 0x1000000,//!< Linux only ! Forces all FloatingContainer to use a QWidget based title bar.
|
FloatingContainerForceQWidgetTitleBar = 0x1000000,//!< Linux only ! Forces all FloatingContainer to use a QWidget based title bar.
|
||||||
//!< If neither this nor FloatingContainerForceNativeTitleBar is set (the default) native titlebars are used except on known bad systems.
|
//!< If neither this nor FloatingContainerForceNativeTitleBar is set (the default) native titlebars are used except on known bad systems.
|
||||||
//! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0".
|
//! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0".
|
||||||
|
MiddleMouseButtonClosesTab = 0x2000000, //! If the flag is set, the user can use the mouse middle button to close the tab under the mouse
|
||||||
|
|
||||||
DefaultDockAreaButtons = DockAreaHasCloseButton
|
DefaultDockAreaButtons = DockAreaHasCloseButton
|
||||||
| DockAreaHasUndockButton
|
| DockAreaHasUndockButton
|
||||||
@ -609,5 +617,7 @@ Q_SIGNALS:
|
|||||||
void focusedDockWidgetChanged(ads::CDockWidget* old, ads::CDockWidget* now);
|
void focusedDockWidgetChanged(ads::CDockWidget* old, ads::CDockWidget* now);
|
||||||
}; // class DockManager
|
}; // class DockManager
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(ads::CDockManager::ConfigFlags)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#endif // DockManagerH
|
#endif // DockManagerH
|
||||||
|
@ -806,7 +806,7 @@ void CDockOverlayCross::setIconColors(const QString& Colors)
|
|||||||
{"Arrow", CDockOverlayCross::ArrowColor},
|
{"Arrow", CDockOverlayCross::ArrowColor},
|
||||||
{"Shadow", CDockOverlayCross::ShadowColor}};
|
{"Shadow", CDockOverlayCross::ShadowColor}};
|
||||||
|
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
|
||||||
auto SkipEmptyParts = QString::SkipEmptyParts;
|
auto SkipEmptyParts = QString::SkipEmptyParts;
|
||||||
#else
|
#else
|
||||||
auto SkipEmptyParts = Qt::SkipEmptyParts;
|
auto SkipEmptyParts = Qt::SkipEmptyParts;
|
||||||
|
@ -66,6 +66,12 @@ namespace ads
|
|||||||
*/
|
*/
|
||||||
struct DockWidgetPrivate
|
struct DockWidgetPrivate
|
||||||
{
|
{
|
||||||
|
struct WidgetFactory
|
||||||
|
{
|
||||||
|
CDockWidget::FactoryFunc createWidget;
|
||||||
|
CDockWidget::eInsertMode insertMode;
|
||||||
|
};
|
||||||
|
|
||||||
CDockWidget* _this = nullptr;
|
CDockWidget* _this = nullptr;
|
||||||
QBoxLayout* Layout = nullptr;
|
QBoxLayout* Layout = nullptr;
|
||||||
QWidget* Widget = nullptr;
|
QWidget* Widget = nullptr;
|
||||||
@ -84,6 +90,7 @@ struct DockWidgetPrivate
|
|||||||
bool IsFloatingTopLevel = false;
|
bool IsFloatingTopLevel = false;
|
||||||
QList<QAction*> TitleBarActions;
|
QList<QAction*> TitleBarActions;
|
||||||
CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget;
|
CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget;
|
||||||
|
WidgetFactory* Factory = nullptr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data constructor
|
* Private data constructor
|
||||||
@ -116,6 +123,12 @@ struct DockWidgetPrivate
|
|||||||
* Setup the main scroll area
|
* Setup the main scroll area
|
||||||
*/
|
*/
|
||||||
void setupScrollArea();
|
void setupScrollArea();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the content widget with the registered widget factory and
|
||||||
|
* returns true on success.
|
||||||
|
*/
|
||||||
|
bool createWidgetFromFactory();
|
||||||
};
|
};
|
||||||
// struct DockWidgetPrivate
|
// struct DockWidgetPrivate
|
||||||
|
|
||||||
@ -130,10 +143,23 @@ DockWidgetPrivate::DockWidgetPrivate(CDockWidget* _public) :
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void DockWidgetPrivate::showDockWidget()
|
void DockWidgetPrivate::showDockWidget()
|
||||||
{
|
{
|
||||||
|
if (!Widget)
|
||||||
|
{
|
||||||
|
if (!createWidgetFromFactory())
|
||||||
|
{
|
||||||
|
Q_ASSERT(!Features.testFlag(CDockWidget::DeleteContentOnClose)
|
||||||
|
&& "DeleteContentOnClose flag was set, but the widget "
|
||||||
|
"factory is missing or it doesn't return a valid QWidget.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!DockArea)
|
if (!DockArea)
|
||||||
{
|
{
|
||||||
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
|
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
|
||||||
FloatingWidget->resize(_this->size());
|
// We use the size hint of the content widget to provide a good
|
||||||
|
// initial size
|
||||||
|
FloatingWidget->resize(Widget ? Widget->sizeHint() : _this->sizeHint());
|
||||||
TabWidget->show();
|
TabWidget->show();
|
||||||
FloatingWidget->show();
|
FloatingWidget->show();
|
||||||
}
|
}
|
||||||
@ -165,6 +191,12 @@ void DockWidgetPrivate::hideDockWidget()
|
|||||||
{
|
{
|
||||||
TabWidget->hide();
|
TabWidget->hide();
|
||||||
updateParentDockArea();
|
updateParentDockArea();
|
||||||
|
|
||||||
|
if (Features.testFlag(CDockWidget::DeleteContentOnClose))
|
||||||
|
{
|
||||||
|
Widget->deleteLater();
|
||||||
|
Widget = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -218,6 +250,30 @@ void DockWidgetPrivate::setupScrollArea()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockWidgetPrivate::createWidgetFromFactory()
|
||||||
|
{
|
||||||
|
if (!Features.testFlag(CDockWidget::DeleteContentOnClose))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Factory)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* w = Factory->createWidget(_this);
|
||||||
|
if (!w)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_this->setWidget(w, Factory->insertMode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
|
CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
|
||||||
QFrame(parent),
|
QFrame(parent),
|
||||||
@ -288,6 +344,17 @@ void CDockWidget::setWidget(QWidget* widget, eInsertMode InsertMode)
|
|||||||
d->Widget->setProperty("dockWidgetContent", true);
|
d->Widget->setProperty("dockWidgetContent", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setWidgetFactory(FactoryFunc createWidget, eInsertMode insertMode)
|
||||||
|
{
|
||||||
|
if (d->Factory)
|
||||||
|
{
|
||||||
|
delete d->Factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Factory = new DockWidgetPrivate::WidgetFactory { createWidget, insertMode };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
QWidget* CDockWidget::takeWidget()
|
QWidget* CDockWidget::takeWidget()
|
||||||
@ -530,7 +597,8 @@ void CDockWidget::toggleViewInternal(bool Open)
|
|||||||
CDockWidget* TopLevelDockWidgetAfter = DockContainer
|
CDockWidget* TopLevelDockWidgetAfter = DockContainer
|
||||||
? DockContainer->topLevelDockWidget() : nullptr;
|
? DockContainer->topLevelDockWidget() : nullptr;
|
||||||
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetAfter, true);
|
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetAfter, true);
|
||||||
CFloatingDockContainer* FloatingContainer = DockContainer->floatingWidget();
|
CFloatingDockContainer* FloatingContainer = DockContainer
|
||||||
|
? DockContainer->floatingWidget() : nullptr;
|
||||||
if (FloatingContainer)
|
if (FloatingContainer)
|
||||||
{
|
{
|
||||||
FloatingContainer->updateWindowTitle();
|
FloatingContainer->updateWindowTitle();
|
||||||
|
@ -147,18 +147,19 @@ public:
|
|||||||
|
|
||||||
enum DockWidgetFeature
|
enum DockWidgetFeature
|
||||||
{
|
{
|
||||||
DockWidgetClosable = 0x01,///< dock widget has a close button
|
DockWidgetClosable = 0x001,///< dock widget has a close button
|
||||||
DockWidgetMovable = 0x02,///< dock widget is movable and can be moved to a new position in the current dock container
|
DockWidgetMovable = 0x002,///< dock widget is movable and can be moved to a new position in the current dock container
|
||||||
DockWidgetFloatable = 0x04,///< dock widget can be dragged into a floating window
|
DockWidgetFloatable = 0x004,///< dock widget can be dragged into a floating window
|
||||||
DockWidgetDeleteOnClose = 0x08, ///< deletes the dock widget when it is closed
|
DockWidgetDeleteOnClose = 0x008, ///< deletes the dock widget when it is closed
|
||||||
CustomCloseHandling = 0x10, ///< clicking the close button will not close the dock widget but emits the closeRequested() signal instead
|
CustomCloseHandling = 0x010, ///< clicking the close button will not close the dock widget but emits the closeRequested() signal instead
|
||||||
DockWidgetFocusable = 0x20, ///< if this is enabled, a dock widget can get focus highlighting
|
DockWidgetFocusable = 0x020, ///< if this is enabled, a dock widget can get focus highlighting
|
||||||
DockWidgetForceCloseWithArea = 0x40, ///< dock widget will be closed when the dock area hosting it is closed
|
DockWidgetForceCloseWithArea = 0x040, ///< dock widget will be closed when the dock area hosting it is closed
|
||||||
NoTab = 0x80, ///< dock widget tab will never be shown if this flag is set
|
NoTab = 0x080, ///< dock widget tab will never be shown if this flag is set
|
||||||
|
DeleteContentOnClose = 0x100, ///< 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.
|
||||||
DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable | DockWidgetFocusable,
|
DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable | DockWidgetFocusable,
|
||||||
AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose | CustomCloseHandling,
|
AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose | CustomCloseHandling,
|
||||||
DockWidgetAlwaysCloseAndDelete = DockWidgetForceCloseWithArea | DockWidgetDeleteOnClose,
|
DockWidgetAlwaysCloseAndDelete = DockWidgetForceCloseWithArea | DockWidgetDeleteOnClose,
|
||||||
NoDockWidgetFeatures = 0x00
|
NoDockWidgetFeatures = 0x000
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
|
Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
|
||||||
|
|
||||||
@ -254,7 +255,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Sets the widget for the dock widget to widget.
|
* Sets the widget for the dock widget to widget.
|
||||||
* The InsertMode defines how the widget is inserted into the dock widget.
|
* The InsertMode defines how the widget is inserted into the dock widget.
|
||||||
* The content of a dock widget should be resizable do a very small size to
|
* The content of a dock widget should be resizable to a very small size to
|
||||||
* prevent the dock widget from blocking the resizing. To ensure, that a
|
* prevent the dock widget from blocking the resizing. To ensure, that a
|
||||||
* dock widget can be resized very well, it is better to insert the content+
|
* dock widget can be resized very well, it is better to insert the content+
|
||||||
* widget into a scroll area or to provide a widget that is already a scroll
|
* widget into a scroll area or to provide a widget that is already a scroll
|
||||||
@ -270,6 +271,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setWidget(QWidget* widget, eInsertMode InsertMode = AutoScrollArea);
|
void setWidget(QWidget* widget, eInsertMode InsertMode = AutoScrollArea);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only used when the feature flag DeleteContentOnClose is set.
|
||||||
|
* Using the flag and setting a widget factory allows to free the resources
|
||||||
|
* of the widget of your application while retaining the position the next
|
||||||
|
* time you want to show your widget, unlike the flag DockWidgetDeleteOnClose
|
||||||
|
* which deletes the dock widget itself. Since we keep the dock widget, all
|
||||||
|
* regular features of ADS should work as normal, including saving and
|
||||||
|
* restoring the state of the docking system and using perspectives.
|
||||||
|
*/
|
||||||
|
using FactoryFunc = std::function<QWidget*(QWidget*)>;
|
||||||
|
void setWidgetFactory(FactoryFunc createWidget, eInsertMode InsertMode = AutoScrollArea);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the widget from the dock and give ownership back to the caller
|
* Remove the widget from the dock and give ownership back to the caller
|
||||||
*/
|
*/
|
||||||
@ -587,7 +600,8 @@ Q_SIGNALS:
|
|||||||
*/
|
*/
|
||||||
void featuresChanged(ads::CDockWidget::DockWidgetFeatures features);
|
void featuresChanged(ads::CDockWidget::DockWidgetFeatures features);
|
||||||
}; // class DockWidget
|
}; // class DockWidget
|
||||||
}
|
} // namespace ads
|
||||||
// namespace ads
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(ads::CDockWidget::DockWidgetFeatures)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#endif // DockWidgetH
|
#endif // DockWidgetH
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "DockOverlay.h"
|
#include "DockOverlay.h"
|
||||||
#include "DockManager.h"
|
#include "DockManager.h"
|
||||||
#include "IconProvider.h"
|
#include "IconProvider.h"
|
||||||
|
#include "DockFocusController.h"
|
||||||
|
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
@ -207,6 +208,14 @@ struct DockWidgetTabPrivate
|
|||||||
IconLabel->setVisible(true);
|
IconLabel->setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for access to the dock manager dock focus controller
|
||||||
|
*/
|
||||||
|
CDockFocusController* focusController() const
|
||||||
|
{
|
||||||
|
return DockWidget->dockManager()->dockFocusController();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
// struct DockWidgetTabPrivate
|
// struct DockWidgetTabPrivate
|
||||||
|
|
||||||
@ -234,6 +243,7 @@ void DockWidgetTabPrivate::createLayout()
|
|||||||
CloseButton->setObjectName("tabCloseButton");
|
CloseButton->setObjectName("tabCloseButton");
|
||||||
internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, TabCloseIcon);
|
internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, TabCloseIcon);
|
||||||
CloseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
CloseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
CloseButton->setFocusPolicy(Qt::NoFocus);
|
||||||
updateCloseButtonSizePolicy();
|
updateCloseButtonSizePolicy();
|
||||||
internal::setToolTip(CloseButton, QObject::tr("Close Tab"));
|
internal::setToolTip(CloseButton, QObject::tr("Close Tab"));
|
||||||
_this->connect(CloseButton, SIGNAL(clicked()), SIGNAL(closeRequested()));
|
_this->connect(CloseButton, SIGNAL(clicked()), SIGNAL(closeRequested()));
|
||||||
@ -331,10 +341,11 @@ CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) :
|
|||||||
setAttribute(Qt::WA_NoMousePropagation, true);
|
setAttribute(Qt::WA_NoMousePropagation, true);
|
||||||
d->DockWidget = DockWidget;
|
d->DockWidget = DockWidget;
|
||||||
d->createLayout();
|
d->createLayout();
|
||||||
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
|
setFocusPolicy(Qt::NoFocus);
|
||||||
|
/*if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
|
||||||
{
|
{
|
||||||
setFocusPolicy(Qt::ClickFocus);
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@ -353,6 +364,10 @@ void CDockWidgetTab::mousePressEvent(QMouseEvent* ev)
|
|||||||
ev->accept();
|
ev->accept();
|
||||||
d->saveDragStartMousePosition(internal::globalPositionOf(ev));
|
d->saveDragStartMousePosition(internal::globalPositionOf(ev));
|
||||||
d->DragState = DraggingMousePressed;
|
d->DragState = DraggingMousePressed;
|
||||||
|
if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting))
|
||||||
|
{
|
||||||
|
d->focusController()->setDockWidgetTabFocused(this);
|
||||||
|
}
|
||||||
Q_EMIT clicked();
|
Q_EMIT clicked();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -377,17 +392,31 @@ void CDockWidgetTab::mouseReleaseEvent(QMouseEvent* ev)
|
|||||||
// End of tab moving, emit signal
|
// End of tab moving, emit signal
|
||||||
if (d->DockArea)
|
if (d->DockArea)
|
||||||
{
|
{
|
||||||
|
ev->accept();
|
||||||
Q_EMIT moved(internal::globalPositionOf(ev));
|
Q_EMIT moved(internal::globalPositionOf(ev));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DraggingFloatingWidget:
|
case DraggingFloatingWidget:
|
||||||
|
ev->accept();
|
||||||
d->FloatingWidget->finishDragging();
|
d->FloatingWidget->finishDragging();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:; // do nothing
|
default:; // do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ev->button() == Qt::MiddleButton)
|
||||||
|
{
|
||||||
|
if (CDockManager::testConfigFlag(CDockManager::MiddleMouseButtonClosesTab) && d->DockWidget->features().testFlag(CDockWidget::DockWidgetClosable))
|
||||||
|
{
|
||||||
|
// Only attempt to close if the mouse is still
|
||||||
|
// on top of the widget, to allow the user to cancel.
|
||||||
|
if (rect().contains(mapFromGlobal(QCursor::pos()))) {
|
||||||
|
ev->accept();
|
||||||
|
Q_EMIT closeRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Super::mouseReleaseEvent(ev);
|
Super::mouseReleaseEvent(ev);
|
||||||
}
|
}
|
||||||
@ -515,7 +544,8 @@ void CDockWidgetTab::setActiveTab(bool active)
|
|||||||
bool UpdateFocusStyle = false;
|
bool UpdateFocusStyle = false;
|
||||||
if (active && !hasFocus())
|
if (active && !hasFocus())
|
||||||
{
|
{
|
||||||
setFocus(Qt::OtherFocusReason);
|
//setFocus(Qt::OtherFocusReason);
|
||||||
|
d->focusController()->setDockWidgetTabFocused(this);
|
||||||
UpdateFocusStyle = true;
|
UpdateFocusStyle = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,6 +641,8 @@ QString CDockWidgetTab::text() const
|
|||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockWidgetTab::mouseDoubleClickEvent(QMouseEvent *event)
|
void CDockWidgetTab::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
{
|
{
|
||||||
// If this is the last dock area in a dock container it does not make
|
// If this is the last dock area in a dock container it does not make
|
||||||
// sense to move it to a new floating widget and leave this one
|
// sense to move it to a new floating widget and leave this one
|
||||||
@ -618,9 +650,11 @@ void CDockWidgetTab::mouseDoubleClickEvent(QMouseEvent *event)
|
|||||||
if ((!d->DockArea->dockContainer()->isFloating() || d->DockArea->dockWidgetsCount() > 1)
|
if ((!d->DockArea->dockContainer()->isFloating() || d->DockArea->dockWidgetsCount() > 1)
|
||||||
&& d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
&& d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
|
||||||
{
|
{
|
||||||
|
event->accept();
|
||||||
d->saveDragStartMousePosition(internal::globalPositionOf(event));
|
d->saveDragStartMousePosition(internal::globalPositionOf(event));
|
||||||
d->startFloating(DraggingInactive);
|
d->startFloating(DraggingInactive);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Super::mouseDoubleClickEvent(event);
|
Super::mouseDoubleClickEvent(event);
|
||||||
}
|
}
|
||||||
@ -677,6 +711,9 @@ bool CDockWidgetTab::event(QEvent *e)
|
|||||||
{
|
{
|
||||||
const auto text = toolTip();
|
const auto text = toolTip();
|
||||||
d->TitleLabel->setToolTip(text);
|
d->TitleLabel->setToolTip(text);
|
||||||
|
if (d->IconLabel) {
|
||||||
|
d->IconLabel->setToolTip(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return Super::event(e);
|
return Super::event(e);
|
||||||
|
@ -163,8 +163,8 @@ void CElidingLabel::resizeEvent(QResizeEvent *event)
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
QSize CElidingLabel::minimumSizeHint() const
|
QSize CElidingLabel::minimumSizeHint() const
|
||||||
{
|
{
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||||
bool HasPixmap = !pixmap().isNull();
|
bool HasPixmap = !pixmap(Qt::ReturnByValue).isNull();
|
||||||
#else
|
#else
|
||||||
bool HasPixmap = (pixmap() != nullptr);
|
bool HasPixmap = (pixmap() != nullptr);
|
||||||
#endif
|
#endif
|
||||||
@ -185,8 +185,8 @@ QSize CElidingLabel::minimumSizeHint() const
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
QSize CElidingLabel::sizeHint() const
|
QSize CElidingLabel::sizeHint() const
|
||||||
{
|
{
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||||
bool HasPixmap = !pixmap().isNull();
|
bool HasPixmap = !pixmap(Qt::ReturnByValue).isNull();
|
||||||
#else
|
#else
|
||||||
bool HasPixmap = (pixmap() != nullptr);
|
bool HasPixmap = (pixmap() != nullptr);
|
||||||
#endif
|
#endif
|
||||||
|
@ -373,6 +373,7 @@ struct FloatingDockContainerPrivate
|
|||||||
CDockAreaWidget *SingleDockArea = nullptr;
|
CDockAreaWidget *SingleDockArea = nullptr;
|
||||||
QPoint DragStartPos;
|
QPoint DragStartPos;
|
||||||
bool Hiding = false;
|
bool Hiding = false;
|
||||||
|
bool AutoHideChildren = true;
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
QWidget* MouseEventHandler = nullptr;
|
QWidget* MouseEventHandler = nullptr;
|
||||||
CFloatingWidgetTitleBar* TitleBar = nullptr;
|
CFloatingWidgetTitleBar* TitleBar = nullptr;
|
||||||
@ -841,6 +842,8 @@ void CFloatingDockContainer::hideEvent(QHideEvent *event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( d->AutoHideChildren )
|
||||||
|
{
|
||||||
d->Hiding = true;
|
d->Hiding = true;
|
||||||
for ( auto DockArea : d->DockContainer->openedDockAreas() )
|
for ( auto DockArea : d->DockContainer->openedDockAreas() )
|
||||||
{
|
{
|
||||||
@ -851,6 +854,7 @@ void CFloatingDockContainer::hideEvent(QHideEvent *event)
|
|||||||
}
|
}
|
||||||
d->Hiding = false;
|
d->Hiding = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@ -1035,6 +1039,18 @@ QList<CDockWidget*> CFloatingDockContainer::dockWidgets() const
|
|||||||
return d->DockContainer->dockWidgets();
|
return d->DockContainer->dockWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::hideAndDeleteLater()
|
||||||
|
{
|
||||||
|
// Widget has been redocked, so it must be hidden right way (see
|
||||||
|
// https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/351)
|
||||||
|
// but AutoHideChildren must be set to false because "this" still contains
|
||||||
|
// dock widgets that shall not be toggled hidden.
|
||||||
|
d->AutoHideChildren = false;
|
||||||
|
hide();
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CFloatingDockContainer::finishDragging()
|
void CFloatingDockContainer::finishDragging()
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@ class CDockingStateReader;
|
|||||||
* This interface is used for opaque and non-opaque undocking. If opaque
|
* This interface is used for opaque and non-opaque undocking. If opaque
|
||||||
* undocking is used, the a real CFloatingDockContainer widget will be created
|
* undocking is used, the a real CFloatingDockContainer widget will be created
|
||||||
*/
|
*/
|
||||||
class IFloatingWidget
|
class ADS_EXPORT IFloatingWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IFloatingWidget() = default;
|
virtual ~IFloatingWidget() = default;
|
||||||
@ -258,6 +258,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
QList<CDockWidget*> dockWidgets() const;
|
QList<CDockWidget*> dockWidgets() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function hides the floating bar instantely and delete it later.
|
||||||
|
*/
|
||||||
|
void hideAndDeleteLater();
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
/**
|
/**
|
||||||
* This is a function that responds to FloatingWidgetTitleBar::maximizeRequest()
|
* This is a function that responds to FloatingWidgetTitleBar::maximizeRequest()
|
||||||
|
@ -39,13 +39,11 @@
|
|||||||
#include "ads_globals.h"
|
#include "ads_globals.h"
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include <QX11Info>
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
@ -57,10 +55,31 @@ static QString _window_manager;
|
|||||||
static QHash<QString, xcb_atom_t> _xcb_atom_cache;
|
static QHash<QString, xcb_atom_t> _xcb_atom_cache;
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool is_platform_x11()
|
||||||
|
{
|
||||||
|
return QGuiApplication::platformName() == QLatin1String("xcb");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
xcb_connection_t* x11_connection()
|
||||||
|
{
|
||||||
|
if (!qApp)
|
||||||
|
return nullptr;
|
||||||
|
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||||
|
if (!native)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
void *connection = native->nativeResourceForIntegration(QByteArray("connection"));
|
||||||
|
return reinterpret_cast<xcb_connection_t *>(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
xcb_atom_t xcb_get_atom(const char *name)
|
xcb_atom_t xcb_get_atom(const char *name)
|
||||||
{
|
{
|
||||||
if (!QX11Info::isPlatformX11())
|
if (!is_platform_x11())
|
||||||
{
|
{
|
||||||
return XCB_ATOM_NONE;
|
return XCB_ATOM_NONE;
|
||||||
}
|
}
|
||||||
@ -69,7 +88,7 @@ xcb_atom_t xcb_get_atom(const char *name)
|
|||||||
{
|
{
|
||||||
return _xcb_atom_cache[key];
|
return _xcb_atom_cache[key];
|
||||||
}
|
}
|
||||||
xcb_connection_t *connection = QX11Info::connection();
|
xcb_connection_t *connection = x11_connection();
|
||||||
xcb_intern_atom_cookie_t request = xcb_intern_atom(connection, 1, strlen(name), name);
|
xcb_intern_atom_cookie_t request = xcb_intern_atom(connection, 1, strlen(name), name);
|
||||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, request, NULL);
|
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, request, NULL);
|
||||||
if (!reply)
|
if (!reply)
|
||||||
@ -93,7 +112,7 @@ xcb_atom_t xcb_get_atom(const char *name)
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void xcb_update_prop(bool set, WId window, const char *type, const char *prop, const char *prop2)
|
void xcb_update_prop(bool set, WId window, const char *type, const char *prop, const char *prop2)
|
||||||
{
|
{
|
||||||
auto connection = QX11Info::connection();
|
auto connection = x11_connection();
|
||||||
xcb_atom_t type_atom = xcb_get_atom(type);
|
xcb_atom_t type_atom = xcb_get_atom(type);
|
||||||
xcb_atom_t prop_atom = xcb_get_atom(prop);
|
xcb_atom_t prop_atom = xcb_get_atom(prop);
|
||||||
xcb_client_message_event_t event;
|
xcb_client_message_event_t event;
|
||||||
@ -118,11 +137,11 @@ void xcb_update_prop(bool set, WId window, const char *type, const char *prop, c
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
xcb_get_property_reply_t* _xcb_get_props(WId window, const char *type, unsigned int atom_type)
|
xcb_get_property_reply_t* _xcb_get_props(WId window, const char *type, unsigned int atom_type)
|
||||||
{
|
{
|
||||||
if (!QX11Info::isPlatformX11())
|
if (!is_platform_x11())
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
xcb_connection_t *connection = QX11Info::connection();
|
xcb_connection_t *connection = x11_connection();
|
||||||
xcb_atom_t type_atom = xcb_get_atom(type);
|
xcb_atom_t type_atom = xcb_get_atom(type);
|
||||||
if (type_atom == XCB_ATOM_NONE)
|
if (type_atom == XCB_ATOM_NONE)
|
||||||
{
|
{
|
||||||
@ -191,7 +210,7 @@ bool xcb_dump_props(WId window, const char *type)
|
|||||||
QVector<xcb_atom_t> atoms;
|
QVector<xcb_atom_t> atoms;
|
||||||
xcb_get_prop_list(window, type, atoms, XCB_ATOM_ATOM);
|
xcb_get_prop_list(window, type, atoms, XCB_ATOM_ATOM);
|
||||||
qDebug() << "\n\n!!!" << type << " - " << atoms.length();
|
qDebug() << "\n\n!!!" << type << " - " << atoms.length();
|
||||||
xcb_connection_t *connection = QX11Info::connection();
|
xcb_connection_t *connection = x11_connection();
|
||||||
for (auto atom : atoms)
|
for (auto atom : atoms)
|
||||||
{
|
{
|
||||||
auto foo = xcb_get_atom_name(connection, atom);
|
auto foo = xcb_get_atom_name(connection, atom);
|
||||||
@ -206,7 +225,7 @@ bool xcb_dump_props(WId window, const char *type)
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void xcb_add_prop(bool state, WId window, const char *type, const char *prop)
|
void xcb_add_prop(bool state, WId window, const char *type, const char *prop)
|
||||||
{
|
{
|
||||||
if (!QX11Info::isPlatformX11())
|
if (!is_platform_x11())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -227,7 +246,7 @@ void xcb_add_prop(bool state, WId window, const char *type, const char *prop)
|
|||||||
{
|
{
|
||||||
atoms.remove(index);
|
atoms.remove(index);
|
||||||
}
|
}
|
||||||
xcb_connection_t *connection = QX11Info::connection();
|
xcb_connection_t *connection = x11_connection();
|
||||||
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, type_atom, XCB_ATOM_ATOM, 32, atoms.count(), atoms.constData());
|
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, type_atom, XCB_ATOM_ATOM, 32, atoms.count(), atoms.constData());
|
||||||
xcb_flush(connection);
|
xcb_flush(connection);
|
||||||
}
|
}
|
||||||
@ -238,11 +257,11 @@ QString detectWindowManagerX11()
|
|||||||
{
|
{
|
||||||
// Tries to detect the windowmanager via X11.
|
// Tries to detect the windowmanager via X11.
|
||||||
// See: https://specifications.freedesktop.org/wm-spec/1.3/ar01s03.html#idm46018259946000
|
// See: https://specifications.freedesktop.org/wm-spec/1.3/ar01s03.html#idm46018259946000
|
||||||
if (!QX11Info::isPlatformX11())
|
if (!is_platform_x11())
|
||||||
{
|
{
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
xcb_connection_t *connection = QX11Info::connection();
|
xcb_connection_t *connection = x11_connection();
|
||||||
xcb_screen_t *first_screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
|
xcb_screen_t *first_screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
|
||||||
if(!first_screen)
|
if(!first_screen)
|
||||||
{
|
{
|
||||||
|
@ -308,5 +308,6 @@ void repolishStyle(QWidget* w, eRepolishChildOptions Options = RepolishIgnoreChi
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(ads::DockWidgetAreas)
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
#endif // ads_globalsH
|
#endif // ads_globalsH
|
||||||
|
@ -73,8 +73,8 @@ SOURCES += \
|
|||||||
unix:!macx {
|
unix:!macx {
|
||||||
HEADERS += linux/FloatingWidgetTitleBar.h
|
HEADERS += linux/FloatingWidgetTitleBar.h
|
||||||
SOURCES += linux/FloatingWidgetTitleBar.cpp
|
SOURCES += linux/FloatingWidgetTitleBar.cpp
|
||||||
QT += x11extras
|
|
||||||
LIBS += -lxcb
|
LIBS += -lxcb
|
||||||
|
QT += gui-private
|
||||||
}
|
}
|
||||||
|
|
||||||
isEmpty(PREFIX){
|
isEmpty(PREFIX){
|
||||||
|
Loading…
Reference in New Issue
Block a user