Compare commits

..

27 Commits
2.0.0 ... 2.1.0

Author SHA1 Message Date
Uwe Kindler
72ee4a53df Improved documentation, made a lot of member functions protected to make it clearer which functions the user is allowed to use, the CDockWidget constructor now sets the objectName() to the given title, so there is no need to call setObjectName() explicitely if the title is static and unique 2018-08-29 08:47:05 +02:00
Uwe Kindler
0b963d1540 Added support for stylesheet styling of overlay cross icons, fixed problem when dragging a floating widget that was maximized, removed som std::cout debug output 2018-08-28 13:25:44 +02:00
Uwe Kindler
9cd2584de5 Added support for display of dock widget icons in DockArea tab menus 2018-08-27 15:40:01 +02:00
Uwe Kindler
3f40c997e5 Improved and fixed handling of CDockWidget::DockWidgetMovable - moving the tab in the tabbar is always allowed, only moving the complete dock widget can be blocked by clearing this flag 2018-08-24 14:04:21 +02:00
Uwe Kindler
6b93ae9c39 Some refactoring to improve code clarity, renamed DockWidgetTitleBar into DockWidgetTab because in the GUI it is a tab, created new class CDockAreaTabBar for the tabbar of a dock area 2018-08-24 13:41:58 +02:00
githubuser0xFFFF
f5b3c0556d Merge pull request #8 from Opostol/master
DockWidgetClosable now prevents Floating Dock Windows from closing
2018-08-14 11:57:01 +02:00
Opostol
5b3841a038 DockWidgetClosable now prevents Floating Dock Windows from closing
Also std::cout were replaced with common used qDebug()
2018-08-10 18:02:29 +03:00
githubuser0xFFFF
9d00a278e6 Merge pull request #7 from Opostol/master
DockWidgetMovable implemented, some signals introduced
2018-08-10 14:23:00 +02:00
Opostol
b470dd5f99 DockManager stateChanged signal introduced(part2) 2018-08-10 15:12:38 +03:00
Opostol
7b4a19b943 DockManager stateChanged signal introduced(part1)
Can be helpful to reconnect to area signals
2018-08-10 15:11:57 +03:00
Opostol
8eceed9aa3 Dock area currentChanging signal introduced(part2) 2018-08-10 14:48:20 +03:00
Opostol
4188d69356 Dock area currentChanging signal introduced(part1)
currentChanging signal helps to save previous layout state before tab will be changed
2018-08-10 14:46:57 +03:00
Opostol
3fc7c195c3 DockWidgetMovable feature implemented
In my implementation DockWidgetMovable feature also not allows tab to float.
2018-08-10 13:54:09 +03:00
Uwe Kindler
f823b67a4a Added support for export of shared library functions to support MSVC builds 2018-07-17 15:11:49 +02:00
githubuser0xFFFF
064cab405a Merge pull request #4 from emoon/mac-compile-warning-fixes
Compile and warning fixes for macOS
2018-05-07 07:37:54 +02:00
Daniel Collin
75ad302d21 Compile and warning fixes for macOS
Number of warnings like this has been fixed

DockWidget.h:62:9: warning: class 'DockContainerWidgetPrivate' was previously declared as a struct [-Wmismatched-tags]

Also in ads_globals.cpp Clang didn’t like how that code setup so I changed it to what I think is the correct way. This would be good to get verified.
2018-05-06 12:45:46 +02:00
Uwe Kindler
18a4f17fbf Fixed a typo in README.md 2018-02-13 12:56:33 +01:00
Uwe Kindler
6266cd3290 Updated README.md and removed superfluous files 2018-02-13 12:50:35 +01:00
Uwe Kindler
8a401ebd68 Fixed a bug in restore functionality that caused application crash, added initial support for perspectives 2018-02-13 12:00:58 +01:00
Uwe Kindler
805e97946e Fixed some issues with restoreState function 2018-02-13 07:28:38 +01:00
Uwe Kindler
e878bb47ed Added support for setting the DockWidget icon - this icon is shown in the title bar or when using the ToggleViewAction 2018-01-02 08:01:23 +01:00
Uwe Kindler
dae852d9f9 Implemented XML serialization and loading of docking state 2017-12-29 18:18:16 +01:00
Uwe Kindler
8a014a6c2d Fixed typo 2017-09-11 10:16:31 +02:00
Uwe Kindler
9676eeb1bf Fixed removeDockArea function, fixed bug when docking into empty container, fix several small bugs, improved code documentation 2017-09-06 15:45:22 +02:00
Uwe Kindler
412f13e1c4 Implemented fix to prevent display of drop overlays and overlay icons when resizing a floating widget 2017-09-05 14:03:43 +02:00
Uwe Kindler
11a30806f6 Merge branch 'master' of https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System 2017-09-04 08:21:36 +02:00
Uwe Kindler
b9257bbe93 Some small fixes to ignore title bar docking if we are over a container drop indicator - this caused come confusion during docking 2017-09-01 16:14:43 +02:00
36 changed files with 1979 additions and 943 deletions

View File

@@ -1,14 +0,0 @@
--style=allman
--indent=force-tab=4
--align-pointer=type
--align-reference=type
--pad-oper
--pad-header
--unpad-paren
--remove-comment-prefix
--mode=c

View File

@@ -24,6 +24,8 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/QtAdvancedDockingSystem/demo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/QtAdvancedDockingSystem/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include/QtCore&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include/QtWidgets&quot;"/>
</option>
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1249325593" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
@@ -33,8 +35,10 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/QtAdvancedDockingSystem/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/QtAdvancedDockingSystem/demo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include/QtCore&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include/QtWidgets&quot;"/>
</option>
<option id="gnu.cpp.compiler.option.preprocessor.def.56223209" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols"/>
<option id="gnu.cpp.compiler.option.preprocessor.def.56223209" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false"/>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1318830536" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.compiler.mingw.base.389117097" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.mingw.base">
@@ -42,8 +46,10 @@
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/QtAdvancedDockingSystem/demo}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/QtAdvancedDockingSystem/src}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include/QtCore&quot;"/>
<listOptionValue builtIn="false" value="&quot;${QTDIR}/include/QtWidgets&quot;"/>
</option>
<option id="gnu.c.compiler.option.preprocessor.def.symbols.806805509" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false" valueType="definedSymbols"/>
<option id="gnu.c.compiler.option.preprocessor.def.symbols.806805509" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" useByScannerDiscovery="false"/>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1568363924" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.linker.mingw.base.1734874312" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.base"/>

View File

@@ -2,10 +2,7 @@
<project>
<configuration id="cdt.managedbuild.toolchain.gnu.mingw.base.1119687795" name="Default">
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider class="org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorMinGW" console="false" env-hash="-445604897520096165" 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 -std=c++14 &quot;${INPUTS}&quot;" 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.GCCBuiltinSpecsDetectorMinGW" ref="shared-provider"/>
<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"/>

View File

@@ -1,24 +0,0 @@
language:
- cpp
compiler:
- g++
addons:
apt:
sources:
- ubuntu-sdk-team
packages:
- qt5-qmake
- qtbase5-dev
- qtdeclarative5-dev
- libqt5webkit5-dev
- libsqlite3-dev
script:
- qmake -qt=qt5 -v
- qmake -qt=qt5 -r build.pro
- make
#- sudo apt-get install -qq qtbase5-dev qtdeclarative5-dev libqt5webkit5-dev libsqlite3-dev
#- sudo apt-get install -qq qt5-default qttools5-dev-tools

Binary file not shown.

Binary file not shown.

View File

@@ -36,6 +36,14 @@ a floating widget or from one dock area to another one.
![Grouped dragging](grouped-dragging.png)
### Perspectives for fast switching of the complete main window layout
A perspective defines the set and layout of dock windows in the main
window. You can save the current layout of the dockmanager into a named
perspective to make your own custom perspective. Later you can simply
select a perspective from the perspective list to quickly switch the complete
main window layout.
![Perspective](perspectives.png)
## Tested Compatible Environments
- Windows 10

327
demo/MainWindow.cpp Normal file
View File

@@ -0,0 +1,327 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file MainWindow.cpp
/// \author Uwe Kindler
/// \date 13.02.2018
/// \brief Implementation of CMainWindow demo class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include <MainWindow.h>
#include "ui_mainwindow.h"
#include <iostream>
#include <QTime>
#include <QLabel>
#include <QTextEdit>
#include <QCalendarWidget>
#include <QFrame>
#include <QTreeView>
#include <QFileSystemModel>
#include <QBoxLayout>
#include <QSettings>
#include <QDockWidget>
#include <QDebug>
#include <QResizeEvent>
#include <QAction>
#include <QWidgetAction>
#include <QComboBox>
#include <QInputDialog>
#include <QMap>
#include <QElapsedTimer>
#include "DockManager.h"
#include "DockWidget.h"
#include "DockAreaWidget.h"
//============================================================================
static ads::CDockWidget* createLongTextLabelDockWidget(QMenu* ViewMenu)
{
static int LabelCount = 0;
QLabel* l = new QLabel();
l->setWordWrap(true);
l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
l->setText(QString("Label %1 %2 - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "
"Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque "
"penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
"Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. "
"Nulla consequat massa quis enim. Donec pede justo, fringilla vel, "
"aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, "
"imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede "
"mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum "
"semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, "
"porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, "
"dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla "
"ut metus varius laoreet.")
.arg(LabelCount)
.arg(QTime::currentTime().toString("hh:mm:ss:zzz")));
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++));
DockWidget->setWidget(l);
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
//============================================================================
static ads::CDockWidget* createCalendarDockWidget(QMenu* ViewMenu)
{
static int CalendarCount = 0;
QCalendarWidget* w = new QCalendarWidget();
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
DockWidget->setWidget(w);
DockWidget->setToggleViewActionMode(ads::CDockWidget::ActionModeShow);
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
//============================================================================
static ads::CDockWidget* createFileSystemTreeDockWidget(QMenu* ViewMenu)
{
static int FileSystemCount = 0;
QTreeView* w = new QTreeView();
w->setFrameShape(QFrame::NoFrame);
QFileSystemModel* m = new QFileSystemModel(w);
m->setRootPath(QDir::currentPath());
w->setModel(m);
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1").arg(FileSystemCount++));
DockWidget->setWidget(w);
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
//============================================================================
/**
* Private data class pimpl
*/
struct MainWindowPrivate
{
CMainWindow* _this;
Ui::MainWindow ui;
QAction* SavePerspectiveAction = nullptr;
QWidgetAction* PerspectiveListAction = nullptr;
QComboBox* PerspectiveComboBox = nullptr;;
ads::CDockManager* DockManager = nullptr;
MainWindowPrivate(CMainWindow* _public) : _this(_public) {}
/**
* Creates the toolbar actions
*/
void createActions();
/**
* Fill the dock manager with dock widgets
*/
void createContent();
/**
* Saves the dock manager state and the main window geometry
*/
void saveState();
/**
* Save the list of perspectives
*/
void savePerspectives();
/**
* Restores the dock manager state
*/
void restoreState();
/**
* Restore the perspective listo of the dock manager
*/
void restorePerspectives();
};
//============================================================================
void MainWindowPrivate::createContent()
{
// Test container docking
QMenu* ViewMenu = ui.menuView;
auto DockWidget = createCalendarDockWidget(ViewMenu);
DockWidget->setIcon(_this->style()->standardIcon(QStyle::SP_DialogOpenButton));
DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
DockManager->addDockWidget(ads::LeftDockWidgetArea, createLongTextLabelDockWidget(ViewMenu));
DockManager->addDockWidget(ads::BottomDockWidgetArea, createFileSystemTreeDockWidget(ViewMenu));
auto FileSystemWidget = createFileSystemTreeDockWidget(ViewMenu);
FileSystemWidget->setFeature(ads::CDockWidget::DockWidgetMovable, false);
auto TopDockArea = DockManager->addDockWidget(ads::TopDockWidgetArea, FileSystemWidget);
DockWidget = createCalendarDockWidget(ViewMenu);
DockWidget->setFeature(ads::CDockWidget::DockWidgetClosable, false);
DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, TopDockArea);
// Test dock area docking
auto RighDockArea = DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), TopDockArea);
DockManager->addDockWidget(ads::TopDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
auto BottomDockArea = DockManager->addDockWidget(ads::BottomDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), BottomDockArea);
}
//============================================================================
void MainWindowPrivate::createActions()
{
ui.toolBar->addAction(ui.actionSaveState);
ui.actionSaveState->setIcon(_this->style()->standardIcon(QStyle::SP_DialogSaveButton));
ui.toolBar->addAction(ui.actionRestoreState);
ui.actionRestoreState->setIcon(_this->style()->standardIcon(QStyle::SP_DialogOpenButton));
SavePerspectiveAction = new QAction("Save Perspective", _this);
_this->connect(SavePerspectiveAction, SIGNAL(triggered()), SLOT(savePerspective()));
PerspectiveListAction = new QWidgetAction(_this);
PerspectiveComboBox = new QComboBox(_this);
PerspectiveComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
PerspectiveComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
PerspectiveListAction->setDefaultWidget(PerspectiveComboBox);
ui.toolBar->addSeparator();
ui.toolBar->addAction(PerspectiveListAction);
ui.toolBar->addAction(SavePerspectiveAction);
}
//============================================================================
void MainWindowPrivate::saveState()
{
QSettings Settings("Settings.ini", QSettings::IniFormat);
Settings.setValue("mainWindow/Geometry", _this->saveGeometry());
Settings.setValue("mainWindow/State", _this->saveState());
Settings.setValue("mainWindow/DockingState", DockManager->saveState());
}
//============================================================================
void MainWindowPrivate::restoreState()
{
QSettings Settings("Settings.ini", QSettings::IniFormat);
_this->restoreGeometry(Settings.value("mainWindow/Geometry").toByteArray());
_this->restoreState(Settings.value("mainWindow/State").toByteArray());
DockManager->restoreState(Settings.value("mainWindow/DockingState").toByteArray());
}
//============================================================================
void MainWindowPrivate::savePerspectives()
{
QSettings Settings("Settings.ini", QSettings::IniFormat);
DockManager->savePerspectives(Settings);
}
//============================================================================
void MainWindowPrivate::restorePerspectives()
{
QSettings Settings("Settings.ini", QSettings::IniFormat);
DockManager->loadPerspectives(Settings);
PerspectiveComboBox->clear();
PerspectiveComboBox->addItems(DockManager->perspectiveNames());
}
//============================================================================
CMainWindow::CMainWindow(QWidget *parent) :
QMainWindow(parent),
d(new MainWindowPrivate(this))
{
d->ui.setupUi(this);
d->createActions();
// Now create the dock manager and its content
d->DockManager = new ads::CDockManager(this);
connect(d->PerspectiveComboBox, SIGNAL(activated(const QString&)),
d->DockManager, SLOT(openPerspective(const QString&)));
d->createContent();
// Default window geometry
resize(800, 600);
d->restoreState();
d->restorePerspectives();
}
//============================================================================
CMainWindow::~CMainWindow()
{
delete d;
}
//============================================================================
void CMainWindow::closeEvent(QCloseEvent* event)
{
d->saveState();
QMainWindow::closeEvent(event);
}
//============================================================================
void CMainWindow::on_actionSaveState_triggered(bool)
{
qDebug() << "MainWindow::on_actionSaveState_triggered";
d->saveState();
}
//============================================================================
void CMainWindow::on_actionRestoreState_triggered(bool)
{
qDebug() << "MainWindow::on_actionRestoreState_triggered";
d->restoreState();
}
//============================================================================
void CMainWindow::savePerspective()
{
std::cout << "savePerspective" << std::endl;
QString PerspectiveName = QInputDialog::getText(this, "Save Perspective", "Enter unique name:");
if (PerspectiveName.isEmpty())
{
return;
}
d->DockManager->addPerspective(PerspectiveName);
QSignalBlocker Blocker(d->PerspectiveComboBox);
d->PerspectiveComboBox->clear();
d->PerspectiveComboBox->addItems(d->DockManager->perspectiveNames());
d->PerspectiveComboBox->setCurrentText(PerspectiveName);
d->savePerspectives();
}

63
demo/MainWindow.h Normal file
View File

@@ -0,0 +1,63 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file MainWindow.h
/// \author Uwe Kindler
/// \date 13.02.2018
/// \brief Declaration of CMainWindow class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include <QMainWindow>
struct MainWindowPrivate;
/**
* Simple main window for demo
*/
class CMainWindow : public QMainWindow
{
Q_OBJECT
private:
MainWindowPrivate* d;///< private data - pimpl
friend struct MainWindowPrivate;
protected:
virtual void closeEvent(QCloseEvent* event) override;
public:
explicit CMainWindow(QWidget *parent = 0);
virtual ~CMainWindow();
private slots:
void on_actionSaveState_triggered(bool);
void on_actionRestoreState_triggered(bool);
void savePerspective();
};
#endif // MAINWINDOW_H

View File

@@ -4,24 +4,16 @@ ADS_OUT_ROOT = $${OUT_PWD}/..
TARGET = AdvancedDockingSystemDemo
DESTDIR = $${ADS_OUT_ROOT}/lib
QT += core gui widgets
CONFIG *= c++14
windows {
# MinGW
*-g++* {
QMAKE_CXXFLAGS += -std=c++11
}
# MSVC
*-msvc* {
}
}
SOURCES += \
main.cpp \
mainwindow.cpp
MainWindow.cpp
HEADERS += \
mainwindow.h
MainWindow.h
FORMS += \
mainwindow.ui

View File

@@ -1,3 +1,4 @@
#include <MainWindow.h>
#include <QString>
#include <QFile>
#include <QApplication>
@@ -5,7 +6,6 @@
#include <memory>
#include "mainwindow.h"
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
@@ -41,7 +41,7 @@ int main(int argc, char *argv[])
qInstallMessageHandler(myMessageOutput);
qDebug() << "Message handler test";
MainWindow mw;
CMainWindow mw;
mw.show();
return a.exec();
}

View File

@@ -1,148 +0,0 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTime>
#include <QLabel>
#include <QTextEdit>
#include <QCalendarWidget>
#include <QFrame>
#include <QTreeView>
#include <QFileSystemModel>
#include <QBoxLayout>
#include <QSettings>
#include <QDockWidget>
#include <QDebug>
#include "DockManager.h"
#include "DockWidget.h"
#include "DockAreaWidget.h"
static ads::CDockWidget* createLongTextLabelDockWidget(QMenu* ViewMenu)
{
static int LabelCount = 0;
QLabel* l = new QLabel();
l->setWordWrap(true);
l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
l->setText(QString("Label %1 %2 - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "
"Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque "
"penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
"Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. "
"Nulla consequat massa quis enim. Donec pede justo, fringilla vel, "
"aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, "
"imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede "
"mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum "
"semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, "
"porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, "
"dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla "
"ut metus varius laoreet.")
.arg(LabelCount)
.arg(QTime::currentTime().toString("hh:mm:ss:zzz")));
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++));
DockWidget->setWidget(l);
DockWidget->setObjectName(DockWidget->windowTitle());
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
static ads::CDockWidget* createCalendarDockWidget(QMenu* ViewMenu)
{
static int CalendarCount = 0;
QCalendarWidget* w = new QCalendarWidget();
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Calendar %1").arg(CalendarCount++));
DockWidget->setWidget(w);
DockWidget->setObjectName(DockWidget->windowTitle());
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
static ads::CDockWidget* createFileSystemTreeDockWidget(QMenu* ViewMenu)
{
static int FileSystemCount = 0;
QTreeView* w = new QTreeView();
w->setFrameShape(QFrame::NoFrame);
QFileSystemModel* m = new QFileSystemModel(w);
m->setRootPath(QDir::currentPath());
w->setModel(m);
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1").arg(FileSystemCount++));
DockWidget->setWidget(w);
DockWidget->setObjectName(DockWidget->windowTitle());
ViewMenu->addAction(DockWidget->toggleViewAction());
return DockWidget;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_DockManager = new ads::CDockManager(this);
createContent();
// Default window geometry
resize(800, 600);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::createContent()
{
// Test container docking
QMenu* ViewMenu = this->ui->menuView;
auto DockWidget = createCalendarDockWidget(ViewMenu);
DockWidget->setFeatures(DockWidget->features().setFlag(ads::CDockWidget::DockWidgetClosable, false));
m_DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget);
m_DockManager->addDockWidget(ads::LeftDockWidgetArea, createLongTextLabelDockWidget(ViewMenu));
m_DockManager->addDockWidget(ads::BottomDockWidgetArea, createFileSystemTreeDockWidget(ViewMenu));
auto TopDockArea = m_DockManager->addDockWidget(ads::TopDockWidgetArea, createFileSystemTreeDockWidget(ViewMenu));
DockWidget = createCalendarDockWidget(ViewMenu);
DockWidget->setFeatures(DockWidget->features().setFlag(ads::CDockWidget::DockWidgetClosable, false));
m_DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, TopDockArea);
// Test dock area docking
auto RighDockArea = m_DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), TopDockArea);
m_DockManager->addDockWidget(ads::TopDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
auto BottomDockArea = m_DockManager->addDockWidget(ads::BottomDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
m_DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), RighDockArea);
m_DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(ViewMenu), BottomDockArea);
}
void MainWindow::closeEvent(QCloseEvent* event)
{
/*QSettings Settings("Settings.ini", QSettings::IniFormat);
Settings.setValue("mainWindow/Geometry", saveGeometry());
Settings.setValue("mainWindow/DockingState", m_DockManager->saveState());*/
QMainWindow::closeEvent(event);
}
void MainWindow::on_actionSaveState_triggered(bool)
{
qDebug() << "MainWindow::on_actionSaveState_triggered";
QSettings Settings("Settings.ini", QSettings::IniFormat);
Settings.setValue("mainWindow/Geometry", saveGeometry());
Settings.setValue("mainWindow/DockingState", m_DockManager->saveState());
}
void MainWindow::on_actionRestoreState_triggered(bool)
{
qDebug() << "MainWindow::on_actionRestoreState_triggered";
QSettings Settings("Settings.ini", QSettings::IniFormat);
restoreGeometry(Settings.value("mainWindow/Geometry").toByteArray());
m_DockManager->restoreState(Settings.value("mainWindow/DockingState").toByteArray());
}

View File

@@ -1,30 +0,0 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "DockManager.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
protected:
virtual void closeEvent(QCloseEvent* event) override;
public:
explicit MainWindow(QWidget *parent = 0);
virtual ~MainWindow();
private:
Ui::MainWindow *ui;
ads::CDockManager* m_DockManager;
void createContent();
private slots:
void on_actionSaveState_triggered(bool);
void on_actionRestoreState_triggered(bool);
};
#endif // MAINWINDOW_H

View File

@@ -13,6 +13,9 @@
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="dockOptions">
<set>QMainWindow::AllowTabbedDocks</set>
</property>
<widget class="QWidget" name="centralWidget"/>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QMenuBar" name="menuBar">
@@ -46,6 +49,17 @@
<addaction name="menuView"/>
<addaction name="menuAbout"/>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<action name="actionExit">
<property name="text">
<string>Exit</string>

BIN
perspectives.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

173
src/DockAreaTabBar.cpp Normal file
View File

@@ -0,0 +1,173 @@
//============================================================================
/// \file DockAreaTabBar.cpp
/// \author Uwe Kindler
/// \date 24.08.2018
/// \brief Implementation of CDockAreaTabBar class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "DockAreaTabBar.h"
#include <QMouseEvent>
#include <QScrollBar>
#include <QDebug>
#include "FloatingDockContainer.h"
#include "DockAreaWidget.h"
#include "DockOverlay.h"
#include "DockManager.h"
namespace ads
{
/**
* Private data class of CDockAreaTabBar class (pimpl)
*/
struct DockAreaTabBarPrivate
{
CDockAreaTabBar* _this;
QPoint DragStartMousePos;
CDockAreaWidget* DockArea;
CFloatingDockContainer* FloatingWidget = nullptr;
/**
* Private data constructor
*/
DockAreaTabBarPrivate(CDockAreaTabBar* _public);
};
// struct DockAreaTabBarPrivate
//============================================================================
DockAreaTabBarPrivate::DockAreaTabBarPrivate(CDockAreaTabBar* _public) :
_this(_public)
{
}
//============================================================================
CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) :
QScrollArea(parent),
d(new DockAreaTabBarPrivate(this))
{
d->DockArea = parent;
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
setFrameStyle(QFrame::NoFrame);
setWidgetResizable(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
//============================================================================
CDockAreaTabBar::~CDockAreaTabBar()
{
delete d;
}
//============================================================================
void CDockAreaTabBar::wheelEvent(QWheelEvent* Event)
{
Event->accept();
const int direction = Event->angleDelta().y();
if (direction < 0)
{
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
}
else
{
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
}
}
//============================================================================
void CDockAreaTabBar::mousePressEvent(QMouseEvent* ev)
{
if (ev->button() == Qt::LeftButton)
{
ev->accept();
d->DragStartMousePos = ev->pos();
return;
}
QScrollArea::mousePressEvent(ev);
}
//============================================================================
void CDockAreaTabBar::mouseReleaseEvent(QMouseEvent* ev)
{
if (ev->button() == Qt::LeftButton)
{
qDebug() << "CTabsScrollArea::mouseReleaseEvent";
ev->accept();
d->FloatingWidget = nullptr;
d->DragStartMousePos = QPoint();
return;
}
QScrollArea::mouseReleaseEvent(ev);
}
//============================================================================
void CDockAreaTabBar::mouseMoveEvent(QMouseEvent* ev)
{
QScrollArea::mouseMoveEvent(ev);
if (ev->buttons() != Qt::LeftButton)
{
return;
}
if (d->FloatingWidget)
{
d->FloatingWidget->moveFloating();
return;
}
// 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
// empty
if (d->DockArea->dockContainer()->isFloating()
&& d->DockArea->dockContainer()->visibleDockAreaCount() == 1)
{
return;
}
if (!this->geometry().contains(ev->pos()))
{
qDebug() << "CTabsScrollArea::startFloating";
startFloating(d->DragStartMousePos);
auto Overlay = d->DockArea->dockManager()->containerOverlay();
Overlay->setAllowedAreas(OuterDockAreas);
}
return;
}
//============================================================================
void CDockAreaTabBar::mouseDoubleClickEvent(QMouseEvent *event)
{
// 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
// empty
if (d->DockArea->dockContainer()->isFloating() && d->DockArea->dockContainer()->dockAreaCount() == 1)
{
return;
}
startFloating(event->pos());
}
//============================================================================
void CDockAreaTabBar::startFloating(const QPoint& Pos)
{
QSize Size = d->DockArea->size();
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(d->DockArea);
FloatingWidget->startFloating(Pos, Size);
d->FloatingWidget = FloatingWidget;
}
} // namespace ads
//---------------------------------------------------------------------------
// EOF DockAreaTabBar.cpp

74
src/DockAreaTabBar.h Normal file
View File

@@ -0,0 +1,74 @@
#ifndef DockAreaTabBarH
#define DockAreaTabBarH
//============================================================================
/// \file DockAreaTabBar.h
/// \author Uwe Kindler
/// \date 24.08.2018
/// \brief Declaration of CDockAreaTabBar class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include <QScrollArea>
namespace ads
{
class CDockAreaWidget;
struct DockAreaTabBarPrivate;
/**
* Custom tabbar implementation for tab area that is shown on top of a
* dock area widget.
* The tabbar displays the tab widgets of the contained dock widgets.
*/
class CDockAreaTabBar : public QScrollArea
{
Q_OBJECT
private:
DockAreaTabBarPrivate* d; ///< private data (pimpl)
friend class DockAreaTabBarPrivate;
protected:
virtual void wheelEvent(QWheelEvent* Event) override;
/**
* Stores mouse position to detect dragging
*/
virtual void mousePressEvent(QMouseEvent* ev) override;
/**
* Stores mouse position to detect dragging
*/
virtual void mouseReleaseEvent(QMouseEvent* ev) override;
/**
* Starts floating the complete docking area including all dock widgets,
* if it is not the last dock area in a floating widget
*/
virtual void mouseMoveEvent(QMouseEvent* ev) override;
/**
* Double clicking the title bar also starts floating of the complete area
*/
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
/**
* Starts floating
*/
void startFloating(const QPoint& Pos);
public:
/**
* Default Constructor
*/
CDockAreaTabBar(CDockAreaWidget* parent);
/**
* Virtual Destructor
*/
virtual ~CDockAreaTabBar();
}; // class CDockAreaTabBar
} // namespace ads
//-----------------------------------------------------------------------------
#endif // DockAreaTabBarH

View File

@@ -28,6 +28,7 @@
//============================================================================
// INCLUDES
//============================================================================
#include <DockWidgetTab.h>
#include "DockAreaWidget.h"
#include <QStackedLayout>
@@ -39,14 +40,15 @@
#include <QDebug>
#include <QMenu>
#include <QSplitter>
#include <QXmlStreamWriter>
#include "DockContainerWidget.h"
#include "DockWidget.h"
#include "DockWidgetTitleBar.h"
#include "FloatingDockContainer.h"
#include "DockManager.h"
#include "DockOverlay.h"
#include "DockAreaTabBar.h"
namespace ads
@@ -55,140 +57,6 @@ static const char* const INDEX_PROPERTY = "index";
static const char* const ACTION_PROPERTY = "action";
static const int APPEND = -1;
/**
* Custom scroll bar implementation for dock area tab bar
* This scroll area enables floating of a whole dock area including all
* dock widgets
*/
class CTabsScrollArea : public QScrollArea
{
private:
QPoint m_DragStartMousePos;
CDockAreaWidget* m_DockArea;
CFloatingDockContainer* m_FloatingWidget = nullptr;
public:
CTabsScrollArea(CDockAreaWidget* parent)
: QScrollArea(parent),
m_DockArea(parent)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
setFrameStyle(QFrame::NoFrame);
setWidgetResizable(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
protected:
virtual void wheelEvent(QWheelEvent* Event) override
{
Event->accept();
const int direction = Event->angleDelta().y();
if (direction < 0)
{
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
}
else
{
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
}
}
/**
* Stores mouse position to detect dragging
*/
virtual void mousePressEvent(QMouseEvent* ev) override
{
if (ev->button() == Qt::LeftButton)
{
ev->accept();
m_DragStartMousePos = ev->pos();
return;
}
QScrollArea::mousePressEvent(ev);
}
/**
* Stores mouse position to detect dragging
*/
virtual void mouseReleaseEvent(QMouseEvent* ev) override
{
if (ev->button() == Qt::LeftButton)
{
qDebug() << "CTabsScrollArea::mouseReleaseEvent";
ev->accept();
m_FloatingWidget = nullptr;
m_DragStartMousePos = QPoint();
return;
}
QScrollArea::mouseReleaseEvent(ev);
}
/**
* Starts floating the complete docking area including all dock widgets,
* if it is not the last dock area in a floating widget
*/
virtual void mouseMoveEvent(QMouseEvent* ev) override
{
QScrollArea::mouseMoveEvent(ev);
if (ev->buttons() != Qt::LeftButton)
{
return;
}
if (m_FloatingWidget)
{
m_FloatingWidget->moveFloating();
return;
}
// 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
// empty
if (m_DockArea->dockContainer()->isFloating()
&& m_DockArea->dockContainer()->visibleDockAreaCount() == 1)
{
return;
}
if (!this->geometry().contains(ev->pos()))
{
qDebug() << "CTabsScrollArea::startFloating";
startFloating(m_DragStartMousePos);
auto Overlay = m_DockArea->dockManager()->containerOverlay();
Overlay->setAllowedAreas(OuterDockAreas);
}
return;
}
/**
* Double clicking the title bar also starts floating of the complete area
*/
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
{
// 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
// empty
if (m_DockArea->dockContainer()->isFloating() && m_DockArea->dockContainer()->dockAreaCount() == 1)
{
return;
}
startFloating(event->pos());
}
/**
* Starts floating
*/
void startFloating(const QPoint& Pos)
{
QSize Size = m_DockArea->size();
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(m_DockArea);
FloatingWidget->startFloating(Pos, Size);
m_FloatingWidget = FloatingWidget;
}
}; // class CTabsScrollArea
/**
* Private data class of CDockAreaWidget class (pimpl)
@@ -200,7 +68,7 @@ struct DockAreaWidgetPrivate
QFrame* TitleBar;
QBoxLayout* TopLayout;
QStackedLayout* ContentsLayout;
QScrollArea* TabsScrollArea;
CDockAreaTabBar* TabBar;
QWidget* TabsContainerWidget;
QBoxLayout* TabsLayout;
QPushButton* TabsMenuButton;
@@ -229,7 +97,7 @@ struct DockAreaWidgetPrivate
/**
* Convenience function to ease title widget access by index
*/
CDockWidgetTitleBar* titleWidgetAt(int index)
CDockWidgetTab* titleWidgetAt(int index)
{
return dockWidgetAt(index)->titleBar();
}
@@ -292,12 +160,12 @@ void DockAreaWidgetPrivate::createTabBar()
TitleBar->setLayout(TopLayout);
Layout->addWidget(TitleBar);
TabsScrollArea = new CTabsScrollArea(_this);
TopLayout->addWidget(TabsScrollArea, 1);
TabBar = new CDockAreaTabBar(_this);
TopLayout->addWidget(TabBar, 1);
TabsContainerWidget = new QWidget();
TabsContainerWidget->setObjectName("tabsContainerWidget");
TabsScrollArea->setWidget(TabsContainerWidget);
TabBar->setWidget(TabsContainerWidget);
TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
TabsLayout->setContentsMargins(0, 0, 0, 0);
@@ -312,6 +180,7 @@ void DockAreaWidgetPrivate::createTabBar()
TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width());
TabsMenuButton->setMenu(new QMenu(TabsMenuButton));
TopLayout->addWidget(TabsMenuButton, 0);
TabsMenuButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
SLOT(onTabsMenuActionTriggered(QAction*)));
@@ -356,12 +225,12 @@ void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget,
QAction* Action;
if (Index >= 0 && Index < menu->actions().count())
{
Action = new QAction(DockWidget->windowTitle());
Action = new QAction(DockWidget->icon(), DockWidget->windowTitle());
menu->insertAction(menu->actions().at(Index), Action);
}
else
{
Action = menu->addAction(DockWidget->windowTitle());
Action = menu->addAction(DockWidget->icon(), DockWidget->windowTitle());
}
QVariant vAction = QVariant::fromValue(Action);
DockWidget->setProperty(ACTION_PROPERTY, vAction);
@@ -488,7 +357,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
//============================================================================
void CDockAreaWidget::onDockWidgetTitleClicked()
{
CDockWidgetTitleBar* TitleWidget = qobject_cast<CDockWidgetTitleBar*>(sender());
CDockWidgetTab* TitleWidget = qobject_cast<CDockWidgetTab*>(sender());
if (!TitleWidget)
{
return;
@@ -532,7 +401,9 @@ void CDockAreaWidget::setCurrentIndex(int index)
{
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
return;
}
}
emit currentChanging(index);
// Set active TAB and update all other tabs to be inactive
for (int i = 0; i < d->TabsLayout->count(); ++i)
@@ -543,7 +414,7 @@ void CDockAreaWidget::setCurrentIndex(int index)
continue;
}
auto TitleWidget = dynamic_cast<CDockWidgetTitleBar*>(item->widget());
auto TitleWidget = dynamic_cast<CDockWidgetTab*>(item->widget());
if (!TitleWidget)
{
continue;
@@ -553,7 +424,7 @@ void CDockAreaWidget::setCurrentIndex(int index)
{
TitleWidget->show();
TitleWidget->setActiveTab(true);
d->TabsScrollArea->ensureWidgetVisible(TitleWidget);
d->TabBar->ensureWidgetVisible(TitleWidget);
auto Features = TitleWidget->dockWidget()->features();
d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable));
}
@@ -706,15 +577,18 @@ void CDockAreaWidget::updateDockArea()
//============================================================================
void CDockAreaWidget::saveState(QDataStream& stream) const
void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
{
stream << d->ContentsLayout->count() << d->ContentsLayout->currentIndex();
s.writeStartElement("DockAreaWidget");
s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count()));
s.writeAttribute("CurrentIndex", QString::number(d->ContentsLayout->currentIndex()));
qDebug() << "CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
<< " CurrentIndex: " << d->ContentsLayout->currentIndex();
for (int i = 0; i < d->ContentsLayout->count(); ++i)
{
dockWidget(i)->saveState(stream);
dockWidget(i)->saveState(s);
}
s.writeEndElement();
}
} // namespace ads

View File

@@ -3,17 +3,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -32,31 +32,72 @@
//============================================================================
#include <QFrame>
#include "ads_globals.h"
class QXmlStreamWriter;
namespace ads
{
struct DockAreaWidgetPrivate;
class CDockManager;
class CDockContainerWidget;
struct DockContainerWidgetPrivate;
class CDockWidget;
/**
* DockAreaWidget manages multiple instances of DckWidgets.
* DockAreaWidget manages multiple instances of DockWidgets.
* It displays a title tab, which is clickable and will switch to
* the contents associated to the title when clicked.
*/
class CDockAreaWidget : public QFrame
class ADS_EXPORT CDockAreaWidget : public QFrame
{
Q_OBJECT
private:
DockAreaWidgetPrivate* d; ///< private data (pimpl)
friend class DockAreaWidgetPrivate;
friend struct DockAreaWidgetPrivate;
friend class CDockContainerWidget;
friend class DockContainerWidgetPrivate;
friend class CDockWidgetTab;
private slots:
void onDockWidgetTitleClicked();
void onTabsMenuActionTriggered(QAction* Action);
void onCloseButtonClicked();
protected:
/**
* Inserts a dock widget into dock area.
* All dockwidgets in the dock area tabified in a stacked layout with tabs.
* The index indicates the index of the new dockwidget in the tabbar and
* in the stacked layout. If the Activate parameter is true, the new
* DockWidget will be the active one in the stacked layout
*/
void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true);
/**
* Add a new dock widget to dock area.
* All dockwidgets in the dock area tabified in a stacked layout with tabs
*/
void addDockWidget(CDockWidget* DockWidget);
/**
* Removes the given dock widget from the dock area
*/
void removeDockWidget(CDockWidget* DockWidget);
/**
* Returns the index of contents of the title widget that is located at
* mouse position pos
*/
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const;
/**
* Reorder the index position of DockWidget at fromIndx to toIndex.
*/
void reorderDockWidget(int fromIndex, int toIndex);
public:
/**
* Default Constructor
@@ -79,26 +120,6 @@ public:
*/
CDockContainerWidget* dockContainer() const;
/**
* Inserts a dock widget into dock area.
* All dockwidgets in the dock area tabified in a stacked layout with tabs.
* The index indicates the index of the new dockwidget in the tabbar and
* in the stacked layout. If the Activate parameter is true, the new
* DockWidget will be the active one in the stacked layout
*/
void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true);
/**
* Add a new dock widget to dock area.
* All dockwidgets in the dock area tabified in a stacked layout with tabs
*/
void addDockWidget(CDockWidget* DockWidget);
/**
* Removes the given dock widget from the dock area
*/
void removeDockWidget(CDockWidget* DockWidget);
/**
* Returns the rectangle of the title area
*/
@@ -114,12 +135,6 @@ public:
*/
int tabIndex(CDockWidget* DockWidget);
/**
* Returns the index of contents of the title widget that is located at
* mouse position pos
*/
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const;
/**
* Returns a list of all dock widgets in this dock area.
* This list contains open and closed dock widgets.
@@ -141,11 +156,6 @@ public:
*/
CDockWidget* dockWidget(int Index) const;
/**
* Reorder the index position of DockWidget at fromIndx to toIndex.
*/
void reorderDockWidget(int fromIndex, int toIndex);
/**
* Returns the index of the current active dock widget
*/
@@ -157,14 +167,14 @@ public:
CDockWidget* currentDockWidget() const;
/**
* Shows the tab with tghe given dock widget
* Shows the tab with the given dock widget
*/
void setCurrentDockWidget(CDockWidget* DockWidget);
/**
* Saves the state into the given stream
*/
void saveState(QDataStream& Stream) const;
void saveState(QXmlStreamWriter& Stream) const;
public slots:
/**
@@ -183,6 +193,13 @@ signals:
*/
void tabBarClicked(int index);
/**
* This signal is emitted when the tab bar's current tab is about to be changed. The new
* current has the given index, or -1 if there isn't a new one.
* @param index
*/
void currentChanging(int index);
/**
* This signal is emitted when the tab bar's current tab changes. The new
* current has the given index, or -1 if there isn't a new one

View File

@@ -30,12 +30,15 @@
//============================================================================
#include "DockContainerWidget.h"
#include <iostream>
#include <QEvent>
#include <QList>
#include <QGridLayout>
#include <QPointer>
#include <QVariant>
#include <QDebug>
#include <QXmlStreamWriter>
#include "DockManager.h"
#include "DockAreaWidget.h"
@@ -120,7 +123,7 @@ struct DockContainerWidgetPrivate
/**
* Save state of child nodes
*/
void saveChildNodesState(QDataStream& Stream, QWidget* Widget);
void saveChildNodesState(QXmlStreamWriter& Stream, QWidget* Widget);
/**
* Restore state of child nodes.
@@ -130,21 +133,21 @@ struct DockContainerWidgetPrivate
* \param[in] Testing If Testing is true, only the stream data is
* parsed without modifiying anything.
*/
bool restoreChildNodes(QDataStream& Stream, QWidget*& CreatedWidget,
bool restoreChildNodes(QXmlStreamReader& Stream, QWidget*& CreatedWidget,
bool Testing);
/**
* Restores a splitter.
* \see restoreChildNodes() for details
*/
bool restoreSplitter(QDataStream& Stream, QWidget*& CreatedWidget,
bool restoreSplitter(QXmlStreamReader& Stream, QWidget*& CreatedWidget,
bool Testing);
/**
* Restores a dock area.
* \see restoreChildNodes() for details
*/
bool restoreDockArea(QDataStream& Stream, QWidget*& CreatedWidget,
bool restoreDockArea(QXmlStreamReader& Stream, QWidget*& CreatedWidget,
bool Testing);
/**
@@ -169,6 +172,7 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
auto InsertParam = internal::dockAreaInsertParameters(area);
auto NewDockAreas = FloatingWidget->dockContainer()->findChildren<CDockAreaWidget*>(
QString(), Qt::FindChildrenRecursively);
CDockWidget* DockWidget = FloatingWidget->dockContainer()->findChild<CDockWidget*>();
QSplitter* Splitter = RootSplitter;
if (DockAreas.count() <= 1)
@@ -205,6 +209,10 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
RootSplitter = Splitter;
addDockAreasToList(NewDockAreas);
FloatingWidget->deleteLater();
if (DockWidget)
{
DockWidget->toggleView(true);
}
_this->dumpLayout();
}
@@ -309,39 +317,56 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QList<CDockAreaWidget*
//============================================================================
void DockContainerWidgetPrivate::saveChildNodesState(QDataStream& stream, QWidget* Widget)
void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidget* Widget)
{
QSplitter* Splitter = dynamic_cast<QSplitter*>(Widget);
if (Splitter)
{
stream << internal::SplitterMarker << Splitter->orientation() << Splitter->count();
s.writeStartElement("Splitter");
s.writeAttribute("Orientation", QString::number(Splitter->orientation()));
s.writeAttribute("Count", QString::number(Splitter->count()));
qDebug() << "NodeSplitter orient: " << Splitter->orientation()
<< " WidgetCont: " << Splitter->count();
for (int i = 0; i < Splitter->count(); ++i)
{
saveChildNodesState(stream, Splitter->widget(i));
}
stream << Splitter->sizes();
for (int i = 0; i < Splitter->count(); ++i)
{
saveChildNodesState(s, Splitter->widget(i));
}
s.writeStartElement("Sizes");
for (auto Size : Splitter->sizes())
{
s.writeCharacters(QString::number(Size) + " ");
}
s.writeEndElement();
s.writeEndElement();
}
else
{
stream << internal::DockAreaMarker;
CDockAreaWidget* DockArea = dynamic_cast<CDockAreaWidget*>(Widget);
if (DockArea)
{
DockArea->saveState(stream);
DockArea->saveState(s);
}
}
}
//============================================================================
bool DockContainerWidgetPrivate::restoreSplitter(QDataStream& stream,
bool DockContainerWidgetPrivate::restoreSplitter(QXmlStreamReader& s,
QWidget*& CreatedWidget, bool Testing)
{
int Orientation;
int WidgetCount;
stream >> Orientation >> WidgetCount;
bool Ok;
int Orientation = s.attributes().value("Orientation").toInt(&Ok);
if (!Ok)
{
return false;
}
int WidgetCount = s.attributes().value("Count").toInt(&Ok);
if (!Ok)
{
return false;
}
qDebug() << "Restore NodeSplitter Orientation: " << Orientation <<
" WidgetCount: " << WidgetCount;
QSplitter* Splitter = nullptr;
@@ -350,15 +375,42 @@ bool DockContainerWidgetPrivate::restoreSplitter(QDataStream& stream,
Splitter = internal::newSplitter((Qt::Orientation)Orientation);
}
bool Visible = false;
for (int i = 0; i < WidgetCount; ++i)
QList<int> Sizes;
while (s.readNextStartElement())
{
QWidget* ChildNode;
if (!restoreChildNodes(stream, ChildNode, Testing))
QWidget* ChildNode = nullptr;
bool Result = true;
if (s.name() == "Splitter")
{
Result = restoreSplitter(s, ChildNode, Testing);
}
else if (s.name() == "DockAreaWidget")
{
Result = restoreDockArea(s, ChildNode, Testing);
}
else if (s.name() == "Sizes")
{
QString sSizes = s.readElementText().trimmed();
qDebug() << "Sizes: " << sSizes;
QTextStream TextStream(&sSizes);
while (!TextStream.atEnd())
{
int value;
TextStream >> value;
Sizes.append(value);
}
}
else
{
s.skipCurrentElement();
}
if (!Result)
{
return false;
}
if (Testing)
if (Testing || !ChildNode)
{
continue;
}
@@ -369,8 +421,11 @@ bool DockContainerWidgetPrivate::restoreSplitter(QDataStream& stream,
Visible |= ChildNode->isVisibleTo(Splitter);
}
QList<int> Sizes;
stream >> Sizes;
if (Sizes.count() != WidgetCount)
{
return false;
}
if (!Testing)
{
if (!Splitter->count())
@@ -389,17 +444,27 @@ bool DockContainerWidgetPrivate::restoreSplitter(QDataStream& stream,
{
CreatedWidget = nullptr;
}
return true;
}
//============================================================================
bool DockContainerWidgetPrivate::restoreDockArea(QDataStream& stream,
bool DockContainerWidgetPrivate::restoreDockArea(QXmlStreamReader& s,
QWidget*& CreatedWidget, bool Testing)
{
int Tabs;
int CurrentIndex;
stream >> Tabs >> CurrentIndex;
bool Ok;
int Tabs = s.attributes().value("Tabs").toInt(&Ok);
if (!Ok)
{
return false;
}
int CurrentIndex = s.attributes().value("CurrentIndex").toInt(&Ok);
if (!Ok)
{
return false;
}
qDebug() << "Restore NodeDockArea Tabs: " << Tabs << " CurrentIndex: "
<< CurrentIndex;
@@ -409,21 +474,27 @@ bool DockContainerWidgetPrivate::restoreDockArea(QDataStream& stream,
DockArea = new CDockAreaWidget(DockManager, _this);
}
for (int i = 0; i < Tabs; ++i)
while (s.readNextStartElement())
{
int Marker;
stream >> Marker;
if (Marker != internal::DockWidgetMarker)
if (s.name() != "DockWidget")
{
continue;
}
auto ObjectName = s.attributes().value("ObjectName");
if (ObjectName.isEmpty())
{
return false;
}
QString ObjectName;
bool Closed;
stream >> ObjectName >> Closed;
qDebug() << "Restore DockWidget " << ObjectName << " Closed: " << Closed;
bool Closed = s.attributes().value("Closed").toInt(&Ok);
if (!Ok)
{
return false;
}
CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName);
s.skipCurrentElement();
CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName.toString());
if (!DockWidget || Testing)
{
continue;
@@ -451,31 +522,39 @@ bool DockContainerWidgetPrivate::restoreDockArea(QDataStream& stream,
else
{
DockArea->setProperty("currentIndex", CurrentIndex);
DockAreas.append(DockArea);
}
CreatedWidget = DockArea;
DockAreas.append(DockArea);
return true;
}
//============================================================================
bool DockContainerWidgetPrivate::restoreChildNodes(QDataStream& stream,
bool DockContainerWidgetPrivate::restoreChildNodes(QXmlStreamReader& s,
QWidget*& CreatedWidget, bool Testing)
{
int Marker;
stream >> Marker;
if (internal::SplitterMarker == Marker)
bool Result = true;
while (s.readNextStartElement())
{
return restoreSplitter(stream, CreatedWidget, Testing);
}
else if (internal::DockAreaMarker == Marker)
{
return restoreDockArea(stream, CreatedWidget, Testing);
}
else
{
return false;
if (s.name() == "Splitter")
{
Result = restoreSplitter(s, CreatedWidget, Testing);
qDebug() << "Splitter";
}
else if (s.name() == "DockAreaWidget")
{
Result = restoreDockArea(s, CreatedWidget, Testing);
qDebug() << "DockAreaWidget";
}
else
{
s.skipCurrentElement();
qDebug() << "Unknown element";
}
}
return Result;
}
@@ -541,8 +620,11 @@ void DockContainerWidgetPrivate::dumpRecursive(int level, QWidget* widget)
buf.fill(' ', level * 4);
if (Splitter)
{
qDebug("%sSplitter %s", (const char*)buf, (Splitter->orientation() == Qt::Vertical)
? "-" : "|");
qDebug("%sSplitter %s v: %s c: %s",
(const char*)buf,
(Splitter->orientation() == Qt::Vertical) ? "-" : "|",
Splitter->isVisibleTo(Splitter->parentWidget()) ? "1" : "0",
QString::number(Splitter->count()).toStdString().c_str());
for (int i = 0; i < Splitter->count(); ++i)
{
dumpRecursive(level + 1, Splitter->widget(i));
@@ -706,22 +788,59 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
{
qDebug() << "CDockContainerWidget::removeDockArea";
d->DockAreas.removeAll(area);
QSplitter* Splitter = internal::findParent<QSplitter*>(area);
CDockSplitter* Splitter = internal::findParent<CDockSplitter*>(area);
// Remove are from parent splitter and hide splitter if it has no visible
// content
area->setParent(0);
if (Splitter == d->RootSplitter || Splitter->count() != 1)
Splitter->setVisible(Splitter->hasVisibleContent());
// If splitter has more than 1 widgets, we are finished and can leave
if (Splitter->count() > 1)
{
emit dockAreasRemoved();
return;
goto emitAndExit;
}
// If this is the RootSplitter we need to remove empty splitters to
// avoid too many empty splitters
if (Splitter == d->RootSplitter)
{
qDebug() << "Removed from RootSplitter";
// If splitter is empty, we are finished
if (!Splitter->count())
{
Splitter->hide();
goto emitAndExit;
}
QWidget* widget = Splitter->widget(0);
QSplitter* ChildSplitter = dynamic_cast<QSplitter*>(widget);
// If the one and only content widget of the splitter is not a splitter
// then we are finished
if (!ChildSplitter)
{
goto emitAndExit;
}
// We replace the superfluous RootSplitter with the ChildSplitter
ChildSplitter->setParent(0);
QLayoutItem* li = d->Layout->replaceWidget(Splitter, ChildSplitter);
d->RootSplitter = ChildSplitter;
delete li;
qDebug() << "RootSplitter replaced by child splitter";
}
else if (Splitter->count() == 1)
{
qDebug() << "Replacing splitter with content";
QWidget* widget = Splitter->widget(0);
widget->setParent(this);
QSplitter* ParentSplitter = internal::findParent<QSplitter*>(Splitter);
internal::replaceSplitterWidget(ParentSplitter, Splitter, widget);
}
// It the splitter contains only one single widget, then we do not need
// it anymore and can replace it with its content
qDebug() << "Replacing splitter with content";
QWidget* widget = Splitter->widget(0);
widget->setParent(this);
QSplitter* ParentSplitter = internal::findParent<QSplitter*>(Splitter);
internal::replaceSplitterWidget(ParentSplitter, Splitter, widget);
delete Splitter;
emitAndExit:
dumpLayout();
emit dockAreasRemoved();
}
@@ -732,7 +851,7 @@ CDockAreaWidget* CDockContainerWidget::dockAreaAt(const QPoint& GlobalPos) const
{
for (const auto& DockArea : d->DockAreas)
{
if (DockArea->rect().contains(DockArea->mapFromGlobal(GlobalPos)))
if (DockArea->isVisible() && DockArea->rect().contains(DockArea->mapFromGlobal(GlobalPos)))
{
return DockArea;
}
@@ -785,11 +904,18 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
qDebug() << "CDockContainerWidget::dropFloatingWidget";
CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
auto dropArea = InvalidDockWidgetArea;
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
if (DockArea)
{
auto dropOverlay = d->DockManager->dockAreaOverlay();
dropOverlay->setAllowedAreas(AllDockAreas);
dropArea = dropOverlay->showOverlay(DockArea);
if (ContainerDropArea != InvalidDockWidgetArea &&
ContainerDropArea != dropArea)
{
dropArea = InvalidDockWidgetArea;
}
if (dropArea != InvalidDockWidgetArea)
{
qDebug() << "Dock Area Drop Content: " << dropArea;
@@ -800,7 +926,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
// mouse is over container
if (InvalidDockWidgetArea == dropArea)
{
dropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
dropArea = ContainerDropArea;
qDebug() << "Container Drop Content: " << dropArea;
if (dropArea != InvalidDockWidgetArea)
{
@@ -827,37 +953,31 @@ QList<CDockAreaWidget*> CDockContainerWidget::openedDockAreas() const
//============================================================================
void CDockContainerWidget::saveState(QDataStream& stream) const
void CDockContainerWidget::saveState(QXmlStreamWriter& s) const
{
qDebug() << "CDockContainerWidget::saveState isFloating "
<< isFloating();
stream << internal::ContainerMarker;
stream << isFloating();
s.writeStartElement("DockContainerWidget");
s.writeAttribute("Floating", QString::number(isFloating() ? 1 : 0));
if (isFloating())
{
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(this);
stream << FloatingWidget->saveGeometry();
QByteArray Geometry = FloatingWidget->saveGeometry();
s.writeTextElement("Geometry", Geometry.toHex(' '));
}
d->saveChildNodesState(stream, d->RootSplitter);
d->saveChildNodesState(s, d->RootSplitter);
s.writeEndElement();
}
//============================================================================
bool CDockContainerWidget::restoreState(QDataStream& stream, bool Testing)
bool CDockContainerWidget::restoreState(QXmlStreamReader& s, bool Testing)
{
bool IsFloating;
int Marker;
stream >> Marker;
if (Marker != internal::ContainerMarker)
{
return false;
}
stream >> IsFloating;
bool IsFloating = s.attributes().value("Floating").toInt();
qDebug() << "Restore CDockContainerWidget Floating" << IsFloating;
QWidget* NewRootSplitter;
QWidget*NewRootSplitter {};
if (!Testing)
{
d->DockAreas.clear();
@@ -866,17 +986,26 @@ bool CDockContainerWidget::restoreState(QDataStream& stream, bool Testing)
if (IsFloating)
{
qDebug() << "Restore floating widget";
QByteArray Geometry;
stream >> Geometry;
if (!s.readNextStartElement() || s.name() != "Geometry")
{
return false;
}
QByteArray GeometryString = s.readElementText(QXmlStreamReader::ErrorOnUnexpectedElement).toLocal8Bit();
QByteArray Geometry = QByteArray::fromHex(GeometryString);
if (Geometry.isEmpty())
{
return false;
}
if (!Testing)
{
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(this);
FloatingWidget->restoreGeometry(Geometry);
FloatingWidget->show();
}
}
if (!d->restoreChildNodes(stream, NewRootSplitter, Testing))
if (!d->restoreChildNodes(s, NewRootSplitter, Testing))
{
return false;
}
@@ -912,7 +1041,9 @@ QSplitter* CDockContainerWidget::rootSplitter() const
//============================================================================
void CDockContainerWidget::dumpLayout()
{
qDebug("\n\nDumping layout --------------------------");
d->dumpRecursive(0, d->RootSplitter);
qDebug("--------------------------\n\n");
}

View File

@@ -3,17 +3,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -34,24 +34,35 @@
#include "ads_globals.h"
class QXmlStreamWriter;
class QXmlStreamReader;
namespace ads
{
struct DockContainerWidgetPrivate;
class CDockAreaWidget;
class CDockWidget;
class CDockManager;
struct DockManagerPrivate;
class CFloatingDockContainer;
struct FloatingDockContainerPrivate;
/**
* Container that manages a number of dock areas with single dock widgets
* or tabyfied dock widgets in each area
*/
class CDockContainerWidget : public QFrame
class ADS_EXPORT CDockContainerWidget : public QFrame
{
Q_OBJECT
private:
DockContainerWidgetPrivate* d; ///< private data (pimpl)
friend class DockContainerWidgetPrivate;
friend struct DockContainerWidgetPrivate;
friend class CDockManager;
friend struct DockManagerPrivate;
friend class CDockAreaWidget;
friend class CFloatingDockContainer;
friend struct FloatingDockContainerPrivate;
protected:
/**
@@ -64,6 +75,34 @@ protected:
*/
QSplitter* rootSplitter() const;
/**
* Drop floating widget into the container
*/
void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
/**
* Adds the given dock area to this container widget
*/
void addDockArea(CDockAreaWidget* DockAreaWidget, DockWidgetArea area = CenterDockWidgetArea);
/**
* Removes the given dock area from this container
*/
void removeDockArea(CDockAreaWidget* area);
/**
* Saves the state into the given stream
*/
void saveState(QXmlStreamWriter& Stream) const;
/**
* Restores the state from given stream.
* If Testing is true, the function only parses the data from the given
* stream but does not restore anything. You can use this check for
* faulty files before you start restoring the state
*/
bool restoreState(QXmlStreamReader& Stream, bool Testing);
public:
/**
* Default Constructor
@@ -75,11 +114,6 @@ public:
*/
virtual ~CDockContainerWidget();
/**
* Drop floating widget into the container
*/
void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
/**
* Adds dockwidget into the given area.
* If DockAreaWidget is not null, then the area parameter indicates the area
@@ -90,16 +124,6 @@ public:
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
CDockAreaWidget* DockAreaWidget = nullptr);
/**
* Adds the given dock area to this container widget
*/
void addDockArea(CDockAreaWidget* DockAreaWidget, DockWidgetArea area = CenterDockWidgetArea);
/**
* Removes the given dock area from this container
*/
void removeDockArea(CDockAreaWidget* area);
/**
* Returns the current zOrderIndex
*/
@@ -144,19 +168,6 @@ public:
*/
bool isFloating() const;
/**
* Saves the state into the given stream
*/
void saveState(QDataStream& Stream) const;
/**
* Restores the state from given stream.
* If Testing is true, the function only parses the data from the given
* stream but does not restore anything. You can use this check for
* faulty files before you start restoring the state
*/
bool restoreState(QDataStream& Stream, bool Testing);
/**
* Dumps the layout for debugging purposes
*/

View File

@@ -28,8 +28,11 @@
//============================================================================
// INCLUDES
//============================================================================
#include <DockWidgetTab.h>
#include "DockManager.h"
#include <iostream>
#include <QMainWindow>
#include <QList>
#include <QMap>
@@ -38,18 +41,19 @@
#include <QFile>
#include <QApplication>
#include <QAction>
#include <QXmlStreamWriter>
#include <QXmlStreamReader>
#include <QSettings>
#include "FloatingDockContainer.h"
#include "DockOverlay.h"
#include "DockWidget.h"
#include "ads_globals.h"
#include "DockStateSerialization.h"
#include "DockWidgetTitleBar.h"
#include "DockAreaWidget.h"
namespace ads
{
/**
* Private data class of CDockManager class (pimpl)
*/
@@ -61,6 +65,7 @@ struct DockManagerPrivate
CDockOverlay* ContainerOverlay;
CDockOverlay* DockAreaOverlay;
QMap<QString, CDockWidget*> DockWidgetsMap;
QMap<QString, QByteArray> Perspectives;
/**
* Private data constructor
@@ -76,12 +81,12 @@ struct DockManagerPrivate
/**
* Restores the state
*/
bool restoreState(const QByteArray &state, int version);
bool restoreState(const QByteArray &state, int version, bool Testing = internal::Restore);
/**
* Restores the container with the given index
*/
bool restoreContainer(int Index, QDataStream& stream, bool Testing);
bool restoreContainer(int Index, QXmlStreamReader& stream, bool Testing);
/**
* Loads the stylesheet
@@ -112,45 +117,13 @@ void DockManagerPrivate::loadStylesheet()
//============================================================================
bool DockManagerPrivate::checkFormat(const QByteArray &state, int version)
bool DockManagerPrivate::restoreContainer(int Index, QXmlStreamReader& stream, bool Testing)
{
if (state.isEmpty())
{
return false;
}
QByteArray sd = state;
QDataStream stream(&sd, QIODevice::ReadOnly);
if (Testing)
{
Index = 0;
}
int marker;
int v;
stream >> marker;
stream >> v;
if (stream.status() != QDataStream::Ok || marker != internal::VersionMarker || v != version)
{
return false;
}
int Result = true;
int ContainerCount;
stream >> ContainerCount;
int i;
for (i = 0; i < ContainerCount; ++i)
{
if (!Containers[0]->restoreState(stream, internal::RestoreTesting))
{
Result = false;
break;
}
}
return Result;
}
//============================================================================
bool DockManagerPrivate::restoreContainer(int Index, QDataStream& stream, bool Testing)
{
if (Index >= Containers.count())
{
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
@@ -165,45 +138,60 @@ bool DockManagerPrivate::restoreContainer(int Index, QDataStream& stream, bool T
//============================================================================
bool DockManagerPrivate::restoreState(const QByteArray &state, int version)
bool DockManagerPrivate::checkFormat(const QByteArray &state, int version)
{
return restoreState(state, version, internal::RestoreTesting);
}
//============================================================================
bool DockManagerPrivate::restoreState(const QByteArray &state, int version,
bool Testing)
{
if (state.isEmpty())
{
return false;
}
QByteArray sd = state;
QDataStream stream(&sd, QIODevice::ReadOnly);
int marker;
int v;
stream >> marker;
stream >> v;
if (stream.status() != QDataStream::Ok || marker != internal::VersionMarker || v != version)
QXmlStreamReader s(state);
s.readNextStartElement();
if (s.name() != "QtAdvancedDockingSystem")
{
return false;
return false;
}
qDebug() << s.attributes().value("Version");
bool ok;
int v = s.attributes().value("Version").toInt(&ok);
if (!ok || v != version)
{
return false;
}
int Result = true;
int ContainerCount;
stream >> ContainerCount;
qDebug() << "ContainerCount " << ContainerCount;
int i;
for (i = 0; i < ContainerCount; ++i)
bool Result = true;
int DockContainers = s.attributes().value("DockContainers").toInt();
qDebug() << DockContainers;
int DockContainerCount = 0;
while (s.readNextStartElement())
{
Result = restoreContainer(i, stream, internal::Restore);
if (!Result)
if (s.name() == "DockContainerWidget")
{
break;
Result = restoreContainer(DockContainerCount, s, Testing);
if (!Result)
{
break;
}
DockContainerCount++;
}
}
// Delete remaining empty floating widgets
int FloatingWidgetIndex = i - 1;
int DeleteCount = FloatingWidgets.count() - FloatingWidgetIndex;
for (int i = 0; i < DeleteCount; ++i)
if (!Testing)
{
FloatingWidgets[FloatingWidgetIndex + i]->deleteLater();
// Delete remaining empty floating widgets
int FloatingWidgetIndex = DockContainerCount - 1;
int DeleteCount = FloatingWidgets.count() - FloatingWidgetIndex;
for (int i = 0; i < DeleteCount; ++i)
{
FloatingWidgets[FloatingWidgetIndex + i]->deleteLater();
}
}
return Result;
@@ -309,17 +297,22 @@ unsigned int CDockManager::zOrderIndex() const
//============================================================================
QByteArray CDockManager::saveState(int version) const
{
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << internal::VersionMarker;
stream << version;
QByteArray xmldata;
QXmlStreamWriter s(&xmldata);
s.setAutoFormatting(true);
s.writeStartDocument();
s.writeStartElement("QtAdvancedDockingSystem");
s.writeAttribute("Version", QString::number(version));
s.writeAttribute("DockContainers", QString::number(d->Containers.count()));
for (auto Container : d->Containers)
{
Container->saveState(s);
}
stream << d->Containers.count();
for (auto Container : d->Containers)
{
Container->saveState(stream);
}
return data;
s.writeEndElement();
s.writeEndDocument();
return xmldata;
}
@@ -345,7 +338,7 @@ bool CDockManager::restoreState(const QByteArray &state, int version)
// All dock widgets, that have not been processed in the restore state
// function are invisible to the user now and have no assigned dock area
// The do not belong to any dock container, until the user toggles the
// They do not belong to any dock container, until the user toggles the
// toggle view action the next time
for (auto DockWidget : d->DockWidgetsMap)
{
@@ -353,9 +346,9 @@ bool CDockManager::restoreState(const QByteArray &state, int version)
{
DockWidget->flagAsUnassigned();
}
else if (!DockWidget->property("closed").toBool())
else
{
DockWidget->toggleView(true);
DockWidget->toggleView(!DockWidget->property("closed").toBool());
}
}
@@ -375,6 +368,7 @@ bool CDockManager::restoreState(const QByteArray &state, int version)
}
}
emit stateChanged();
return true;
}
@@ -393,6 +387,78 @@ CDockWidget* CDockManager::findDockWidget(const QString& ObjectName)
{
return d->DockWidgetsMap.value(ObjectName, nullptr);
}
//============================================================================
void CDockManager::addPerspective(const QString& UniquePrespectiveName)
{
d->Perspectives.insert(UniquePrespectiveName, saveState());
emit perspectiveListChanged();
}
//============================================================================
QStringList CDockManager::perspectiveNames() const
{
return d->Perspectives.keys();
}
//============================================================================
void CDockManager::openPerspective(const QString& PerspectiveName)
{
const auto Iterator = d->Perspectives.find(PerspectiveName);
if (d->Perspectives.end() == Iterator)
{
return;
}
restoreState(Iterator.value());
}
//============================================================================
void CDockManager::savePerspectives(QSettings& Settings) const
{
Settings.beginWriteArray("Perspectives", d->Perspectives.size());
int i = 0;
for (auto it = d->Perspectives.constBegin(); it != d->Perspectives.constEnd(); ++it)
{
Settings.setArrayIndex(i);
Settings.setValue("Name", it.key());
Settings.setValue("State", it.value());
++i;
}
Settings.endArray();
}
//============================================================================
void CDockManager::loadPerspectives(QSettings& Settings)
{
d->Perspectives.clear();
int Size = Settings.beginReadArray("Perspectives");
if (!Size)
{
Settings.endArray();
return;
}
for (int i = 0; i < Size; ++i)
{
Settings.setArrayIndex(i);
QString Name = Settings.value("Name").toString();
QByteArray Data = Settings.value("State").toByteArray();
if (Name.isEmpty() || Data.isEmpty())
{
continue;
}
d->Perspectives.insert(Name, Data);
}
Settings.endArray();
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@@ -3,17 +3,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -32,39 +32,40 @@
//============================================================================
#include "DockContainerWidget.h"
#include "ads_globals.h"
class QSettings;
namespace ads
{
struct DockManagerPrivate;
class CFloatingDockContainer;
struct FloatingDockContainerPrivate;
class CDockContainerWidget;
class CDockOverlay;
class CDockAreaTabBar;
class CDockWidgetTab;
struct DockWidgetTabPrivate;
struct DockAreaWidgetPrivate;
/**
* The central dock manager that maintains the complete docking system
**/
class CDockManager : public CDockContainerWidget
class ADS_EXPORT CDockManager : public CDockContainerWidget
{
Q_OBJECT
private:
DockManagerPrivate* d; ///< private data (pimpl)
friend class DockManagerPrivate;
friend struct DockManagerPrivate;
friend class CFloatingDockContainer;
friend struct FloatingDockContainerPrivate;
friend class CDockContainerWidget;
friend class CDockAreaTabBar;
friend class CDockWidgetTab;
friend struct DockAreaWidgetPrivate;
friend struct DockWidgetTabPrivate;
protected:
public:
/**
* Default Constructor.
* If the given parent is a QMainWindow, the dock manager sets itself as the
* central widget
*/
CDockManager(QWidget* parent = 0);
/**
* Virtual Destructor
*/
virtual ~CDockManager();
/**
* Registers the given floating widget in the internal list of
* floating widgets
@@ -98,11 +99,30 @@ public:
*/
CDockOverlay* dockAreaOverlay() const;
public:
/**
* Default Constructor.
* If the given parent is a QMainWindow, the dock manager sets itself as the
* central widget
*/
CDockManager(QWidget* parent = 0);
/**
* Virtual Destructor
*/
virtual ~CDockManager();
/**
* Adds dockwidget into the given area.
* If DockAreaWidget is not null, then the area parameter indicates the area
* into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will
* be dropped into the container.
* be dropped into the container. If you would like to add a dock widget
* tabified, then you need to add it to an existing dock area object
* into the CenterDockWidgetArea. The following code shows this:
* \code
* DockManager->addDockWidget(ads::CenterDockWidgetArea, NewDockWidget,
* ExisitingDockArea);
* \endcode
* \return Returns the dock area widget that contains the new DockWidget
*/
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
@@ -134,6 +154,7 @@ public:
/**
* Saves the current state of the dockmanger and all its dock widgets
* into the returned QByteArray
*/
QByteArray saveState(int version = 0) const;
@@ -145,6 +166,50 @@ public:
* returns true.
*/
bool restoreState(const QByteArray &state, int version = 0);
/**
* Saves the current perspective to the internal list of perspectives.
* A perspective is the current state of the dock manager assigned
* with a certain name. This makes it possible for the user,
* to switch between different perspectives quickly.
* If a perspective with the given name already exists, then
* it will be overwritten with the new state.
*/
void addPerspective(const QString& UniquePrespectiveName);
/**
* Returns the names of all available perspectives
*/
QStringList perspectiveNames() const;
/**
* Saves the perspectives to the given settings file.
*/
void savePerspectives(QSettings& Settings) const;
/**
* Loads the perspectives from the given settings file
*/
void loadPerspectives(QSettings& Settings);
public slots:
/**
* Opens the perspective with the given name.
*/
void openPerspective(const QString& PerspectiveName);
signals:
/**
* This signal is emitted if the list of perspectives changed
*/
void perspectiveListChanged();
/**
* This signal is emitted if the state changed in restoreState.
* The signal is emitted if the restoreState() function is called or
* if the openPerspective() function is called
*/
void stateChanged();
}; // class DockManager
} // namespace ads
//-----------------------------------------------------------------------------

View File

@@ -33,160 +33,14 @@
#include <QLabel>
#include <QtGlobal>
#include <QDebug>
#include <QMap>
#include "DockAreaWidget.h"
#include <iostream>
namespace ads
{
//============================================================================
static QPixmap createDropIndicatorPixmap(const QPalette& pal, const QSizeF& size, DockWidgetArea DockWidgetArea,
CDockOverlay::eMode Mode)
{
QColor borderColor = pal.color(QPalette::Active, QPalette::Highlight);
QColor backgroundColor = pal.color(QPalette::Active, QPalette::Base);
QPixmap pm(size.width(), size.height());
pm.fill(QColor(0, 0, 0, 0));
QPainter p(&pm);
QPen pen = p.pen();
QRectF ShadowRect(pm.rect());
QRectF baseRect;
baseRect.setSize(ShadowRect.size() * 0.7);
baseRect.moveCenter(ShadowRect.center());
// Fill
p.fillRect(ShadowRect, QColor(0, 0, 0, 64));
// Drop area rect.
p.save();
QRectF areaRect;
QLineF areaLine;
QRectF nonAreaRect;
switch (DockWidgetArea)
{
case TopDockWidgetArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
nonAreaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight());
break;
case RightDockWidgetArea:
areaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft());
break;
case BottomDockWidgetArea:
areaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.topLeft(), areaRect.topRight());
break;
case LeftDockWidgetArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
nonAreaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight());
break;
default:
break;
}
QSizeF baseSize = baseRect.size();
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
{
baseRect = areaRect;
}
p.fillRect(baseRect, backgroundColor);
if (areaRect.isValid())
{
pen = p.pen();
pen.setColor(borderColor);
QColor Color = borderColor;
Color.setAlpha(64);
p.setBrush(Color);
p.setPen(Qt::NoPen);
p.drawRect(areaRect);
pen = p.pen();
pen.setColor(borderColor);
pen.setStyle(Qt::DashLine);
p.setPen(pen);
p.drawLine(areaLine);
}
p.restore();
p.save();
// Draw outer border
pen = p.pen();
pen.setColor(borderColor);
pen.setWidth(1);
p.setBrush(Qt::NoBrush);
p.setPen(pen);
p.drawRect(baseRect);
// draw window title bar
p.setBrush(borderColor);
QRectF FrameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10));
p.drawRect(FrameRect);
p.restore();
// Draw arrow for outer container drop indicators
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
{
QRectF ArrowRect;
ArrowRect.setSize(baseSize);
ArrowRect.setWidth(ArrowRect.width() / 4.6);
ArrowRect.setHeight(ArrowRect.height() / 2);
ArrowRect.moveCenter(QPointF(0, 0));
QPolygonF Arrow;
Arrow << ArrowRect.topLeft()
<< QPointF( ArrowRect.right(), ArrowRect.center().y())
<< ArrowRect.bottomLeft();
p.setPen(Qt::NoPen);
p.setBrush(backgroundColor);
p.setRenderHint(QPainter::Antialiasing, true);
p.translate(nonAreaRect.center().x(), nonAreaRect.center().y());
switch (DockWidgetArea)
{
case TopDockWidgetArea:
p.rotate(-90);
break;
case RightDockWidgetArea:
break;
case BottomDockWidgetArea:
p.rotate(90);
break;
case LeftDockWidgetArea:
p.rotate(180);
break;
default:
break;
}
p.drawPolygon(Arrow);
}
return pm;
}
//============================================================================
QWidget* createDropIndicatorWidget(DockWidgetArea DockWidgetArea,
CDockOverlay::eMode Mode)
{
QLabel* l = new QLabel();
l->setObjectName("DockWidgetAreaLabel");
const qreal metric = static_cast<qreal>(l->fontMetrics().height()) * 3.f;
const QSizeF size(metric, metric);
l->setPixmap(createDropIndicatorPixmap(l->palette(), size, DockWidgetArea,
Mode));
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
l->setAttribute(Qt::WA_TranslucentBackground);
return l;
}
/**
* Private data class of CDockOverlay
@@ -219,6 +73,8 @@ struct DockOverlayCrossPrivate
CDockOverlay* DockOverlay;
QHash<DockWidgetArea, QWidget*> DropIndicatorWidgets;
QGridLayout* GridLayout;
QColor IconColors[5];
bool UpdateRequired = false;
/**
* Private data constructor
@@ -231,6 +87,206 @@ struct DockOverlayCrossPrivate
* @return
*/
QPoint areaGridPosition(const DockWidgetArea area);
/**
* Palette based default icon colors
*/
QColor defaultIconColor(CDockOverlayCross::eIconColor ColorIndex)
{
QPalette pal = _this->palette();
switch (ColorIndex)
{
case CDockOverlayCross::FrameColor: return pal.color(QPalette::Active, QPalette::Highlight);
case CDockOverlayCross::WindowBackgroundColor: return pal.color(QPalette::Active, QPalette::Base);
case CDockOverlayCross::OverlayColor:
{
QColor Color = pal.color(QPalette::Active, QPalette::Highlight);
Color.setAlpha(64);
return Color;
}
break;
case CDockOverlayCross::ArrowColor: return pal.color(QPalette::Active, QPalette::Base);
case CDockOverlayCross::ShadowColor: return QColor(0, 0, 0, 64);
default:
return QColor();
}
return QColor();
}
/**
* Stylehseet based icon colors
*/
QColor iconColor(CDockOverlayCross::eIconColor ColorIndex)
{
QColor Color = IconColors[ColorIndex];
if (!Color.isValid())
{
Color = defaultIconColor(ColorIndex);
IconColors[ColorIndex] = Color;
}
return Color;
}
//============================================================================
QWidget* createDropIndicatorWidget(DockWidgetArea DockWidgetArea,
CDockOverlay::eMode Mode)
{
QLabel* l = new QLabel();
l->setObjectName("DockWidgetAreaLabel");
const qreal metric = static_cast<qreal>(l->fontMetrics().height()) * 3.f;
const QSizeF size(metric, metric);
l->setPixmap(createDropIndicatorPixmap(size, DockWidgetArea, Mode));
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
l->setAttribute(Qt::WA_TranslucentBackground);
return l;
}
//============================================================================
QPixmap createDropIndicatorPixmap(const QSizeF& size, DockWidgetArea DockWidgetArea,
CDockOverlay::eMode Mode)
{
QColor borderColor = iconColor(CDockOverlayCross::FrameColor);
QColor backgroundColor = iconColor(CDockOverlayCross::WindowBackgroundColor);
QPixmap pm(size.width(), size.height());
pm.fill(QColor(0, 0, 0, 0));
QPainter p(&pm);
QPen pen = p.pen();
QRectF ShadowRect(pm.rect());
QRectF baseRect;
baseRect.setSize(ShadowRect.size() * 0.7);
baseRect.moveCenter(ShadowRect.center());
// Fill
QColor ShadowColor = iconColor(CDockOverlayCross::ShadowColor);
if (ShadowColor.alpha() == 255)
{
ShadowColor.setAlpha(64);
}
p.fillRect(ShadowRect, ShadowColor);
// Drop area rect.
p.save();
QRectF areaRect;
QLineF areaLine;
QRectF nonAreaRect;
switch (DockWidgetArea)
{
case TopDockWidgetArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
nonAreaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight());
break;
case RightDockWidgetArea:
areaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft());
break;
case BottomDockWidgetArea:
areaRect = QRectF(baseRect.x(), ShadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.topLeft(), areaRect.topRight());
break;
case LeftDockWidgetArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
nonAreaRect = QRectF(ShadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight());
break;
default:
break;
}
QSizeF baseSize = baseRect.size();
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
{
baseRect = areaRect;
}
p.fillRect(baseRect, backgroundColor);
if (areaRect.isValid())
{
pen = p.pen();
pen.setColor(borderColor);
QColor Color = iconColor(CDockOverlayCross::OverlayColor);
if (Color.alpha() == 255)
{
Color.setAlpha(64);
}
p.setBrush(Color);
p.setPen(Qt::NoPen);
p.drawRect(areaRect);
pen = p.pen();
pen.setColor(borderColor);
pen.setStyle(Qt::DashLine);
p.setPen(pen);
p.drawLine(areaLine);
}
p.restore();
p.save();
// Draw outer border
pen = p.pen();
pen.setColor(borderColor);
pen.setWidth(1);
p.setBrush(Qt::NoBrush);
p.setPen(pen);
p.drawRect(baseRect);
// draw window title bar
p.setBrush(borderColor);
QRectF FrameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10));
p.drawRect(FrameRect);
p.restore();
// Draw arrow for outer container drop indicators
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
{
QRectF ArrowRect;
ArrowRect.setSize(baseSize);
ArrowRect.setWidth(ArrowRect.width() / 4.6);
ArrowRect.setHeight(ArrowRect.height() / 2);
ArrowRect.moveCenter(QPointF(0, 0));
QPolygonF Arrow;
Arrow << ArrowRect.topLeft()
<< QPointF( ArrowRect.right(), ArrowRect.center().y())
<< ArrowRect.bottomLeft();
p.setPen(Qt::NoPen);
p.setBrush(iconColor(CDockOverlayCross::ArrowColor));
p.setRenderHint(QPainter::Antialiasing, true);
p.translate(nonAreaRect.center().x(), nonAreaRect.center().y());
switch (DockWidgetArea)
{
case TopDockWidgetArea:
p.rotate(-90);
break;
case RightDockWidgetArea:
break;
case BottomDockWidgetArea:
p.rotate(90);
break;
case LeftDockWidgetArea:
p.rotate(180);
break;
default:
break;
}
p.drawPolygon(Arrow);
}
return pm;
}
};
@@ -247,7 +303,6 @@ CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) :
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
d->Cross->setupOverlayCross(Mode);
d->Cross->setVisible(false);
setVisible(false);
}
@@ -405,6 +460,18 @@ void CDockOverlay::hideEvent(QHideEvent* e)
}
//============================================================================
bool CDockOverlay::event(QEvent *e)
{
bool Result = Super::event(e);
if (e->type() == QEvent::Polish)
{
d->Cross->setupOverlayCross(d->Mode);
}
return Result;
}
//============================================================================
static int areaAlignment(const DockWidgetArea area)
{
@@ -480,13 +547,29 @@ void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode)
d->Mode = Mode;
QHash<DockWidgetArea, QWidget*> areaWidgets;
areaWidgets.insert(TopDockWidgetArea, createDropIndicatorWidget(TopDockWidgetArea, Mode));
areaWidgets.insert(RightDockWidgetArea, createDropIndicatorWidget(RightDockWidgetArea, Mode));
areaWidgets.insert(BottomDockWidgetArea, createDropIndicatorWidget(BottomDockWidgetArea, Mode));
areaWidgets.insert(LeftDockWidgetArea, createDropIndicatorWidget(LeftDockWidgetArea, Mode));
areaWidgets.insert(CenterDockWidgetArea, createDropIndicatorWidget(CenterDockWidgetArea, Mode));
areaWidgets.insert(TopDockWidgetArea, d->createDropIndicatorWidget(TopDockWidgetArea, Mode));
areaWidgets.insert(RightDockWidgetArea, d->createDropIndicatorWidget(RightDockWidgetArea, Mode));
areaWidgets.insert(BottomDockWidgetArea, d->createDropIndicatorWidget(BottomDockWidgetArea, Mode));
areaWidgets.insert(LeftDockWidgetArea, d->createDropIndicatorWidget(LeftDockWidgetArea, Mode));
areaWidgets.insert(CenterDockWidgetArea, d->createDropIndicatorWidget(CenterDockWidgetArea, Mode));
setAreaWidgets(areaWidgets);
d->UpdateRequired = false;
}
//============================================================================
void CDockOverlayCross::setIconColor(eIconColor ColorIndex, const QColor& Color)
{
d->IconColors[ColorIndex] = Color;
d->UpdateRequired = true;
}
//============================================================================
QColor CDockOverlayCross::iconColor(eIconColor ColorIndex) const
{
return d->IconColors[ColorIndex];
}
@@ -573,6 +656,10 @@ DockWidgetArea CDockOverlayCross::cursorLocation() const
//============================================================================
void CDockOverlayCross::showEvent(QShowEvent*)
{
if (d->UpdateRequired)
{
setupOverlayCross(d->Mode);
}
this->updatePosition();
}
@@ -611,6 +698,38 @@ void CDockOverlayCross::reset()
}
//============================================================================
void CDockOverlayCross::setIconColors(const QString& Colors)
{
static const QMap<QString, int> ColorCompenentStringMap{
{"Frame", CDockOverlayCross::FrameColor},
{"Background", CDockOverlayCross::WindowBackgroundColor},
{"Overlay", CDockOverlayCross::OverlayColor},
{"Arrow", CDockOverlayCross::ArrowColor},
{"Shadow", CDockOverlayCross::ShadowColor}};
auto ColorList = Colors.split(' ', QString::SkipEmptyParts);
for (const auto& ColorListEntry : ColorList)
{
auto ComponentColor = ColorListEntry.split('=', QString::SkipEmptyParts);
int Component = ColorCompenentStringMap.value(ComponentColor[0], -1);
if (Component < 0)
{
continue;
}
d->IconColors[Component] = QColor(ComponentColor[1]);
}
d->UpdateRequired = true;
}
//============================================================================
QString CDockOverlayCross::iconColors() const
{
return QString();
}
} // namespace ads
//----------------------------------------------------------------------------

View File

@@ -3,17 +3,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -39,15 +39,17 @@ class CDockOverlayCross;
* DockOverlay paints a translucent rectangle over another widget. The geometry
* of the rectangle is based on the mouse location.
*/
class CDockOverlay : public QFrame
class ADS_EXPORT CDockOverlay : public QFrame
{
Q_OBJECT
private:
DockOverlayPrivate* d; //< private data class
friend class DockOverlayPrivate;
friend struct DockOverlayPrivate;
friend class DockOverlayCross;
public:
using Super = QFrame;
enum eMode
{
ModeDockAreaOverlay,
@@ -100,6 +102,11 @@ public:
*/
QRect dropOverlayRect() const;
/**
* Handle polish events
*/
virtual bool event(QEvent *e) override;
protected:
virtual void paintEvent(QPaintEvent *e) override;
virtual void showEvent(QShowEvent* e) override;
@@ -112,18 +119,71 @@ struct DockOverlayCrossPrivate;
* DockOverlayCross shows a cross with 5 different drop area possibilities.
* I could have handled everything inside DockOverlay, but because of some
* styling issues it's better to have a separate class for the cross.
* You can style the cross icon using the property system.
* \code
* ads--CDockOverlayCross
{
qproperty-iconFrameColor: palette(highlight);
qproperty-iconBackgroundColor: palette(base);
qproperty-iconOverlayColor: palette(highlight);
qproperty-iconArrowColor: rgb(227, 227, 227);
qproperty-iconShadowColor: rgb(0, 0, 0);
}
* \endcode
* Or you can use the iconColors property to pass in AARRGGBB values as
* hex string like shown in the example below.
* \code
* ads--CDockOverlayCross
* {
* qproperty-iconColors: "Frame=#ff3d3d3d Background=#ff929292 Overlay=#1f3d3d3d Arrow=#ffb4b4b4 Shadow=#40474747";
* }
* \endcode
*/
class CDockOverlayCross : public QWidget
{
Q_OBJECT
Q_PROPERTY(QString iconColors READ iconColors WRITE setIconColors)
Q_PROPERTY(QColor iconFrameColor READ iconColor WRITE setIconFrameColor)
Q_PROPERTY(QColor iconBackgroundColor READ iconColor WRITE setIconBackgroundColor)
Q_PROPERTY(QColor iconOverlayColor READ iconColor WRITE setIconOverlayColor)
Q_PROPERTY(QColor iconArrowColor READ iconColor WRITE setIconArrowColor)
Q_PROPERTY(QColor iconShadowColor READ iconColor WRITE setIconShadowColor)
public:
enum eIconColor
{
FrameColor,///< the color of the frame of the small window icon
WindowBackgroundColor,///< the background color of the small window in the icon
OverlayColor,///< the color that shows the overlay (the dock side) in the icon
ArrowColor,///< the arrow that points into the direction
ShadowColor///< the color of the shadow rectangle that is painted below the icons
};
private:
DockOverlayCrossPrivate* d;
friend class DockOverlayCrossPrivate;
friend struct DockOverlayCrossPrivate;
friend class CDockOverlay;
protected:
/**
* This function returns an empty string and is only here to silence
* moc
*/
QString iconColors() const;
/**
* This is a dummy function for the property system
*/
QColor iconColor() const {return QColor();}
void setIconFrameColor(const QColor& Color) {setIconColor(FrameColor, Color);}
void setIconBackgroundColor(const QColor& Color) {setIconColor(WindowBackgroundColor, Color);}
void setIconOverlayColor(const QColor& Color) {setIconColor(OverlayColor, Color);}
void setIconArrowColor(const QColor& Color) {setIconColor(ArrowColor, Color);}
void setIconShadowColor(const QColor& Color) {setIconColor(ShadowColor, Color);}
public:
/**
* Creates an overlay corss for the given overlay
* Creates an overlay cross for the given overlay
*/
CDockOverlayCross(CDockOverlay* overlay);
@@ -132,6 +192,16 @@ public:
*/
virtual ~CDockOverlayCross();
/**
* Sets a certain icon color
*/
void setIconColor(eIconColor ColorIndex, const QColor& Color);
/**
* Returns the icon color given by ColorIndex
*/
QColor iconColor(eIconColor ColorIndex) const;
/**
* Returns the dock widget area depending on the current cursor location.
* The function checks, if the mouse cursor is inside of any drop indicator
@@ -154,6 +224,19 @@ public:
*/
void updatePosition();
/**
* A string with all icon colors to set.
* You can use this property to style the overly icon via CSS stylesheet
* file. The colors are set via a color identifier and a hex AARRGGBB value like
* in the example below.
* \code
* ads--CDockOverlayCross
* {
* qproperty-iconColors: "Frame=#ff3d3d3d Background=#ff929292 Overlay=#1f3d3d3d Arrow=#ffb4b4b4 Shadow=#40474747";
* }
*/
void setIconColors(const QString& Colors);
protected:
virtual void showEvent(QShowEvent* e) override;
void setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets);

View File

@@ -3,17 +3,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -31,6 +31,8 @@
//============================================================================
#include <QSplitter>
#include "ads_globals.h"
namespace ads
{
struct DockSplitterPrivate;
@@ -38,12 +40,12 @@ struct DockSplitterPrivate;
/**
* Splitter used internally instead of QSplitter
*/
class CDockSplitter : public QSplitter
class ADS_EXPORT CDockSplitter : public QSplitter
{
Q_OBJECT
private:
DockSplitterPrivate* d;
friend class DockSplitterPrivate;
friend struct DockSplitterPrivate;
public:
CDockSplitter(QWidget *parent = Q_NULLPTR);

View File

@@ -28,6 +28,7 @@
//============================================================================
// INCLUDES
//============================================================================
#include <DockWidgetTab.h>
#include "DockWidget.h"
#include <QBoxLayout>
@@ -38,8 +39,8 @@
#include <QPointer>
#include <QEvent>
#include <QDebug>
#include <QXmlStreamWriter>
#include "DockWidgetTitleBar.h"
#include "DockContainerWidget.h"
#include "DockAreaWidget.h"
#include "DockManager.h"
@@ -58,7 +59,7 @@ struct DockWidgetPrivate
CDockWidget* _this;
QBoxLayout* Layout;
QWidget* Widget = nullptr;
CDockWidgetTitleBar* TitleWidget;
CDockWidgetTab* TitleWidget;
CDockWidget::DockWidgetFeatures Features = CDockWidget::AllDockWidgetFeatures;
CDockManager* DockManager = nullptr;
CDockAreaWidget* DockArea = nullptr;
@@ -210,8 +211,9 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
d->Layout->setSpacing(0);
setLayout(d->Layout);
setWindowTitle(title);
setObjectName(title);
d->TitleWidget = new CDockWidgetTitleBar(this);
d->TitleWidget = new CDockWidgetTab(this);
d->ToggleViewAction = new QAction(title);
d->ToggleViewAction->setCheckable(true);
connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this,
@@ -260,7 +262,7 @@ QWidget* CDockWidget::widget() const
//============================================================================
CDockWidgetTitleBar* CDockWidget::titleBar() const
CDockWidgetTab* CDockWidget::titleBar() const
{
return d->TitleWidget;
}
@@ -273,6 +275,13 @@ void CDockWidget::setFeatures(DockWidgetFeatures features)
}
//============================================================================
void CDockWidget::setFeature(DockWidgetFeature flag, bool on)
{
d->Features.setFlag(flag, on);
}
//============================================================================
CDockWidget::DockWidgetFeatures CDockWidget::features() const
{
@@ -329,9 +338,31 @@ QAction* CDockWidget::toggleViewAction() const
}
//============================================================================
void CDockWidget::setToggleViewActionMode(eToggleViewActionMode Mode)
{
if (ActionModeToggle == Mode)
{
d->ToggleViewAction->setCheckable(true);
d->ToggleViewAction->setIcon(QIcon());
}
else
{
d->ToggleViewAction->setCheckable(false);
d->ToggleViewAction->setIcon(d->TitleWidget->icon());
}
}
//============================================================================
void CDockWidget::toggleView(bool Open)
{
QAction* Sender = qobject_cast<QAction*>(sender());
if (Sender == d->ToggleViewAction && !d->ToggleViewAction->isCheckable())
{
Open = true;
}
if (Open)
{
d->showDockWidget();
@@ -361,11 +392,12 @@ void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
//============================================================================
void CDockWidget::saveState(QDataStream& stream) const
void CDockWidget::saveState(QXmlStreamWriter& s) const
{
stream << internal::DockWidgetMarker;
qDebug() << "CDockWidget::saveState " << objectName() << " closed " << d->Closed;
stream << objectName() << d->Closed;
s.writeStartElement("DockWidget");
s.writeAttribute("ObjectName", objectName());
s.writeAttribute("Closed", QString::number(d->Closed ? 1 : 0));
s.writeEndElement();
}
@@ -389,6 +421,24 @@ bool CDockWidget::event(QEvent *e)
}
//============================================================================
void CDockWidget::setIcon(const QIcon& Icon)
{
d->TitleWidget->setIcon(Icon);
if (!d->ToggleViewAction->isCheckable())
{
d->ToggleViewAction->setIcon(Icon);
}
}
//============================================================================
QIcon CDockWidget::icon() const
{
return d->TitleWidget->icon();
}
} // namespace ads

View File

@@ -3,17 +3,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -32,10 +32,14 @@
//============================================================================
#include <QFrame>
#include "ads_globals.h"
class QXmlStreamWriter;
namespace ads
{
struct DockWidgetPrivate;
class CDockWidgetTitleBar;
class CDockWidgetTab;
class CDockManager;
class CDockContainerWidget;
class CDockAreaWidget;
@@ -45,19 +49,19 @@ struct DockContainerWidgetPrivate;
* The QDockWidget class provides a widget that can be docked inside a
* CDockManager or floated as a top-level window on the desktop.
*/
class CDockWidget : public QFrame
class ADS_EXPORT CDockWidget : public QFrame
{
Q_OBJECT
private:
DockWidgetPrivate* d; ///< private data (pimpl)
friend class DockWidgetPrivate;
friend struct DockWidgetPrivate;
protected:
friend class CDockContainerWidget;
friend class CDockAreaWidget;
friend class CFloatingDockContainer;
friend class CDockManager;
friend class DockContainerWidgetPrivate;
friend struct DockContainerWidgetPrivate;
/**
* Assigns the dock manager that manages this dock widget
@@ -81,7 +85,7 @@ protected:
/**
* Saves the state into the given stream
*/
void saveState(QDataStream& Stream) const;
void saveState(QXmlStreamWriter& Stream) const;
/**
* This is a helper function for the dock manager to flag this widget
@@ -114,7 +118,30 @@ public:
};
/**
* Default Constructor
* This mode configures the behavior of the toggle view action.
* If the mode if ActionModeToggle, then the toggle view action is
* a checkable action to show / hide the dock widget. If the mode
* is ActionModeShow, then the action is not checkable an it will
* always show the dock widget if clicked. If the mode is ActionModeShow,
* the user can only close the DockWidget with the close button.
*/
enum eToggleViewActionMode
{
ActionModeToggle,//!< ActionModeToggle
ActionModeShow //!< ActionModeShow
};
/**
* This constructor creates a dock widget with the given title.
* The title is the text that is shown in the window title when the dock
* widget is floating and it is the title that is shown in the titlebar
* or the tab of this dock widget if it is tabified.
* The object name of the dock widget is also set to the title. The
* object name is required by the dock manager to properly save and restore
* the state of the dock widget. That means, the title needs to be unique.
* If your title is not unique or if you would like to change the title
* during runtime, you need to set a unique object name explicitely
* by calling setObjectName() after construction.
*/
CDockWidget(const QString &title, QWidget* parent = 0);
@@ -137,13 +164,19 @@ public:
/**
* Returns the title bar widget of this dock widget
*/
CDockWidgetTitleBar* titleBar() const;
CDockWidgetTab* titleBar() const;
/**
* Sets, whether the dock widget is movable, closable, and floatable.
*/
void setFeatures(DockWidgetFeatures features);
/**
* Sets the feature flag for this dock widget if on is true; otherwise
* clears the flag.
*/
void setFeature(DockWidgetFeature flag, bool on);
/**
* This property holds whether the dock widget is movable, closable, and
* floatable.
@@ -187,7 +220,26 @@ public:
QAction* toggleViewAction() const;
/**
* Emits titleChanged signal if title change event occures
* Configures the behavior of the toggle view action.
* \see eToggleViewActionMode for a detailed description
*/
void setToggleViewActionMode(eToggleViewActionMode Mode);
/**
* Sets the dock widget icon that is shown in tabs and in toggle view
* actions
*/
void setIcon(const QIcon& Icon);
/**
* Returns tzhe icon that has been assigned to the dock widget
*/
QIcon icon() const;
public: // reimplements QFrame -----------------------------------------------
/**
* Emits titleChanged signal if title change event occurs
*/
virtual bool event(QEvent *e) override;
@@ -196,7 +248,7 @@ public slots:
* This property controls whether the dock widget is open or closed.
* The toogleViewAction triggers this slot
*/
void toggleView(bool Open);
void toggleView(bool Open = true);
signals:
/**

View File

@@ -18,17 +18,17 @@
//============================================================================
/// \file DockWidgetTitleBar.cpp
/// \file DockWidgetTab.cpp
/// \author Uwe Kindler
/// \date 27.02.2017
/// \brief Implementation of CDockWidgetTitleBar class
/// \brief Implementation of CDockWidgetTab class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "DockWidgetTitleBar.h"
#include "DockWidgetTab.h"
#include <QBoxLayout>
#include <QLabel>
@@ -60,11 +60,11 @@ enum eDragState
/**
* Private data class of CDockWidgetTitleBar class (pimpl)
* Private data class of CDockWidgetTab class (pimpl)
*/
struct DockWidgetTitleBarPrivate
struct DockWidgetTabPrivate
{
CDockWidgetTitleBar* _this;
CDockWidgetTab* _this;
CDockWidget* DockWidget;
QLabel* IconLabel;
QLabel* TitleLabel;
@@ -73,11 +73,12 @@ struct DockWidgetTitleBarPrivate
CDockAreaWidget* DockArea = nullptr;
eDragState DragState = DraggingInactive;
CFloatingDockContainer* FloatingWidget = nullptr;
QIcon Icon;
/**
* Private data constructor
*/
DockWidgetTitleBarPrivate(CDockWidgetTitleBar* _public);
DockWidgetTabPrivate(CDockWidgetTab* _public);
/**
* Creates the complete layout including all controls
@@ -114,11 +115,11 @@ struct DockWidgetTitleBarPrivate
*/
bool startFloating();
};
// struct DockWidgetTitleBarPrivate
// struct DockWidgetTabPrivate
//============================================================================
DockWidgetTitleBarPrivate::DockWidgetTitleBarPrivate(CDockWidgetTitleBar* _public) :
DockWidgetTabPrivate::DockWidgetTabPrivate(CDockWidgetTab* _public) :
_this(_public)
{
@@ -126,7 +127,7 @@ DockWidgetTitleBarPrivate::DockWidgetTitleBarPrivate(CDockWidgetTitleBar* _publi
//============================================================================
void DockWidgetTitleBarPrivate::createLayout()
void DockWidgetTabPrivate::createLayout()
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight);
l->setContentsMargins(0, 0, 0, 0);
@@ -137,6 +138,7 @@ void DockWidgetTitleBarPrivate::createLayout()
l->addWidget(IconLabel, Qt::AlignVCenter);
TitleLabel = new QLabel();
TitleLabel->setObjectName("dockWidgetTabLabel");
l->addWidget(TitleLabel, 1);
IconLabel->setVisible(false);
@@ -145,7 +147,7 @@ void DockWidgetTitleBarPrivate::createLayout()
}
//============================================================================
void DockWidgetTitleBarPrivate::moveTab(QMouseEvent* ev)
void DockWidgetTabPrivate::moveTab(QMouseEvent* ev)
{
ev->accept();
int left, top, right, bottom;
@@ -158,13 +160,13 @@ void DockWidgetTitleBarPrivate::moveTab(QMouseEvent* ev)
//============================================================================
bool DockWidgetTitleBarPrivate::startFloating()
bool DockWidgetTabPrivate::startFloating()
{
qDebug() << "isFloating " << DockWidget->dockContainer()->isFloating();
qDebug() << "areaCount " << DockWidget->dockContainer()->dockAreaCount();
qDebug() << "widgetCount " << DockWidget->dockAreaWidget()->count();
// if this is the last dock widget inside of this floating widget,
// then it does not make any sense, to make if floating because
// then it does not make any sense, to make it floating because
// it is already floating
if (DockWidget->dockContainer()->isFloating()
&& (DockWidget->dockContainer()->visibleDockAreaCount() == 1)
@@ -184,7 +186,7 @@ bool DockWidgetTitleBarPrivate::startFloating()
}
else
{
qDebug() << "DockWidgetTitleBarPrivate::startFloating DockArea";
qDebug() << "DockWidgetTabPrivate::startFloating DockArea";
// If section widget has only one content widget, we can move the complete
// dock area into floating widget
FloatingWidget = new CFloatingDockContainer(DockArea);
@@ -199,9 +201,9 @@ bool DockWidgetTitleBarPrivate::startFloating()
//============================================================================
CDockWidgetTitleBar::CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget *parent) :
CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) :
QFrame(parent),
d(new DockWidgetTitleBarPrivate(this))
d(new DockWidgetTabPrivate(this))
{
setAttribute(Qt::WA_NoMousePropagation, true);
d->DockWidget = DockWidget;
@@ -209,19 +211,19 @@ CDockWidgetTitleBar::CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget *paren
}
//============================================================================
CDockWidgetTitleBar::~CDockWidgetTitleBar()
CDockWidgetTab::~CDockWidgetTab()
{
qDebug() << "~CDockWidgetTitleBar()";
qDebug() << "~CDockWidgetTab()";
delete d;
}
//============================================================================
void CDockWidgetTitleBar::mousePressEvent(QMouseEvent* ev)
void CDockWidgetTab::mousePressEvent(QMouseEvent* ev)
{
if (ev->button() == Qt::LeftButton)
{
qDebug() << "CDockWidgetTitleBar::mousePressEvent";
qDebug() << "CDockWidgetTab::mousePressEvent";
ev->accept();
d->DragStartMousePosition = ev->pos();
d->DragState = DraggingMousePressed;
@@ -233,22 +235,22 @@ void CDockWidgetTitleBar::mousePressEvent(QMouseEvent* ev)
//============================================================================
void CDockWidgetTitleBar::mouseReleaseEvent(QMouseEvent* ev)
void CDockWidgetTab::mouseReleaseEvent(QMouseEvent* ev)
{
qDebug() << "CDockWidgetTitleBar::mouseReleaseEvent";
qDebug() << "CDockWidgetTab::mouseReleaseEvent";
// End of tab moving, change order now
if (d->isDraggingState(DraggingTab) && d->DockArea)
{
// Find tab under mouse
QPoint pos = d->DockArea->mapFromGlobal(ev->globalPos());
int fromIndex = d->DockArea->tabIndex(d->DockWidget);
int toIndex = d->DockArea->indexOfContentByTitlePos(pos, this);
if (-1 == toIndex)
{
toIndex = d->DockArea->count() - 1;
}
qDebug() << "Move tab from " << fromIndex << " to " << toIndex;
d->DockArea->reorderDockWidget(fromIndex, toIndex);
int fromIndex = d->DockArea->tabIndex(d->DockWidget);
int toIndex = d->DockArea->indexOfContentByTitlePos(pos, this);
if (-1 == toIndex)
{
toIndex = d->DockArea->count() - 1;
}
qDebug() << "Move tab from " << fromIndex << " to " << toIndex;
d->DockArea->reorderDockWidget(fromIndex, toIndex);
}
if (!d->DragStartMousePosition.isNull())
@@ -263,10 +265,8 @@ void CDockWidgetTitleBar::mouseReleaseEvent(QMouseEvent* ev)
//============================================================================
void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev)
{
/*std::cout << "CDockWidgetTitleBar::mouseMoveEventmouseMoveEvent DragState "
<< d->DragState << std::endl;*/
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
{
d->DragState = DraggingInactive;
@@ -274,10 +274,10 @@ void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
return;
}
// move floating winwdow
if (d->isDraggingState(DraggingFloatingWidget))
{
//std::cout << "DraggingFloatingWidget" << std::endl;
d->FloatingWidget->moveFloating();
d->FloatingWidget->moveFloating();
QFrame::mouseMoveEvent(ev);
return;
}
@@ -285,13 +285,19 @@ void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
// move tab
if (d->isDraggingState(DraggingTab))
{
d->moveTab(ev);
// Moving the tab is always allowed because it does not mean moving the
// dock widget around
d->moveTab(ev);
}
bool MouseInsideTitleArea = d->titleAreaGeometryContains(ev->globalPos());
if (!MouseInsideTitleArea)
{
d->startFloating();
// Floating is only allowed for widgets that are movable
if (d->DockWidget->features().testFlag(CDockWidget::DockWidgetMovable))
{
d->startFloating();
}
return;
}
else if (d->DockArea->count() > 1
@@ -306,14 +312,14 @@ void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
//============================================================================
bool CDockWidgetTitleBar::isActiveTab() const
bool CDockWidgetTab::isActiveTab() const
{
return d->IsActiveTab;
}
//============================================================================
void CDockWidgetTitleBar::setActiveTab(bool active)
void CDockWidgetTab::setActiveTab(bool active)
{
if (d->IsActiveTab == active)
{
@@ -332,25 +338,41 @@ void CDockWidgetTitleBar::setActiveTab(bool active)
//============================================================================
CDockWidget* CDockWidgetTitleBar::dockWidget() const
CDockWidget* CDockWidgetTab::dockWidget() const
{
return d->DockWidget;
}
//============================================================================
void CDockWidgetTitleBar::setDockAreaWidget(CDockAreaWidget* DockArea)
void CDockWidgetTab::setDockAreaWidget(CDockAreaWidget* DockArea)
{
d->DockArea = DockArea;
}
//============================================================================
CDockAreaWidget* CDockWidgetTitleBar::dockAreaWidget() const
CDockAreaWidget* CDockWidgetTab::dockAreaWidget() const
{
return d->DockArea;
}
//============================================================================
void CDockWidgetTab::setIcon(const QIcon& Icon)
{
d->Icon = Icon;
d->IconLabel->setPixmap(Icon.pixmap(this->windowHandle(), QSize(16, 16)));
d->IconLabel->setVisible(true);
}
//============================================================================
const QIcon& CDockWidgetTab::icon() const
{
return d->Icon;
}
} // namespace ads
//---------------------------------------------------------------------------
// EOF DockWidgetTitleBar.cpp
// EOF DockWidgetTab.cpp

View File

@@ -1,29 +1,29 @@
#ifndef DockWidgetTitleBarH
#define DockWidgetTitleBarH
#ifndef DockWidgetTabH
#define DockWidgetTabH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockWidgetTitleBar.h
/// \file DockWidgetTab.h
/// \author Uwe Kindler
/// \date 27.02.2017
/// \brief Declaration of CDockWidgetTitleBar class
/// \brief Declaration of CDockWidgetTab class
//============================================================================
@@ -32,23 +32,27 @@
//============================================================================
#include <QFrame>
#include "ads_globals.h"
namespace ads
{
class CDockWidget;
class CDockAreaWidget;
struct DockWidgetTitleBarPrivate;
struct DockWidgetTabPrivate;
/**
* A dock widget title bar that shows a title and an icon
* A dock widget tab that shows a title and an icon.
* The dock widget tab is shown in the dock area title bar to switch between
* tabbed dock widgets
*/
class CDockWidgetTitleBar : public QFrame
class ADS_EXPORT CDockWidgetTab : public QFrame
{
Q_OBJECT
Q_PROPERTY(bool activeTab READ isActiveTab WRITE setActiveTab NOTIFY activeTabChanged)
private:
DockWidgetTitleBarPrivate* d; ///< private data (pimpl)
friend class DockWidgetTitleBarPrivate;
DockWidgetTabPrivate* d; ///< private data (pimpl)
friend struct DockWidgetTabPrivate;
protected:
virtual void mousePressEvent(QMouseEvent* ev) override;
@@ -61,12 +65,12 @@ public:
* param[in] DockWidget The dock widget this title bar belongs to
* param[in] parent The parent widget of this title bar
*/
CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget* parent = 0);
CDockWidgetTab(CDockWidget* DockWidget, QWidget* parent = 0);
/**
* Virtual Destructor
*/
virtual ~CDockWidgetTitleBar();
virtual ~CDockWidgetTab();
/**
* Returns true, if this is the active tab
@@ -96,11 +100,21 @@ public:
*/
CDockAreaWidget* dockAreaWidget() const;
/**
* Sets the icon to show in title bar
*/
void setIcon(const QIcon& Icon);
/**
* Returns the icon
*/
const QIcon& icon() const;
signals:
void activeTabChanged();
void clicked();
}; // class DockWidgetTitleBar
}; // class DockWidgetTab
}
// namespace ads
//-----------------------------------------------------------------------------
#endif // DockWidgetTitleBarH
#endif // DockWidgetTabH

View File

@@ -59,6 +59,7 @@ struct FloatingDockContainerPrivate
unsigned int zOrderIndex = ++zOrderCounter;
QPointer<CDockManager> DockManager;
bool DraggingActive = false;
bool NonClientAreaMouseButtonPress = false;
QPoint DragStartMousePosition;
CDockContainerWidget* DropContainer = nullptr;
CDockAreaWidget* SingleDockArea = nullptr;
@@ -92,19 +93,24 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
return;
}
// Resize the floating widget to the size of the highlighted drop area
// rectangle
QRect Rect = DockManager->containerOverlay()->dropOverlayRect();
if (!Rect.isValid())
if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
|| DockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea)
{
Rect = DockManager->dockAreaOverlay()->rect();
// Resize the floating widget to the size of the highlighted drop area
// rectangle
QRect Rect = DockManager->containerOverlay()->dropOverlayRect();
if (!Rect.isValid())
{
Rect = DockManager->dockAreaOverlay()->rect();
}
if (Rect.isValid())
{
_this->resize(Rect.size());
}
DropContainer->dropFloatingWidget(_this, QCursor::pos());
}
if (Rect.isValid())
{
_this->resize(Rect.size());
}
DropContainer->dropFloatingWidget(_this, QCursor::pos());
DockManager->containerOverlay()->hideOverlay();
DockManager->dockAreaOverlay()->hideOverlay();
}
@@ -157,15 +163,29 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
ContainerOverlay->setAllowedAreas(VisibleDockAreas > 1 ?
OuterDockAreas : AllDockAreas);
ContainerOverlay->showOverlay(TopContainer);
DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
{
DockAreaOverlay->enableDropPreview(true);
DockAreaOverlay->setAllowedAreas((VisibleDockAreas == 1) ?
NoDockWidgetArea : AllDockAreas);
DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);
// A CenterDockWidgetArea for the dockAreaOverlay() indicates that
// the mouse is in the title bar. If the ContainerArea is valid
// then we ignore the dock area of the dockAreaOverlay() and disable
// the drop preview
if ((Area == CenterDockWidgetArea) && (ContainerArea != InvalidDockWidgetArea))
{
DockAreaOverlay->enableDropPreview(false);
ContainerOverlay->enableDropPreview(true);
}
else
{
ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);
}
}
else
{
@@ -178,6 +198,10 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
void FloatingDockContainerPrivate::setDraggingActive(bool Active)
{
DraggingActive = Active;
if (!DraggingActive)
{
NonClientAreaMouseButtonPress = false;
}
}
@@ -186,7 +210,6 @@ CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) :
QWidget(DockManager, Qt::Window),
d(new FloatingDockContainerPrivate(this))
{
//setAttribute(Qt::WA_DeleteOnClose);
d->DockManager = DockManager;
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
@@ -276,15 +299,20 @@ void CFloatingDockContainer::moveEvent(QMoveEvent *event)
//============================================================================
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
{
qDebug() << "CFloatingDockContainer closeEvent";
d->setDraggingActive(false);
QWidget::closeEvent(event);
if (isClosable())
QWidget::closeEvent(event);
else
event->ignore();
}
//============================================================================
void CFloatingDockContainer::hideEvent(QHideEvent *event)
{
qDebug() << "CFloatingDockContainer hideEvent";
QWidget::hideEvent(event);
auto OpenDockAreas = d->DockContainer->openedDockAreas();
for (auto DockArea : OpenDockAreas)
@@ -292,7 +320,7 @@ void CFloatingDockContainer::hideEvent(QHideEvent *event)
auto OpenDockWidgets = DockArea->openedDockWidgets();
for (auto DockWidget : OpenDockWidgets)
{
DockWidget->setToggleViewActionChecked(false);
DockWidget->toggleView(false);
}
}
}
@@ -317,12 +345,13 @@ void CFloatingDockContainer::showEvent(QShowEvent *event)
//============================================================================
bool CFloatingDockContainer::event(QEvent *e)
{
if ((e->type() == QEvent::NonClientAreaMouseButtonPress))
if (e->type() == QEvent::NonClientAreaMouseButtonPress)
{
if (QGuiApplication::mouseButtons() == Qt::LeftButton)
{
qDebug() << "FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type();
d->setDraggingActive(true);
d->NonClientAreaMouseButtonPress = true;
}
}
else if (e->type() == QEvent::NonClientAreaMouseButtonDblClick)
@@ -335,6 +364,20 @@ bool CFloatingDockContainer::event(QEvent *e)
qDebug() << "FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease";
d->titleMouseReleaseEvent();
}
else if (d->NonClientAreaMouseButtonPress && (e->type() == QEvent::Resize))
{
// If user resizes the floating widget, we do not want to show any
// drop overlays or drop overlay icons. If the window is maximized,
// then dragging the window via title bar will cause the widget to
// leave the maximized state. This in turn will trigger a resize event.
// To know, if the resize event was triggered by user via moving a
// corner of the window frame or if it was caused by a windows state
// change, we check, if we are not in maximized state.
if (!isMaximized())
{
d->setDraggingActive(false);
}
}
return QWidget::event(e);
}
@@ -375,6 +418,25 @@ void CFloatingDockContainer::moveFloating()
}
//============================================================================
bool CFloatingDockContainer::isClosable() const
{
auto OpenDockAreas = d->DockContainer->openedDockAreas();
for (auto DockArea : OpenDockAreas)
{
auto OpenDockWidgets = DockArea->openedDockWidgets();
for (auto DockWidget : OpenDockWidgets)
{
if (!DockWidget->features().testFlag(CDockWidget::DockWidgetClosable))
{
return false;
}
}
}
return true;
}
//============================================================================
void CFloatingDockContainer::onDockAreasAddedOrRemoved()
{
@@ -408,7 +470,7 @@ void CFloatingDockContainer::onDockAreaCurrentChanged(int Index)
//============================================================================
bool CFloatingDockContainer::restoreState(QDataStream& Stream, bool Testing)
bool CFloatingDockContainer::restoreState(QXmlStreamReader& Stream, bool Testing)
{
if (!d->DockContainer->restoreState(Stream, Testing))
{

View File

@@ -3,17 +3,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -31,30 +31,66 @@
//============================================================================
#include <QWidget>
#include "ads_globals.h"
class QXmlStreamReader;
namespace ads
{
struct FloatingDockContainerPrivate;
class CDockManager;
struct DockManagerPrivate;
class CDockAreaWidget;
class CDockContainerWidget;
class CDockWidget;
class CDockManager;
class CDockAreaTabBar;
class CDockWidgetTab;
struct DockWidgetTabPrivate;
/**
* This implements a floating widget that is a dock container that accepts
* docking of dock widgets like the main window and that can be docked into
* another dock container
*/
class CFloatingDockContainer : public QWidget
class ADS_EXPORT CFloatingDockContainer : public QWidget
{
Q_OBJECT
private:
FloatingDockContainerPrivate* d; ///< private data (pimpl)
friend class FloatingDockContainerPrivate;
friend struct FloatingDockContainerPrivate;
friend class CDockManager;
friend struct DockManagerPrivate;
friend class CDockAreaTabBar;
friend struct DockWidgetTabPrivate;
friend class CDockWidgetTab;
private slots:
void onDockAreasAddedOrRemoved();
void onDockAreaCurrentChanged(int Index);
protected:
/**
* Starts floating at the given global position.
* Use moveToGlobalPos() to move the widget to a new position
* depending on the start position given in Pos parameter
*/
void startFloating(const QPoint& Pos, const QSize& Size = QSize());
/**
* Moves the widget to a new position relative to the position given when
* startFloating() was called
*/
void moveFloating();
/**
* Restores the state from given stream.
* If Testing is true, the function only parses the data from the given
* stream but does not restore anything. You can use this check for
* faulty files before you start restoring the state
*/
bool restoreState(QXmlStreamReader& Stream, bool Testing);
protected: // reimplements QWidget
virtual void changeEvent(QEvent *event) override;
@@ -92,25 +128,10 @@ public:
CDockContainerWidget* dockContainer() const;
/**
* Starts floating at the given global position.
* Use moveToGlobalPos() to move the widget to a new position
* depending on the start position given in Pos parameter
* This function returns true, if it can be closed.
* It can be closed, if all dock widgets in all dock areas can be closed
*/
void startFloating(const QPoint& Pos, const QSize& Size = QSize());
/**
* Moves the widget to a new position relative to the position given when
* startFloating() was called
*/
void moveFloating();
/**
* Restores the state from given stream.
* If Testing is true, the function only parses the data from the given
* stream but does not restore anything. You can use this check for
* faulty files before you start restoring the state
*/
bool restoreState(QDataStream& Stream, bool Testing);
bool isClosable() const;
}; // class FloatingDockContainer
}
// namespace ads

View File

@@ -1,17 +1,17 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
@@ -62,12 +62,12 @@ CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area)
{
switch (Area)
{
case TopDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Vertical, false);
case RightDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Horizontal, true);
case TopDockWidgetArea: return CDockInsertParam(Qt::Vertical, false);
case RightDockWidgetArea: return CDockInsertParam(Qt::Horizontal, true);
case CenterDockWidgetArea:
case BottomDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Vertical, true);
case LeftDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Horizontal, false);
default: QPair<Qt::Orientation, bool>(Qt::Vertical, false);
case BottomDockWidgetArea: return CDockInsertParam(Qt::Vertical, true);
case LeftDockWidgetArea: return CDockInsertParam(Qt::Horizontal, false);
default: CDockInsertParam(Qt::Vertical, false);
} // switch (Area)
return CDockInsertParam(Qt::Vertical, false);

View File

@@ -31,6 +31,13 @@
// INCLUDES
//============================================================================
#include <QPair>
#include <QtCore/QtGlobal>
#ifdef ADS_SHARED_EXPORT
#define ADS_EXPORT Q_DECL_EXPORT
#else
#define ADS_EXPORT Q_DECL_IMPORT
#endif
class QSplitter;

View File

@@ -11,7 +11,7 @@ CONFIG += adsBuildShared
adsBuildShared {
CONFIG += shared
DEFINES += ADS_EXPORT
DEFINES += ADS_SHARED_EXPORT
}
!adsBuildShared {
CONFIG += staticlib
@@ -33,10 +33,11 @@ RESOURCES += ads.qrc
HEADERS += \
ads_globals.h \
DockAreaWidget.h \
DockAreaTabBar.h \
DockContainerWidget.h \
DockManager.h \
DockWidget.h \
DockWidgetTitleBar.h \
DockWidgetTab.h \
FloatingDockContainer.h \
DockOverlay.h \
DockSplitter.h
@@ -46,10 +47,11 @@ HEADERS += \
SOURCES += \
ads_globals.cpp \
DockAreaWidget.cpp \
DockAreaTabBar.cpp \
DockContainerWidget.cpp \
DockManager.cpp \
DockWidget.cpp \
DockWidgetTitleBar.cpp \
DockWidgetTab.cpp \
FloatingDockContainer.cpp \
DockOverlay.cpp \
DockSplitter.cpp

View File

@@ -25,7 +25,7 @@ ads--CDockAreaWidget #tabsMenuButton::menu-indicator
image: none;
}
ads--CDockWidgetTitleBar
ads--CDockWidgetTab
{
background: palette(window);
border-color: palette(light);
@@ -34,17 +34,17 @@ ads--CDockWidgetTitleBar
padding: 0 9px;
}
ads--CDockWidgetTitleBar[activeTab="true"]
ads--CDockWidgetTab[activeTab="true"]
{
background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:0.5, stop:0 palette(window), stop:1 palette(light));
}
ads--CDockWidgetTitleBar QLabel
ads--CDockWidgetTab QLabel
{
color: palette(dark);
}
ads--CDockWidgetTitleBar[activeTab="true"] QLabel
ads--CDockWidgetTab[activeTab="true"] QLabel
{
color: palette(foreground);
}