Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3f5b668e5 | ||
|
|
82d15fbe29 | ||
|
|
01533a9f85 | ||
|
|
fb9f1d851b | ||
|
|
6fb80fdeb7 | ||
|
|
e94cf9bcb7 | ||
|
|
da0ec6dd4b | ||
|
|
80efed693e | ||
|
|
653f475e72 | ||
|
|
87e3777e37 | ||
|
|
71f66ea6dc | ||
|
|
0b3f419c80 | ||
|
|
f69af82a49 | ||
|
|
854f542164 | ||
|
|
b9265fccec | ||
|
|
b3a272110a | ||
|
|
316e5324ad | ||
|
|
6843703484 | ||
|
|
115a9a5b3d | ||
|
|
a4838a41ac | ||
|
|
74b9d35c7b | ||
|
|
c973482b2b | ||
|
|
188624440b | ||
|
|
72ec61a043 | ||
|
|
0ac19ebdfb | ||
|
|
bc6ffcc02c | ||
|
|
a9246f7ce4 | ||
|
|
3f5697554a | ||
|
|
5e6c82b68d | ||
|
|
268f8655a1 | ||
|
|
1dfabb3bef | ||
|
|
6617cf6f19 | ||
|
|
81523b0346 | ||
|
|
927be9a7d9 | ||
|
|
ada3d6b3b5 | ||
|
|
30bbd26d0a | ||
|
|
8637c89a6b | ||
|
|
11e5f9c95a | ||
|
|
9bfb3fbea1 | ||
|
|
9c95e34df5 | ||
|
|
ceebda7431 | ||
|
|
75288af88c | ||
|
|
7c67d71f68 | ||
|
|
548dfb363a | ||
|
|
9fec2bd515 | ||
|
|
fc04aa2411 | ||
|
|
c3a5e3ef21 | ||
|
|
0e85431405 | ||
|
|
b3b6d20d96 | ||
|
|
272bbe275e | ||
|
|
496aec211e | ||
|
|
b9b72df9d4 | ||
|
|
fcb1846bf5 | ||
|
|
9f1b2c122a | ||
|
|
6ec38b48ef | ||
|
|
b93e723a83 | ||
|
|
1a47918bdb | ||
|
|
ff9d965726 | ||
|
|
77d2cebe39 | ||
|
|
5d380708e1 | ||
|
|
aa7b36dbd1 | ||
|
|
c9123c3640 | ||
|
|
67199a81f4 | ||
|
|
72ee4a53df | ||
|
|
0b963d1540 | ||
|
|
9cd2584de5 | ||
|
|
3f40c997e5 | ||
|
|
6b93ae9c39 | ||
|
|
f5b3c0556d | ||
|
|
5b3841a038 | ||
|
|
9d00a278e6 | ||
|
|
b470dd5f99 | ||
|
|
7b4a19b943 | ||
|
|
8eceed9aa3 | ||
|
|
4188d69356 | ||
|
|
3fc7c195c3 | ||
|
|
f823b67a4a | ||
|
|
064cab405a | ||
|
|
75ad302d21 | ||
|
|
18a4f17fbf | ||
|
|
6266cd3290 | ||
|
|
8a401ebd68 | ||
|
|
805e97946e | ||
|
|
e878bb47ed | ||
|
|
dae852d9f9 | ||
|
|
8a014a6c2d | ||
|
|
9676eeb1bf | ||
|
|
412f13e1c4 | ||
|
|
11a30806f6 | ||
|
|
b9257bbe93 |
14
.astylerc
@@ -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
|
|
||||||
10
.cproject
@@ -24,6 +24,8 @@
|
|||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/demo}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/demo}""/>
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/src}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/src}""/>
|
||||||
<listOptionValue builtIn="false" value=""${QTDIR}/include""/>
|
<listOptionValue builtIn="false" value=""${QTDIR}/include""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${QTDIR}/include/QtCore""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${QTDIR}/include/QtWidgets""/>
|
||||||
</option>
|
</option>
|
||||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1249325593" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1249325593" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||||
</tool>
|
</tool>
|
||||||
@@ -33,8 +35,10 @@
|
|||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/src}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/src}""/>
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/demo}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/demo}""/>
|
||||||
<listOptionValue builtIn="false" value=""${QTDIR}/include""/>
|
<listOptionValue builtIn="false" value=""${QTDIR}/include""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${QTDIR}/include/QtCore""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${QTDIR}/include/QtWidgets""/>
|
||||||
</option>
|
</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"/>
|
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1318830536" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
|
||||||
</tool>
|
</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">
|
<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=""${workspace_loc:/QtAdvancedDockingSystem/demo}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/demo}""/>
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/src}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/QtAdvancedDockingSystem/src}""/>
|
||||||
<listOptionValue builtIn="false" value=""${QTDIR}/include""/>
|
<listOptionValue builtIn="false" value=""${QTDIR}/include""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${QTDIR}/include/QtCore""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${QTDIR}/include/QtWidgets""/>
|
||||||
</option>
|
</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"/>
|
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1568363924" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||||
</tool>
|
</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"/>
|
<tool id="cdt.managedbuild.tool.gnu.c.linker.mingw.base.1734874312" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.base"/>
|
||||||
|
|||||||
@@ -2,10 +2,7 @@
|
|||||||
<project>
|
<project>
|
||||||
<configuration id="cdt.managedbuild.toolchain.gnu.mingw.base.1119687795" name="Default">
|
<configuration id="cdt.managedbuild.toolchain.gnu.mingw.base.1119687795" name="Default">
|
||||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
<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 "${INPUTS}"" prefer-non-shared="true">
|
<provider-reference id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetectorMinGW" ref="shared-provider"/>
|
||||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
|
||||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
|
||||||
</provider>
|
|
||||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||||
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuildCommandParser" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser" keep-relative-paths="false" name="CDT GCC Build Output Parser" parameter="(g?cc)|([gc]\+\+)|(clang)" prefer-non-shared="true"/>
|
<provider class="org.eclipse.cdt.managedbuilder.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"/>
|
||||||
|
|||||||
24
.travis.yml
@@ -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
|
|
||||||
BIN
MainWindow.dat
24
README.md
@@ -19,23 +19,37 @@ There is no central widget like in the Qt docking system. You can dock on every
|
|||||||
border of the main window or you can dock into each dock area - so you are
|
border of the main window or you can dock into each dock area - so you are
|
||||||
free to dock almost everywhere.
|
free to dock almost everywhere.
|
||||||
|
|
||||||

|
\
|
||||||
|
\
|
||||||

|

|
||||||
|
|
||||||
### Docking inside floating windows
|
### Docking inside floating windows
|
||||||
There is no difference between the main window and a floating window. Docking
|
There is no difference between the main window and a floating window. Docking
|
||||||
into floating windows is supported.
|
into floating windows is supported.
|
||||||
|
|
||||||

|
\
|
||||||
|
\
|
||||||
|

|
||||||
|
|
||||||
### Grouped dragging
|
### Grouped dragging
|
||||||
When dragging the titlebar of a dock, all the tabs that are tabbed with it are
|
When dragging the titlebar of a dock, all the tabs that are tabbed with it are
|
||||||
going to be dragged. So you can move complete groups of tabbed widgets into
|
going to be dragged. So you can move complete groups of tabbed widgets into
|
||||||
a floating widget or from one dock area to another one.
|
a floating widget or from one dock area to another one.
|
||||||
|
|
||||||

|
\
|
||||||
|
\
|
||||||
|

|
||||||
|
|
||||||
|
### Perspectives for fast switching of the complete main window layout
|
||||||
|
A perspective defines the set and layout of dock windows in the main
|
||||||
|
window. You can save the current layout of the dockmanager into a named
|
||||||
|
perspective to make your own custom perspective. Later you can simply
|
||||||
|
select a perspective from the perspective list to quickly switch the complete
|
||||||
|
main window layout.
|
||||||
|
|
||||||
|
\
|
||||||
|
\
|
||||||
|

|
||||||
|
|
||||||
## Tested Compatible Environments
|
## Tested Compatible Environments
|
||||||
- Windows 10
|
- Windows 10
|
||||||
|
|||||||
1
ads.pro
@@ -1,4 +1,5 @@
|
|||||||
TEMPLATE = subdirs
|
TEMPLATE = subdirs
|
||||||
|
CONFIG += ordered
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
src \
|
src \
|
||||||
|
|||||||
340
demo/MainWindow.cpp
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** 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"
|
||||||
|
#include "AnimatedLabel.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));
|
||||||
|
auto FileSystemWidget = createFileSystemTreeDockWidget(ViewMenu);
|
||||||
|
auto ToolBar = FileSystemWidget->createDefaultToolBar();
|
||||||
|
ToolBar->addAction(ui.actionSaveState);
|
||||||
|
ToolBar->addAction(ui.actionRestoreState);
|
||||||
|
DockManager->addDockWidget(ads::BottomDockWidgetArea, FileSystemWidget);
|
||||||
|
|
||||||
|
FileSystemWidget = createFileSystemTreeDockWidget(ViewMenu);
|
||||||
|
ToolBar = FileSystemWidget->createDefaultToolBar();
|
||||||
|
ToolBar->addAction(ui.actionSaveState);
|
||||||
|
ToolBar->addAction(ui.actionRestoreState);
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
using namespace ads;
|
||||||
|
d->ui.setupUi(this);
|
||||||
|
d->createActions();
|
||||||
|
|
||||||
|
// Now create the dock manager and its content
|
||||||
|
d->DockManager = new CDockManager(this);
|
||||||
|
|
||||||
|
// Uncomment the following line to have the old style where the dock
|
||||||
|
// area close button closes the active tab
|
||||||
|
//d->DockManager->setConfigFlags({
|
||||||
|
// CDockManager::DockAreaHasCloseButton | CDockManager::DockAreaCloseButtonClosesTab});
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,55 +1,63 @@
|
|||||||
#ifndef DockStateSerializationH
|
#ifndef MAINWINDOW_H
|
||||||
#define DockStateSerializationH
|
#define MAINWINDOW_H
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
/// \file DockStateSerialization.h
|
/// \file MainWindow.h
|
||||||
/// \author Uwe Kindler
|
/// \author Uwe Kindler
|
||||||
/// \date 26.02.2017
|
/// \date 13.02.2018
|
||||||
/// \brief Declaration of serialization related data, constants and stuff
|
/// \brief Declaration of CMainWindow class
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
// INCLUDES
|
// INCLUDES
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
|
||||||
namespace ads
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace internal
|
struct MainWindowPrivate;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple main window for demo
|
||||||
|
*/
|
||||||
|
class CMainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
// sentinel values used to validate state data
|
Q_OBJECT
|
||||||
enum VersionMarkers
|
private:
|
||||||
{
|
MainWindowPrivate* d;///< private data - pimpl
|
||||||
VersionMarker = 0xff,
|
friend struct MainWindowPrivate;
|
||||||
ContainerMarker = 0xfe,
|
|
||||||
SplitterMarker = 0xfd,
|
protected:
|
||||||
DockAreaMarker = 0xfc,
|
virtual void closeEvent(QCloseEvent* event) override;
|
||||||
DockWidgetMarker = 0xfb
|
|
||||||
|
public:
|
||||||
|
explicit CMainWindow(QWidget *parent = 0);
|
||||||
|
virtual ~CMainWindow();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_actionSaveState_triggered(bool);
|
||||||
|
void on_actionRestoreState_triggered(bool);
|
||||||
|
void savePerspective();
|
||||||
};
|
};
|
||||||
|
|
||||||
static const bool RestoreTesting = true;
|
#endif // MAINWINDOW_H
|
||||||
static const bool Restore = false;
|
|
||||||
} // internal
|
|
||||||
} // namespace ads
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
#endif // DockManagerH
|
|
||||||
@@ -4,33 +4,27 @@ ADS_OUT_ROOT = $${OUT_PWD}/..
|
|||||||
TARGET = AdvancedDockingSystemDemo
|
TARGET = AdvancedDockingSystemDemo
|
||||||
DESTDIR = $${ADS_OUT_ROOT}/lib
|
DESTDIR = $${ADS_OUT_ROOT}/lib
|
||||||
QT += core gui widgets
|
QT += core gui widgets
|
||||||
|
CONFIG *= c++14
|
||||||
|
|
||||||
windows {
|
|
||||||
# MinGW
|
|
||||||
*-g++* {
|
|
||||||
QMAKE_CXXFLAGS += -std=c++11
|
|
||||||
}
|
|
||||||
# MSVC
|
|
||||||
*-msvc* {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
mainwindow.cpp
|
MainWindow.cpp
|
||||||
|
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
mainwindow.h
|
MainWindow.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
mainwindow.ui
|
mainwindow.ui
|
||||||
|
|
||||||
|
RESOURCES += main.qrc
|
||||||
|
|
||||||
LIBS += -L$${ADS_OUT_ROOT}/lib
|
LIBS += -L$${ADS_OUT_ROOT}/lib
|
||||||
|
|
||||||
# Dependency: AdvancedDockingSystem (shared)
|
# Dependency: AdvancedDockingSystem (shared)
|
||||||
win32:CONFIG(release, debug|release): LIBS += -lAdvancedDockingSystem
|
win32:CONFIG(release, debug|release): LIBS += -lqtadvanceddocking
|
||||||
else:win32:CONFIG(debug, debug|release): LIBS += -lAdvancedDockingSystemd
|
else:win32:CONFIG(debug, debug|release): LIBS += -lqtadvanceddockingd
|
||||||
else:unix: LIBS += -lAdvancedDockingSystem
|
else:unix: LIBS += -lAdvancedDockingSystem
|
||||||
|
|
||||||
INCLUDEPATH += ../src
|
INCLUDEPATH += ../src
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <MainWindow.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -5,7 +8,6 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "mainwindow.h"
|
|
||||||
|
|
||||||
|
|
||||||
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
@@ -35,13 +37,15 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
|
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
std::shared_ptr<int> b;
|
std::shared_ptr<int> b;
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
a.setQuitOnLastWindowClosed(true);
|
a.setQuitOnLastWindowClosed(true);
|
||||||
qInstallMessageHandler(myMessageOutput);
|
qInstallMessageHandler(myMessageOutput);
|
||||||
qDebug() << "Message handler test";
|
qDebug() << "Message handler test";
|
||||||
|
|
||||||
MainWindow mw;
|
CMainWindow mw;
|
||||||
mw.show();
|
mw.show();
|
||||||
return a.exec();
|
return a.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
7
demo/main.qrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/main">
|
||||||
|
<file>bricks.gif</file>
|
||||||
|
<file>bricks_orange.gif</file>
|
||||||
|
<file>bricks.apng</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
@@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -13,6 +13,9 @@
|
|||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>MainWindow</string>
|
<string>MainWindow</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="dockOptions">
|
||||||
|
<set>QMainWindow::AllowTabbedDocks</set>
|
||||||
|
</property>
|
||||||
<widget class="QWidget" name="centralWidget"/>
|
<widget class="QWidget" name="centralWidget"/>
|
||||||
<widget class="QStatusBar" name="statusBar"/>
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
<widget class="QMenuBar" name="menuBar">
|
<widget class="QMenuBar" name="menuBar">
|
||||||
@@ -46,6 +49,17 @@
|
|||||||
<addaction name="menuView"/>
|
<addaction name="menuView"/>
|
||||||
<addaction name="menuAbout"/>
|
<addaction name="menuAbout"/>
|
||||||
</widget>
|
</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">
|
<action name="actionExit">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Exit</string>
|
<string>Exit</string>
|
||||||
|
|||||||
BIN
doc/TabMenu.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
doc/TabMenu_dark.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
doc/floating-widget-dragndrop.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
doc/floating-widget-dragndrop_dark.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
doc/grouped-dragging.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
doc/grouped-dragging_dark.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
doc/perspectives.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
doc/perspectives_dark.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
doc/preview-dragndrop.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
doc/preview-dragndrop_dark.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
doc/preview_dark.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 82 KiB |
BIN
preview.png
|
Before Width: | Height: | Size: 57 KiB |
558
src/DockAreaTabBar.cpp
Normal file
@@ -0,0 +1,558 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** 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 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 <QBoxLayout>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private data class of CDockAreaTabBar class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockAreaTabBarPrivate
|
||||||
|
{
|
||||||
|
CDockAreaTabBar* _this;
|
||||||
|
QPoint DragStartMousePos;
|
||||||
|
CDockAreaWidget* DockArea;
|
||||||
|
CFloatingDockContainer* FloatingWidget = nullptr;
|
||||||
|
QWidget* TabsContainerWidget;
|
||||||
|
QBoxLayout* TabsLayout;
|
||||||
|
int CurrentIndex = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockAreaTabBarPrivate(CDockAreaTabBar* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update tabs after current index changed or when tabs are removed.
|
||||||
|
* The function reassigns the stylesheet to update the tabs
|
||||||
|
*/
|
||||||
|
void updateTabs();
|
||||||
|
};
|
||||||
|
// struct DockAreaTabBarPrivate
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockAreaTabBarPrivate::DockAreaTabBarPrivate(CDockAreaTabBar* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaTabBarPrivate::updateTabs()
|
||||||
|
{
|
||||||
|
// Set active TAB and update all other tabs to be inactive
|
||||||
|
for (int i = 0; i < _this->count(); ++i)
|
||||||
|
{
|
||||||
|
auto TabWidget = _this->tab(i);
|
||||||
|
if (!TabWidget)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == CurrentIndex)
|
||||||
|
{
|
||||||
|
TabWidget->show();
|
||||||
|
TabWidget->setActiveTab(true);
|
||||||
|
_this->ensureWidgetVisible(TabWidget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TabWidget->setActiveTab(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
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);
|
||||||
|
|
||||||
|
d->TabsContainerWidget = new QWidget();
|
||||||
|
d->TabsContainerWidget->setObjectName("tabsContainerWidget");
|
||||||
|
setWidget(d->TabsContainerWidget);
|
||||||
|
|
||||||
|
d->TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
|
d->TabsLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
d->TabsLayout->setSpacing(0);
|
||||||
|
d->TabsLayout->addStretch(1);
|
||||||
|
d->TabsContainerWidget->setLayout(d->TabsLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength();
|
||||||
|
if (DragDistance >= CDockManager::startDragDistance())
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CFloatingDockContainer* CDockAreaTabBar::makeAreaFloating(const QPoint& Pos)
|
||||||
|
{
|
||||||
|
QSize Size = d->DockArea->size();
|
||||||
|
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(d->DockArea);
|
||||||
|
FloatingWidget->startFloating(Pos, Size);
|
||||||
|
auto TopLevelDockWidget = FloatingWidget->topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FloatingWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::startFloating(const QPoint& Pos)
|
||||||
|
{
|
||||||
|
d->FloatingWidget = makeAreaFloating(Pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTabBar::setCurrentIndex(int index)
|
||||||
|
{
|
||||||
|
if (index == d->CurrentIndex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < -1 || index > (count() - 1))
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit currentChanging(index);
|
||||||
|
d->CurrentIndex = index;
|
||||||
|
d->updateTabs();
|
||||||
|
emit currentChanged(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaTabBar::count() const
|
||||||
|
{
|
||||||
|
// The tab bar contains a stretch item as last item
|
||||||
|
return d->TabsLayout->count() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::insertTab(int Index, CDockWidgetTab* Tab)
|
||||||
|
{
|
||||||
|
d->TabsLayout->insertWidget(Index, Tab);
|
||||||
|
connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked()));
|
||||||
|
connect(Tab, SIGNAL(closeRequested()), this, SLOT(onTabCloseRequested()));
|
||||||
|
connect(Tab, SIGNAL(closeOtherTabsRequested()), this, SLOT(onCloseOtherTabsRequested()));
|
||||||
|
connect(Tab, SIGNAL(moved(const QPoint&)), this, SLOT(onTabWidgetMoved(const QPoint&)));
|
||||||
|
Tab->installEventFilter(this);
|
||||||
|
emit tabInserted(Index);
|
||||||
|
if (Index <= d->CurrentIndex)
|
||||||
|
{
|
||||||
|
setCurrentIndex(d->CurrentIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab)
|
||||||
|
{
|
||||||
|
if (!count())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << "CDockAreaTabBar::removeTab ";
|
||||||
|
int NewCurrentIndex = currentIndex();
|
||||||
|
int RemoveIndex = d->TabsLayout->indexOf(Tab);
|
||||||
|
if (count() == 1)
|
||||||
|
{
|
||||||
|
NewCurrentIndex = -1;
|
||||||
|
}
|
||||||
|
if (NewCurrentIndex > RemoveIndex)
|
||||||
|
{
|
||||||
|
NewCurrentIndex--;
|
||||||
|
}
|
||||||
|
else if (NewCurrentIndex == RemoveIndex)
|
||||||
|
{
|
||||||
|
NewCurrentIndex = -1;
|
||||||
|
// First we walk to the right to search for the next visible tab
|
||||||
|
for (int i = (RemoveIndex + 1); i < count(); ++i)
|
||||||
|
{
|
||||||
|
if (tab(i)->isVisibleTo(this))
|
||||||
|
{
|
||||||
|
NewCurrentIndex = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no visible tab right to this tab then we walk to
|
||||||
|
// the left to find a visible tab
|
||||||
|
if (NewCurrentIndex < 0)
|
||||||
|
{
|
||||||
|
for (int i = (RemoveIndex - 1); i >= 0; --i)
|
||||||
|
{
|
||||||
|
if (tab(i)->isVisibleTo(this))
|
||||||
|
{
|
||||||
|
NewCurrentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emit removingTab(RemoveIndex);
|
||||||
|
d->TabsLayout->removeWidget(Tab);
|
||||||
|
Tab->disconnect(this);
|
||||||
|
Tab->removeEventFilter(this);
|
||||||
|
qDebug() << "NewCurrentIndex " << NewCurrentIndex;
|
||||||
|
if (NewCurrentIndex != d->CurrentIndex)
|
||||||
|
{
|
||||||
|
setCurrentIndex(NewCurrentIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->updateTabs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
int CDockAreaTabBar::currentIndex() const
|
||||||
|
{
|
||||||
|
return d->CurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CDockWidgetTab* CDockAreaTabBar::currentTab() const
|
||||||
|
{
|
||||||
|
if (d->CurrentIndex < 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(d->CurrentIndex)->widget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onTabClicked()
|
||||||
|
{
|
||||||
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
if (!Tab)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = d->TabsLayout->indexOf(Tab);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCurrentIndex(index);
|
||||||
|
emit tabBarClicked(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onTabCloseRequested()
|
||||||
|
{
|
||||||
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
int Index = d->TabsLayout->indexOf(Tab);
|
||||||
|
closeTab(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onCloseOtherTabsRequested()
|
||||||
|
{
|
||||||
|
auto Sender = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
for (int i = 0; i < count(); ++i)
|
||||||
|
{
|
||||||
|
auto Tab = tab(i);
|
||||||
|
if (Tab->isClosable() && !Tab->isHidden() && Tab != Sender)
|
||||||
|
{
|
||||||
|
closeTab(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CDockWidgetTab* CDockAreaTabBar::tab(int Index) const
|
||||||
|
{
|
||||||
|
if (Index >= count() || Index < 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(Index)->widget());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos)
|
||||||
|
{
|
||||||
|
CDockWidgetTab* MovingTab = qobject_cast<CDockWidgetTab*>(sender());
|
||||||
|
if (!MovingTab)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fromIndex = d->TabsLayout->indexOf(MovingTab);
|
||||||
|
auto MousePos = mapFromGlobal(GlobalPos);
|
||||||
|
int toIndex = -1;
|
||||||
|
// Find tab under mouse
|
||||||
|
for (int i = 0; i < count(); ++i)
|
||||||
|
{
|
||||||
|
CDockWidgetTab* DropTab = tab(i);
|
||||||
|
if (DropTab == MovingTab || !DropTab->isVisibleTo(this)
|
||||||
|
|| !DropTab->geometry().contains(MousePos))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
toIndex = d->TabsLayout->indexOf(DropTab);
|
||||||
|
if (toIndex == fromIndex)
|
||||||
|
{
|
||||||
|
toIndex = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toIndex < 0)
|
||||||
|
{
|
||||||
|
toIndex = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check if the mouse is behind the last tab
|
||||||
|
if (toIndex < 0)
|
||||||
|
{
|
||||||
|
if (MousePos.x() > tab(count() - 1)->geometry().right())
|
||||||
|
{
|
||||||
|
qDebug() << "after all tabs";
|
||||||
|
toIndex = count() - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toIndex = fromIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d->TabsLayout->removeWidget(MovingTab);
|
||||||
|
d->TabsLayout->insertWidget(toIndex, MovingTab);
|
||||||
|
if (toIndex >= 0)
|
||||||
|
{
|
||||||
|
qDebug() << "tabMoved from " << fromIndex << " to " << toIndex;
|
||||||
|
emit tabMoved(fromIndex, toIndex);
|
||||||
|
setCurrentIndex(toIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockAreaTabBar::closeTab(int Index)
|
||||||
|
{
|
||||||
|
if (Index < 0 || Index >= count())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Tab = tab(Index);
|
||||||
|
if (Tab->isHidden())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit tabCloseRequested(Index);
|
||||||
|
Tab->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
bool Result = Super::eventFilter(watched, event);
|
||||||
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(watched);
|
||||||
|
if (!Tab)
|
||||||
|
{
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event->type())
|
||||||
|
{
|
||||||
|
case QEvent::Hide:
|
||||||
|
emit tabClosed(d->TabsLayout->indexOf(Tab)); break;
|
||||||
|
case QEvent::Show:
|
||||||
|
emit tabOpened(d->TabsLayout->indexOf(Tab)); break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool CDockAreaTabBar::isTabOpen(int Index) const
|
||||||
|
{
|
||||||
|
if (Index < 0 || Index >= count())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !tab(Index)->isHidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockAreaTabBar.cpp
|
||||||
218
src/DockAreaTabBar.h
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
#ifndef DockAreaTabBarH
|
||||||
|
#define DockAreaTabBarH
|
||||||
|
/*******************************************************************************
|
||||||
|
** 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 DockAreaTabBar.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 24.08.2018
|
||||||
|
/// \brief Declaration of CDockAreaTabBar class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QScrollArea>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
class CDockAreaWidget;
|
||||||
|
class CDockWidgetTab;
|
||||||
|
struct DockAreaTabBarPrivate;
|
||||||
|
class CDockAreaTitleBar;
|
||||||
|
class CFloatingDockContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
friend class CDockAreaTitleBar;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onTabClicked();
|
||||||
|
void onTabCloseRequested();
|
||||||
|
void onCloseOtherTabsRequested();
|
||||||
|
void onTabWidgetMoved(const QPoint& GlobalPos);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the dock area loating
|
||||||
|
*/
|
||||||
|
CFloatingDockContainer* makeAreaFloating(const QPoint& Pos);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QScrollArea;
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
*/
|
||||||
|
CDockAreaTabBar(CDockAreaWidget* parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockAreaTabBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the given dock widget tab at the given position.
|
||||||
|
* Inserting a new tab at an index less than or equal to the current index
|
||||||
|
* will increment the current index, but keep the current tab.
|
||||||
|
*/
|
||||||
|
void insertTab(int Index, CDockWidgetTab* Tab);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given DockWidgetTab from the tabbar
|
||||||
|
*/
|
||||||
|
void removeTab(CDockWidgetTab* Tab);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of tabs in this tabbar
|
||||||
|
*/
|
||||||
|
int count() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current index or -1 if no tab is selected
|
||||||
|
*/
|
||||||
|
int currentIndex() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current tab or a nullptr if no tab is selected.
|
||||||
|
*/
|
||||||
|
CDockWidgetTab* currentTab() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tab with the given index
|
||||||
|
*/
|
||||||
|
CDockWidgetTab* tab(int Index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the tab widget events
|
||||||
|
*/
|
||||||
|
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if the tab is open, that means if it is
|
||||||
|
* visible to the user. If the function returns false, the tab is
|
||||||
|
* closed
|
||||||
|
*/
|
||||||
|
bool isTabOpen(int Index) const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* This property sets the index of the tab bar's visible tab
|
||||||
|
*/
|
||||||
|
void setCurrentIndex(int Index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will close the tab given in Index param.
|
||||||
|
* Closing a tab means, the tab will be hidden, it will not be removed
|
||||||
|
*/
|
||||||
|
void closeTab(int Index);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
void currentChanged(int Index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when user clicks on a tab
|
||||||
|
*/
|
||||||
|
void tabBarClicked(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the close button on a tab is clicked.
|
||||||
|
* The index is the index that should be closed.
|
||||||
|
*/
|
||||||
|
void tabCloseRequested(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab has been closed
|
||||||
|
*/
|
||||||
|
void tabClosed(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab has been opened.
|
||||||
|
* A tab is opened if it has been made visible
|
||||||
|
*/
|
||||||
|
void tabOpened(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the tab has moved the tab at index position
|
||||||
|
* from to index position to.
|
||||||
|
*/
|
||||||
|
void tabMoved(int from, int to);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, just before the tab with the given index is
|
||||||
|
* removed
|
||||||
|
*/
|
||||||
|
void removingTab(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab has been inserted
|
||||||
|
*/
|
||||||
|
void tabInserted(int index);
|
||||||
|
}; // class CDockAreaTabBar
|
||||||
|
} // namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockAreaTabBarH
|
||||||
|
|
||||||
316
src/DockAreaTitleBar.cpp
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** 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 DockAreaTitleBar.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 12.10.2018
|
||||||
|
/// \brief Implementation of CDockAreaTitleBar class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include "DockAreaTitleBar.h"
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
#include "DockAreaTabBar.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
using tTileBarButton = QToolButton;
|
||||||
|
/**
|
||||||
|
* Private data class of CDockAreaTitleBar class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockAreaTitleBarPrivate
|
||||||
|
{
|
||||||
|
CDockAreaTitleBar* _this;
|
||||||
|
tTileBarButton* TabsMenuButton;
|
||||||
|
tTileBarButton* UndockButton;
|
||||||
|
tTileBarButton* CloseButton;
|
||||||
|
QBoxLayout* TopLayout;
|
||||||
|
CDockAreaWidget* DockArea;
|
||||||
|
CDockAreaTabBar* TabBar;
|
||||||
|
bool MenuOutdated = true;
|
||||||
|
QMenu* TabsMenu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockAreaTitleBarPrivate(CDockAreaTitleBar* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the title bar close and menu buttons
|
||||||
|
*/
|
||||||
|
void createButtons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the internal TabBar
|
||||||
|
*/
|
||||||
|
void createTabBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function for DockManager access
|
||||||
|
*/
|
||||||
|
CDockManager* dockManager() const
|
||||||
|
{
|
||||||
|
return DockArea->dockManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given config flag is set
|
||||||
|
*/
|
||||||
|
bool testConfigFlag(CDockManager::eConfigFlag Flag) const
|
||||||
|
{
|
||||||
|
return DockArea->dockManager()->configFlags().testFlag(Flag);
|
||||||
|
}
|
||||||
|
};// struct DockAreaTitleBarPrivate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaTitleBarPrivate::createButtons()
|
||||||
|
{
|
||||||
|
TabsMenuButton = new tTileBarButton();
|
||||||
|
TabsMenuButton->setObjectName("tabsMenuButton");
|
||||||
|
TabsMenuButton->setAutoRaise(true);
|
||||||
|
TabsMenuButton->setPopupMode(QToolButton::InstantPopup);
|
||||||
|
TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton));
|
||||||
|
|
||||||
|
QMenu* TabsMenu = new QMenu(TabsMenuButton);
|
||||||
|
_this->connect(TabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow()));
|
||||||
|
TabsMenuButton->setMenu(TabsMenu);
|
||||||
|
TabsMenuButton->setToolTip(QObject::tr("List all tabs"));
|
||||||
|
TabsMenuButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
TopLayout->addWidget(TabsMenuButton, 0);
|
||||||
|
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
|
||||||
|
SLOT(onTabsMenuActionTriggered(QAction*)));
|
||||||
|
|
||||||
|
// Undock button
|
||||||
|
UndockButton = new tTileBarButton();
|
||||||
|
UndockButton->setObjectName("undockButton");
|
||||||
|
UndockButton->setAutoRaise(true);
|
||||||
|
UndockButton->setToolTip(QObject::tr("Detach Group"));
|
||||||
|
UndockButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarNormalButton));
|
||||||
|
UndockButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
TopLayout->addWidget(UndockButton, 0);
|
||||||
|
_this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked()));
|
||||||
|
|
||||||
|
CloseButton = new tTileBarButton();
|
||||||
|
CloseButton->setObjectName("closeButton");
|
||||||
|
CloseButton->setAutoRaise(true);
|
||||||
|
|
||||||
|
// The standard icons do not look good on high DPI screens
|
||||||
|
QIcon CloseIcon = _this->style()->standardIcon(QStyle::SP_TitleBarCloseButton);
|
||||||
|
QPixmap normalPixmap = _this->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, CloseButton);
|
||||||
|
QPixmap disabledPixmap = internal::createTransparentPixmap(normalPixmap, 0.25);
|
||||||
|
CloseIcon.addPixmap(disabledPixmap, QIcon::Disabled);
|
||||||
|
|
||||||
|
CloseButton->setIcon(CloseIcon);
|
||||||
|
if (testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||||
|
{
|
||||||
|
CloseButton->setToolTip(QObject::tr("Close Active Tab"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseButton->setToolTip(QObject::tr("Close Group"));
|
||||||
|
}
|
||||||
|
CloseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
TopLayout->addWidget(CloseButton, 0);
|
||||||
|
_this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockAreaTitleBarPrivate::createTabBar()
|
||||||
|
{
|
||||||
|
TabBar = new CDockAreaTabBar(DockArea);
|
||||||
|
TopLayout->addWidget(TabBar);
|
||||||
|
_this->connect(TabBar, SIGNAL(tabClosed(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabOpened(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabInserted(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(removingTab(int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabMoved(int, int)), SLOT(markTabsMenuOutdated()));
|
||||||
|
_this->connect(TabBar, SIGNAL(currentChanged(int)), SLOT(onCurrentTabChanged(int)));
|
||||||
|
_this->connect(TabBar, SIGNAL(tabBarClicked(int)), SIGNAL(tabBarClicked(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
d(new DockAreaTitleBarPrivate(this))
|
||||||
|
{
|
||||||
|
d->DockArea = parent;
|
||||||
|
|
||||||
|
setObjectName("dockAreaTitleBar");
|
||||||
|
d->TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
|
d->TopLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
d->TopLayout->setSpacing(0);
|
||||||
|
setLayout(d->TopLayout);
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
|
||||||
|
d->createTabBar();
|
||||||
|
d->createButtons();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTitleBar::~CDockAreaTitleBar()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaTabBar* CDockAreaTitleBar::tabBar() const
|
||||||
|
{
|
||||||
|
return d->TabBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::markTabsMenuOutdated()
|
||||||
|
{
|
||||||
|
d->MenuOutdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onTabsMenuAboutToShow()
|
||||||
|
{
|
||||||
|
if (!d->MenuOutdated)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu* menu = d->TabsMenuButton->menu();
|
||||||
|
menu->clear();
|
||||||
|
for (int i = 0; i < d->TabBar->count(); ++i)
|
||||||
|
{
|
||||||
|
if (!d->TabBar->isTabOpen(i))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto Tab = d->TabBar->tab(i);
|
||||||
|
QAction* Action = menu->addAction(Tab->icon(), Tab->text());
|
||||||
|
Action->setData(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->MenuOutdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onCloseButtonClicked()
|
||||||
|
{
|
||||||
|
qDebug() << "CDockAreaTitleBar::onCloseButtonClicked";
|
||||||
|
if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||||
|
{
|
||||||
|
d->TabBar->closeTab(d->TabBar->currentIndex());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->DockArea->closeArea();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onUndockButtonClicked()
|
||||||
|
{
|
||||||
|
d->TabBar->makeAreaFloating(mapFromGlobal(QCursor::pos()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onTabsMenuActionTriggered(QAction* Action)
|
||||||
|
{
|
||||||
|
int Index = Action->data().toInt();
|
||||||
|
d->TabBar->setCurrentIndex(Index);
|
||||||
|
emit tabBarClicked(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::onCurrentTabChanged(int Index)
|
||||||
|
{
|
||||||
|
if (Index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab))
|
||||||
|
{
|
||||||
|
CDockWidget* DockWidget = d->TabBar->tab(Index)->dockWidget();
|
||||||
|
d->CloseButton->setEnabled(DockWidget->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const
|
||||||
|
{
|
||||||
|
switch (which)
|
||||||
|
{
|
||||||
|
case TitleBarButtonTabsMenu: return d->TabsMenuButton;
|
||||||
|
case TitleBarButtonUndock: return d->UndockButton;
|
||||||
|
case TitleBarButtonClose: return d->CloseButton;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaTitleBar::setVisible(bool Visible)
|
||||||
|
{
|
||||||
|
Super::setVisible(Visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockAreaTitleBar.cpp
|
||||||
100
src/DockAreaTitleBar.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#ifndef DockAreaTitleBarH
|
||||||
|
#define DockAreaTitleBarH
|
||||||
|
/*******************************************************************************
|
||||||
|
** 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 DockAreaTitleBar.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 12.10.2018
|
||||||
|
/// \brief Declaration of CDockAreaTitleBar class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class QAbstractButton;
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
class CDockAreaTabBar;
|
||||||
|
class CDockAreaWidget;
|
||||||
|
struct DockAreaTitleBarPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title bar of a dock area
|
||||||
|
*/
|
||||||
|
class CDockAreaTitleBar : public QFrame
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
DockAreaTitleBarPrivate* d; ///< private data (pimpl)
|
||||||
|
friend class DockAreaTitleBarPrivate;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void markTabsMenuOutdated();
|
||||||
|
void onTabsMenuAboutToShow();
|
||||||
|
void onCloseButtonClicked();
|
||||||
|
void onUndockButtonClicked();
|
||||||
|
void onTabsMenuActionTriggered(QAction* Action);
|
||||||
|
void onCurrentTabChanged(int Index);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
/**
|
||||||
|
* Default Constructor
|
||||||
|
*/
|
||||||
|
CDockAreaTitleBar(CDockAreaWidget* parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockAreaTitleBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pointer to the tabBar()
|
||||||
|
*/
|
||||||
|
CDockAreaTabBar* tabBar() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the button corresponding to the given title bar button identifier
|
||||||
|
*/
|
||||||
|
QAbstractButton* button(TitleBarButton which) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is here for debug reasons
|
||||||
|
*/
|
||||||
|
virtual void setVisible(bool Visible) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a tab in the tab bar is clicked by the user
|
||||||
|
* or if the user clicks on a tab item in the title bar tab menu.
|
||||||
|
*/
|
||||||
|
void tabBarClicked(int index);
|
||||||
|
}; // class name
|
||||||
|
}
|
||||||
|
// namespace ads
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#endif // DockAreaTitleBarH
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// INCLUDES
|
// INCLUDES
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
#include <DockWidgetTab.h>
|
||||||
#include "DockAreaWidget.h"
|
#include "DockAreaWidget.h"
|
||||||
|
|
||||||
#include <QStackedLayout>
|
#include <QStackedLayout>
|
||||||
@@ -39,155 +40,198 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
|
||||||
#include "DockContainerWidget.h"
|
#include "DockContainerWidget.h"
|
||||||
#include "DockWidget.h"
|
#include "DockWidget.h"
|
||||||
#include "DockWidgetTitleBar.h"
|
|
||||||
#include "FloatingDockContainer.h"
|
#include "FloatingDockContainer.h"
|
||||||
#include "DockManager.h"
|
#include "DockManager.h"
|
||||||
#include "DockOverlay.h"
|
#include "DockOverlay.h"
|
||||||
|
#include "DockAreaTabBar.h"
|
||||||
|
#include "DockSplitter.h"
|
||||||
|
#include "DockAreaTitleBar.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
static const char* const INDEX_PROPERTY = "index";
|
static const char* const INDEX_PROPERTY = "index";
|
||||||
static const char* const ACTION_PROPERTY = "action";
|
static const char* const ACTION_PROPERTY = "action";
|
||||||
|
static const char* const DOCKWIDGET_PROPERTY = "dockwidget";
|
||||||
static const int APPEND = -1;
|
static const int APPEND = -1;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom scroll bar implementation for dock area tab bar
|
* New dock area layout mimics stack layout but only inserts the current
|
||||||
* This scroll area enables floating of a whole dock area including all
|
* widget into the internal QLayout object
|
||||||
* dock widgets
|
|
||||||
*/
|
*/
|
||||||
class CTabsScrollArea : public QScrollArea
|
class CDockAreaLayout
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
QPoint m_DragStartMousePos;
|
QBoxLayout* m_ParentLayout;
|
||||||
CDockAreaWidget* m_DockArea;
|
QList<QWidget*> m_Widgets;
|
||||||
CFloatingDockContainer* m_FloatingWidget = nullptr;
|
int m_CurrentIndex = -1;
|
||||||
|
QWidget* m_CurrentWidget = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CTabsScrollArea(CDockAreaWidget* parent)
|
/**
|
||||||
: QScrollArea(parent),
|
* Creates an instance with the given parent layout
|
||||||
m_DockArea(parent)
|
*/
|
||||||
|
CDockAreaLayout(QBoxLayout* ParentLayout)
|
||||||
|
: m_ParentLayout(ParentLayout)
|
||||||
{
|
{
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
|
|
||||||
setFrameStyle(QFrame::NoFrame);
|
|
||||||
setWidgetResizable(true);
|
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
virtual void wheelEvent(QWheelEvent* Event) override
|
* Returns the number of widgets in this layout
|
||||||
|
*/
|
||||||
|
int count() const
|
||||||
{
|
{
|
||||||
Event->accept();
|
return m_Widgets.count();
|
||||||
const int direction = Event->angleDelta().y();
|
}
|
||||||
if (direction < 0)
|
|
||||||
|
/**
|
||||||
|
* Inserts the widget at the given index position into the internal widget
|
||||||
|
* list
|
||||||
|
*/
|
||||||
|
void insertWidget(int index, QWidget* Widget)
|
||||||
|
{
|
||||||
|
Widget->setParent(0);
|
||||||
|
if (index < 0)
|
||||||
{
|
{
|
||||||
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
|
index = m_Widgets.count();
|
||||||
|
}
|
||||||
|
m_Widgets.insert(index, Widget);
|
||||||
|
if (m_CurrentIndex < 0)
|
||||||
|
{
|
||||||
|
setCurrentIndex(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
|
if (index <= m_CurrentIndex )
|
||||||
|
{
|
||||||
|
++m_CurrentIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores mouse position to detect dragging
|
* Removes the given widget from the lyout
|
||||||
*/
|
*/
|
||||||
virtual void mousePressEvent(QMouseEvent* ev) override
|
void removeWidget(QWidget* Widget)
|
||||||
{
|
{
|
||||||
if (ev->button() == Qt::LeftButton)
|
if (currentWidget() == Widget)
|
||||||
{
|
{
|
||||||
ev->accept();
|
auto LayoutItem = m_ParentLayout->takeAt(1);
|
||||||
m_DragStartMousePos = ev->pos();
|
if (LayoutItem)
|
||||||
return;
|
{
|
||||||
|
LayoutItem->widget()->setParent(0);
|
||||||
|
}
|
||||||
|
m_CurrentWidget = nullptr;
|
||||||
|
m_CurrentIndex = -1;
|
||||||
}
|
}
|
||||||
QScrollArea::mousePressEvent(ev);
|
m_Widgets.removeOne(Widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores mouse position to detect dragging
|
* Returns the current selected widget
|
||||||
*/
|
*/
|
||||||
virtual void mouseReleaseEvent(QMouseEvent* ev) override
|
QWidget* currentWidget() const
|
||||||
{
|
{
|
||||||
if (ev->button() == Qt::LeftButton)
|
return m_CurrentWidget;
|
||||||
{
|
|
||||||
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,
|
* Activates the widget with the give index.
|
||||||
* if it is not the last dock area in a floating widget
|
|
||||||
*/
|
*/
|
||||||
virtual void mouseMoveEvent(QMouseEvent* ev) override
|
void setCurrentIndex(int index)
|
||||||
{
|
{
|
||||||
QScrollArea::mouseMoveEvent(ev);
|
QWidget *prev = currentWidget();
|
||||||
if (ev->buttons() != Qt::LeftButton)
|
QWidget *next = widget(index);
|
||||||
|
if (!next || (next == prev && !m_CurrentWidget))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_FloatingWidget)
|
bool reenableUpdates = false;
|
||||||
|
QWidget *parent = m_ParentLayout->parentWidget();
|
||||||
|
|
||||||
|
if (parent && parent->updatesEnabled())
|
||||||
{
|
{
|
||||||
m_FloatingWidget->moveFloating();
|
reenableUpdates = true;
|
||||||
return;
|
parent->setUpdatesEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is the last dock area in a dock container it does not make
|
auto LayoutItem = m_ParentLayout->takeAt(1);
|
||||||
// sense to move it to a new floating widget and leave this one
|
if (LayoutItem)
|
||||||
// empty
|
|
||||||
if (m_DockArea->dockContainer()->isFloating()
|
|
||||||
&& m_DockArea->dockContainer()->visibleDockAreaCount() == 1)
|
|
||||||
{
|
{
|
||||||
return;
|
LayoutItem->widget()->setParent(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->geometry().contains(ev->pos()))
|
m_ParentLayout->addWidget(next);
|
||||||
|
if (prev)
|
||||||
{
|
{
|
||||||
qDebug() << "CTabsScrollArea::startFloating";
|
prev->hide();
|
||||||
startFloating(m_DragStartMousePos);
|
|
||||||
auto Overlay = m_DockArea->dockManager()->containerOverlay();
|
|
||||||
Overlay->setAllowedAreas(OuterDockAreas);
|
|
||||||
}
|
}
|
||||||
|
m_CurrentIndex = index;
|
||||||
|
m_CurrentWidget = next;
|
||||||
|
|
||||||
return;
|
|
||||||
|
if (reenableUpdates)
|
||||||
|
{
|
||||||
|
parent->setUpdatesEnabled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Double clicking the title bar also starts floating of the complete area
|
* Returns the index of the current active widget
|
||||||
*/
|
*/
|
||||||
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
|
int currentIndex() const
|
||||||
{
|
{
|
||||||
// If this is the last dock area in a dock container it does not make
|
return m_CurrentIndex;
|
||||||
// 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
|
* Returns true if there are no widgets in the layout
|
||||||
*/
|
*/
|
||||||
void startFloating(const QPoint& Pos)
|
bool isEmpty() const
|
||||||
{
|
{
|
||||||
QSize Size = m_DockArea->size();
|
return m_Widgets.empty();
|
||||||
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(m_DockArea);
|
|
||||||
FloatingWidget->startFloating(Pos, Size);
|
|
||||||
m_FloatingWidget = FloatingWidget;
|
|
||||||
}
|
}
|
||||||
}; // class CTabsScrollArea
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the given widget
|
||||||
|
*/
|
||||||
|
int indexOf(QWidget* w) const
|
||||||
|
{
|
||||||
|
return m_Widgets.indexOf(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the widget for the given index
|
||||||
|
*/
|
||||||
|
QWidget* widget(int index) const
|
||||||
|
{
|
||||||
|
return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the geometry of the current active widget
|
||||||
|
*/
|
||||||
|
QRect geometry() const
|
||||||
|
{
|
||||||
|
return m_Widgets.empty() ? QRect() : currentWidget()->geometry();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using DockAreaLayout = CDockAreaLayout;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,16 +241,10 @@ struct DockAreaWidgetPrivate
|
|||||||
{
|
{
|
||||||
CDockAreaWidget* _this;
|
CDockAreaWidget* _this;
|
||||||
QBoxLayout* Layout;
|
QBoxLayout* Layout;
|
||||||
QFrame* TitleBar;
|
DockAreaLayout* ContentsLayout;
|
||||||
QBoxLayout* TopLayout;
|
CDockAreaTitleBar* TitleBar;
|
||||||
QStackedLayout* ContentsLayout;
|
|
||||||
QScrollArea* TabsScrollArea;
|
|
||||||
QWidget* TabsContainerWidget;
|
|
||||||
QBoxLayout* TabsLayout;
|
|
||||||
QPushButton* TabsMenuButton;
|
|
||||||
QPushButton* CloseButton;
|
|
||||||
int TabsLayoutInitCount;
|
|
||||||
CDockManager* DockManager = nullptr;
|
CDockManager* DockManager = nullptr;
|
||||||
|
bool UpdateCloseButton = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data constructor
|
* Private data constructor
|
||||||
@@ -216,7 +254,7 @@ struct DockAreaWidgetPrivate
|
|||||||
/**
|
/**
|
||||||
* Creates the layout for top area with tabs and close button
|
* Creates the layout for top area with tabs and close button
|
||||||
*/
|
*/
|
||||||
void createTabBar();
|
void createTitleBar();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the dock widget with the given index
|
* Returns the dock widget with the given index
|
||||||
@@ -229,18 +267,11 @@ struct DockAreaWidgetPrivate
|
|||||||
/**
|
/**
|
||||||
* Convenience function to ease title widget access by index
|
* Convenience function to ease title widget access by index
|
||||||
*/
|
*/
|
||||||
CDockWidgetTitleBar* titleWidgetAt(int index)
|
CDockWidgetTab* tabWidgetAt(int index)
|
||||||
{
|
{
|
||||||
return dockWidgetAt(index)->titleBar();
|
return dockWidgetAt(index)->tabWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a tabs menu entry for the given dock widget
|
|
||||||
* If menu is 0, a menu entry is added to the menu of the TabsMenuButton
|
|
||||||
* member. If menu is a valid menu pointer, the entry will be added to
|
|
||||||
* the given menu
|
|
||||||
*/
|
|
||||||
void addTabsMenuEntry(CDockWidget* DockWidget, int Index = -1, QMenu* menu = 0);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tab action of the given dock widget
|
* Returns the tab action of the given dock widget
|
||||||
@@ -259,16 +290,17 @@ struct DockAreaWidgetPrivate
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the tabs menu if dock widget order changed or if dock widget has
|
* Convenience function for tabbar access
|
||||||
* been removed
|
|
||||||
*/
|
*/
|
||||||
void updateTabsMenu();
|
CDockAreaTabBar* tabBar() const
|
||||||
|
{
|
||||||
|
return TitleBar->tabBar();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the tab bar visibility depending on the number of dock widgets
|
* Udpates the enable state of the close button
|
||||||
* in this area
|
|
||||||
*/
|
*/
|
||||||
void updateTabBar();
|
void updateCloseButtonState();
|
||||||
};
|
};
|
||||||
// struct DockAreaWidgetPrivate
|
// struct DockAreaWidgetPrivate
|
||||||
|
|
||||||
@@ -282,101 +314,31 @@ DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) :
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void DockAreaWidgetPrivate::createTabBar()
|
void DockAreaWidgetPrivate::createTitleBar()
|
||||||
{
|
{
|
||||||
TitleBar = new QFrame(_this);
|
TitleBar = new CDockAreaTitleBar(_this);
|
||||||
TitleBar->setObjectName("dockAreaTitleBar");
|
|
||||||
TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
|
||||||
TopLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
TopLayout->setSpacing(0);
|
|
||||||
TitleBar->setLayout(TopLayout);
|
|
||||||
Layout->addWidget(TitleBar);
|
Layout->addWidget(TitleBar);
|
||||||
|
_this->connect(tabBar(), SIGNAL(tabCloseRequested(int)),
|
||||||
TabsScrollArea = new CTabsScrollArea(_this);
|
SLOT(onTabCloseRequested(int)));
|
||||||
TopLayout->addWidget(TabsScrollArea, 1);
|
_this->connect(TitleBar, SIGNAL(tabBarClicked(int)),
|
||||||
|
SLOT(setCurrentIndex(int)));
|
||||||
TabsContainerWidget = new QWidget();
|
_this->connect(tabBar(), SIGNAL(tabMoved(int, int)),
|
||||||
TabsContainerWidget->setObjectName("tabsContainerWidget");
|
SLOT(reorderDockWidget(int, int)));
|
||||||
TabsScrollArea->setWidget(TabsContainerWidget);
|
|
||||||
|
|
||||||
TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
|
||||||
TabsLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
TabsLayout->setSpacing(0);
|
|
||||||
TabsLayout->addStretch(1);
|
|
||||||
TabsContainerWidget->setLayout(TabsLayout);
|
|
||||||
|
|
||||||
TabsMenuButton = new QPushButton();
|
|
||||||
TabsMenuButton->setObjectName("tabsMenuButton");
|
|
||||||
TabsMenuButton->setFlat(true);
|
|
||||||
TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton));
|
|
||||||
TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width());
|
|
||||||
TabsMenuButton->setMenu(new QMenu(TabsMenuButton));
|
|
||||||
TopLayout->addWidget(TabsMenuButton, 0);
|
|
||||||
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
|
|
||||||
SLOT(onTabsMenuActionTriggered(QAction*)));
|
|
||||||
|
|
||||||
CloseButton = new QPushButton();
|
|
||||||
CloseButton->setObjectName("closeButton");
|
|
||||||
CloseButton->setFlat(true);
|
|
||||||
CloseButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
|
|
||||||
CloseButton->setToolTip(_this->tr("Close"));
|
|
||||||
CloseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
||||||
TopLayout->addWidget(CloseButton, 0);
|
|
||||||
_this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked()));
|
|
||||||
|
|
||||||
TabsLayoutInitCount = TabsLayout->count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void DockAreaWidgetPrivate::updateTabBar()
|
void DockAreaWidgetPrivate::updateCloseButtonState()
|
||||||
{
|
{
|
||||||
CDockContainerWidget* Container = _this->dockContainer();
|
if (_this->isHidden())
|
||||||
if (!Container)
|
|
||||||
{
|
{
|
||||||
|
UpdateCloseButton = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Container->isFloating() && (Container->dockAreaCount() == 1) && (_this->count() == 1))
|
TitleBar->button(TitleBarButtonClose)->setEnabled(
|
||||||
{
|
_this->features().testFlag(CDockWidget::DockWidgetClosable));
|
||||||
TitleBar->setVisible(false);
|
UpdateCloseButton = false;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TitleBar->setVisible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget,
|
|
||||||
int Index, QMenu* menu)
|
|
||||||
{
|
|
||||||
menu = menu ? menu : TabsMenuButton->menu();
|
|
||||||
QAction* Action;
|
|
||||||
if (Index >= 0 && Index < menu->actions().count())
|
|
||||||
{
|
|
||||||
Action = new QAction(DockWidget->windowTitle());
|
|
||||||
menu->insertAction(menu->actions().at(Index), Action);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Action = menu->addAction(DockWidget->windowTitle());
|
|
||||||
}
|
|
||||||
QVariant vAction = QVariant::fromValue(Action);
|
|
||||||
DockWidget->setProperty(ACTION_PROPERTY, vAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void DockAreaWidgetPrivate::updateTabsMenu()
|
|
||||||
{
|
|
||||||
QMenu* menu = TabsMenuButton->menu();
|
|
||||||
menu->clear();
|
|
||||||
for (int i = 0; i < ContentsLayout->count(); ++i)
|
|
||||||
{
|
|
||||||
addTabsMenuEntry(dockWidgetAt(i), APPEND, menu);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -391,18 +353,15 @@ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget
|
|||||||
d->Layout->setSpacing(0);
|
d->Layout->setSpacing(0);
|
||||||
setLayout(d->Layout);
|
setLayout(d->Layout);
|
||||||
|
|
||||||
d->createTabBar();
|
d->createTitleBar();
|
||||||
|
d->ContentsLayout = new DockAreaLayout(d->Layout);
|
||||||
d->ContentsLayout = new QStackedLayout();
|
|
||||||
d->ContentsLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
d->ContentsLayout->setSpacing(0);
|
|
||||||
d->Layout->addLayout(d->ContentsLayout, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockAreaWidget::~CDockAreaWidget()
|
CDockAreaWidget::~CDockAreaWidget()
|
||||||
{
|
{
|
||||||
qDebug() << "~CDockAreaWidget()";
|
qDebug() << "~CDockAreaWidget()";
|
||||||
|
delete d->ContentsLayout;
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,18 +376,7 @@ CDockManager* CDockAreaWidget::dockManager() const
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
CDockContainerWidget* CDockAreaWidget::dockContainer() const
|
CDockContainerWidget* CDockAreaWidget::dockContainer() const
|
||||||
{
|
{
|
||||||
QWidget* Parent = parentWidget();
|
return internal::findParent<CDockContainerWidget*>(this);
|
||||||
while (Parent)
|
|
||||||
{
|
|
||||||
CDockContainerWidget* Container = dynamic_cast<CDockContainerWidget*>(Parent);
|
|
||||||
if (Container)
|
|
||||||
{
|
|
||||||
return Container;
|
|
||||||
}
|
|
||||||
Parent = Parent->parentWidget();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -444,18 +392,21 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
|
|||||||
bool Activate)
|
bool Activate)
|
||||||
{
|
{
|
||||||
d->ContentsLayout->insertWidget(index, DockWidget);
|
d->ContentsLayout->insertWidget(index, DockWidget);
|
||||||
DockWidget->titleBar()->setDockAreaWidget(this);
|
DockWidget->tabWidget()->setDockAreaWidget(this);
|
||||||
auto TitleBar = DockWidget->titleBar();
|
auto TabWidget = DockWidget->tabWidget();
|
||||||
d->TabsLayout->insertWidget(index, TitleBar);
|
// Inserting the tab will change the current index which in turn will
|
||||||
TitleBar->show();
|
// make the tab widget visible in the slot
|
||||||
connect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked()));
|
d->tabBar()->blockSignals(true);
|
||||||
|
d->tabBar()->insertTab(index, TabWidget);
|
||||||
|
d->tabBar()->blockSignals(false);
|
||||||
|
TabWidget->setVisible(!DockWidget->isClosed());
|
||||||
DockWidget->setProperty(INDEX_PROPERTY, index);
|
DockWidget->setProperty(INDEX_PROPERTY, index);
|
||||||
if (Activate)
|
if (Activate)
|
||||||
{
|
{
|
||||||
setCurrentIndex(index);
|
setCurrentIndex(index);
|
||||||
}
|
}
|
||||||
d->addTabsMenuEntry(DockWidget, index);
|
|
||||||
DockWidget->setDockArea(this);
|
DockWidget->setDockArea(this);
|
||||||
|
d->updateCloseButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -463,64 +414,118 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget,
|
|||||||
void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
|
void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
|
||||||
{
|
{
|
||||||
qDebug() << "CDockAreaWidget::removeDockWidget";
|
qDebug() << "CDockAreaWidget::removeDockWidget";
|
||||||
d->ContentsLayout->removeWidget(DockWidget);
|
auto NextOpenDockWidget = nextOpenDockWidget(DockWidget);
|
||||||
auto TitleBar = DockWidget->titleBar();
|
|
||||||
TitleBar->hide();
|
|
||||||
d->TabsLayout->removeWidget(TitleBar);
|
|
||||||
disconnect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked()));
|
|
||||||
setCurrentIndex(d->ContentsLayout->currentIndex());
|
|
||||||
d->updateTabsMenu();
|
|
||||||
|
|
||||||
CDockContainerWidget* DockContainer = dockContainer();
|
d->ContentsLayout->removeWidget(DockWidget);
|
||||||
if (d->ContentsLayout->isEmpty())
|
auto TabWidget = DockWidget->tabWidget();
|
||||||
|
TabWidget->hide();
|
||||||
|
d->tabBar()->removeTab(TabWidget);
|
||||||
|
if (NextOpenDockWidget)
|
||||||
|
{
|
||||||
|
setCurrentDockWidget(NextOpenDockWidget);
|
||||||
|
}
|
||||||
|
else if (d->ContentsLayout->isEmpty())
|
||||||
{
|
{
|
||||||
qDebug() << "Dock Area empty";
|
qDebug() << "Dock Area empty";
|
||||||
dockContainer()->removeDockArea(this);
|
dockContainer()->removeDockArea(this);
|
||||||
this->deleteLater();;
|
this->deleteLater();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if contents layout is not empty but there are no more open dock
|
||||||
|
// widgets, then we need to hide the dock area because it does not
|
||||||
|
// contain any visible content
|
||||||
|
hideAreaWithNoVisibleContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
d->updateTabBar();
|
d->updateCloseButtonState();
|
||||||
DockWidget->setDockArea(nullptr);
|
updateTitleBarVisibility();
|
||||||
|
auto TopLevelDockWidget = dockContainer()->topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (ADS_DEBUG_LEVEL > 0)
|
||||||
|
CDockContainerWidget* DockContainer = dockContainer();
|
||||||
DockContainer->dumpLayout();
|
DockContainer->dumpLayout();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockAreaWidget::onDockWidgetTitleClicked()
|
void CDockAreaWidget::hideAreaWithNoVisibleContent()
|
||||||
{
|
{
|
||||||
CDockWidgetTitleBar* TitleWidget = qobject_cast<CDockWidgetTitleBar*>(sender());
|
this->toggleView(false);
|
||||||
if (!TitleWidget)
|
|
||||||
|
// Hide empty parent splitters
|
||||||
|
auto Splitter = internal::findParent<CDockSplitter*>(this);
|
||||||
|
internal::hideEmptyParentSplitters(Splitter);
|
||||||
|
|
||||||
|
//Hide empty floating widget
|
||||||
|
CDockContainerWidget* Container = this->dockContainer();
|
||||||
|
if (!Container->isFloating())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = d->TabsLayout->indexOf(TitleWidget);
|
updateTitleBarVisibility();
|
||||||
setCurrentIndex(index);
|
auto TopLevelWidget = Container->topLevelDockWidget();
|
||||||
|
auto FloatingWidget = Container->floatingWidget();
|
||||||
|
if (TopLevelWidget)
|
||||||
|
{
|
||||||
|
FloatingWidget->updateWindowTitle();
|
||||||
|
CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
|
||||||
|
}
|
||||||
|
else if (Container->openedDockAreas().isEmpty())
|
||||||
|
{
|
||||||
|
FloatingWidget->hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockAreaWidget::onCloseButtonClicked()
|
void CDockAreaWidget::onTabCloseRequested(int Index)
|
||||||
{
|
{
|
||||||
currentDockWidget()->toggleView(false);
|
qDebug() << "CDockAreaWidget::onTabCloseRequested " << Index;
|
||||||
|
dockWidget(Index)->toggleView(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockWidget* CDockAreaWidget::currentDockWidget() const
|
CDockWidget* CDockAreaWidget::currentDockWidget() const
|
||||||
{
|
{
|
||||||
return dockWidget(currentIndex());
|
int CurrentIndex = currentIndex();
|
||||||
|
if (CurrentIndex < 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dockWidget(CurrentIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
|
void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
|
||||||
{
|
{
|
||||||
int Index = tabIndex(DockWidget);
|
if (dockManager()->isRestoringState())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
internalSetCurrentDockWidget(DockWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::internalSetCurrentDockWidget(CDockWidget* DockWidget)
|
||||||
|
{
|
||||||
|
int Index = index(DockWidget);
|
||||||
if (Index < 0)
|
if (Index < 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentIndex(Index);
|
setCurrentIndex(Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,41 +533,15 @@ void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockAreaWidget::setCurrentIndex(int index)
|
void CDockAreaWidget::setCurrentIndex(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index > (d->TabsLayout->count() - 1))
|
auto TabBar = d->tabBar();
|
||||||
|
if (index < 0 || index > (TabBar->count() - 1))
|
||||||
{
|
{
|
||||||
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set active TAB and update all other tabs to be inactive
|
|
||||||
for (int i = 0; i < d->TabsLayout->count(); ++i)
|
|
||||||
{
|
|
||||||
QLayoutItem* item = d->TabsLayout->itemAt(i);
|
|
||||||
if (!item->widget())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto TitleWidget = dynamic_cast<CDockWidgetTitleBar*>(item->widget());
|
|
||||||
if (!TitleWidget)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == index)
|
|
||||||
{
|
|
||||||
TitleWidget->show();
|
|
||||||
TitleWidget->setActiveTab(true);
|
|
||||||
d->TabsScrollArea->ensureWidgetVisible(TitleWidget);
|
|
||||||
auto Features = TitleWidget->dockWidget()->features();
|
|
||||||
d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TitleWidget->setActiveTab(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
emit currentChanging(index);
|
||||||
|
TabBar->setCurrentIndex(index);
|
||||||
d->ContentsLayout->setCurrentIndex(index);
|
d->ContentsLayout->setCurrentIndex(index);
|
||||||
d->ContentsLayout->currentWidget()->show();
|
d->ContentsLayout->currentWidget()->show();
|
||||||
emit currentChanged(index);
|
emit currentChanged(index);
|
||||||
@@ -577,9 +556,9 @@ int CDockAreaWidget::currentIndex() const
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
QRect CDockAreaWidget::titleAreaGeometry() const
|
QRect CDockAreaWidget::titleBarGeometry() const
|
||||||
{
|
{
|
||||||
return d->TopLayout->geometry();
|
return d->TitleBar->geometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@@ -590,7 +569,7 @@ QRect CDockAreaWidget::contentAreaGeometry() const
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
int CDockAreaWidget::tabIndex(CDockWidget* DockWidget)
|
int CDockAreaWidget::index(CDockWidget* DockWidget)
|
||||||
{
|
{
|
||||||
return d->ContentsLayout->indexOf(DockWidget);
|
return d->ContentsLayout->indexOf(DockWidget);
|
||||||
}
|
}
|
||||||
@@ -608,6 +587,21 @@ QList<CDockWidget*> CDockAreaWidget::dockWidgets() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
int CDockAreaWidget::openDockWidgetsCount() const
|
||||||
|
{
|
||||||
|
int Count = 0;
|
||||||
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
|
{
|
||||||
|
if (!dockWidget(i)->isClosed())
|
||||||
|
{
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
|
QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
|
||||||
{
|
{
|
||||||
@@ -625,22 +619,22 @@ QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
|
int CDockAreaWidget::indexOfFirstOpenDockWidget() const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
{
|
{
|
||||||
auto TitleWidget = d->titleWidgetAt(i);
|
if (!dockWidget(i)->isClosed())
|
||||||
if (TitleWidget->geometry().contains(p) && (!exclude || TitleWidget != exclude))
|
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
int CDockAreaWidget::count() const
|
int CDockAreaWidget::dockWidgetsCount() const
|
||||||
{
|
{
|
||||||
return d->ContentsLayout->count();
|
return d->ContentsLayout->count();
|
||||||
}
|
}
|
||||||
@@ -649,74 +643,142 @@ int CDockAreaWidget::count() const
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
CDockWidget* CDockAreaWidget::dockWidget(int Index) const
|
CDockWidget* CDockAreaWidget::dockWidget(int Index) const
|
||||||
{
|
{
|
||||||
return dynamic_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
|
return qobject_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
|
void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
|
||||||
{
|
{
|
||||||
|
qDebug() << "CDockAreaWidget::reorderDockWidget";
|
||||||
if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0
|
if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0
|
||||||
|| toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex)
|
|| toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex)
|
||||||
{
|
{
|
||||||
qDebug() << "Invalid index for tab movement" << fromIndex << toIndex;
|
qDebug() << "Invalid index for tab movement" << fromIndex << toIndex;
|
||||||
d->TabsLayout->update();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDockWidget* DockWidget = dockWidget(fromIndex);
|
auto Widget = d->ContentsLayout->widget(fromIndex);
|
||||||
|
d->ContentsLayout->removeWidget(Widget);
|
||||||
|
d->ContentsLayout->insertWidget(toIndex, Widget);
|
||||||
|
setCurrentIndex(toIndex);
|
||||||
|
}
|
||||||
|
|
||||||
// reorder tabs menu action to match new order of contents
|
|
||||||
auto Menu = d->TabsMenuButton->menu();
|
//============================================================================
|
||||||
auto TabsAction = d->dockWidgetTabAction(DockWidget);
|
void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open)
|
||||||
Menu->removeAction(TabsAction);
|
{
|
||||||
if (toIndex >= Menu->actions().count())
|
Q_UNUSED(DockWidget);
|
||||||
|
Q_UNUSED(Open);
|
||||||
|
updateTitleBarVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::updateTitleBarVisibility()
|
||||||
|
{
|
||||||
|
CDockContainerWidget* Container = dockContainer();
|
||||||
|
if (!Container)
|
||||||
{
|
{
|
||||||
Menu->addAction(TabsAction);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->TitleBar->setVisible(!Container->isFloating() || !Container->hasTopLevelDockWidget());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
|
||||||
|
{
|
||||||
|
s.writeStartElement("Area");
|
||||||
|
s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count()));
|
||||||
|
auto CurrentDockWidget = currentDockWidget();
|
||||||
|
QString Name = CurrentDockWidget ? CurrentDockWidget->objectName() : "";
|
||||||
|
s.writeAttribute("Current", Name);
|
||||||
|
qDebug() << "CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
|
||||||
|
<< " Current: " << Name;
|
||||||
|
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||||
|
{
|
||||||
|
dockWidget(i)->saveState(s);
|
||||||
|
}
|
||||||
|
s.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const
|
||||||
|
{
|
||||||
|
auto OpenDockWidgets = openedDockWidgets();
|
||||||
|
if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget))
|
||||||
|
{
|
||||||
|
CDockWidget* NextDockWidget;
|
||||||
|
if (OpenDockWidgets.last() == DockWidget)
|
||||||
|
{
|
||||||
|
NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int NextIndex = OpenDockWidgets.indexOf(DockWidget) + 1;
|
||||||
|
NextDockWidget = OpenDockWidgets[NextIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextDockWidget;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Menu->insertAction(Menu->actions().at(toIndex), TabsAction);
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// now reorder contents and title bars
|
|
||||||
QLayoutItem* liFrom = nullptr;
|
|
||||||
liFrom = d->TabsLayout->takeAt(fromIndex);
|
|
||||||
d->TabsLayout->insertItem(toIndex, liFrom);
|
|
||||||
liFrom = d->ContentsLayout->takeAt(fromIndex);
|
|
||||||
d->ContentsLayout->insertWidget(toIndex, liFrom->widget());
|
|
||||||
delete liFrom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action)
|
CDockWidget::DockWidgetFeatures CDockAreaWidget::features() const
|
||||||
{
|
{
|
||||||
int Index = d->TabsMenuButton->menu()->actions().indexOf(Action);
|
CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures);
|
||||||
setCurrentIndex(Index);
|
for (const auto DockWidget : dockWidgets())
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void CDockAreaWidget::updateDockArea()
|
|
||||||
{
|
|
||||||
d->updateTabBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void CDockAreaWidget::saveState(QDataStream& stream) const
|
|
||||||
{
|
|
||||||
stream << d->ContentsLayout->count() << 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);
|
Features &= DockWidget->features();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Features;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::toggleView(bool Open)
|
||||||
|
{
|
||||||
|
setVisible(Open);
|
||||||
|
|
||||||
|
emit viewToggled(Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::setVisible(bool Visible)
|
||||||
|
{
|
||||||
|
Super::setVisible(Visible);
|
||||||
|
if (d->UpdateCloseButton)
|
||||||
|
{
|
||||||
|
d->updateCloseButtonState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QAbstractButton* CDockAreaWidget::titleBarButton(TitleBarButton which) const
|
||||||
|
{
|
||||||
|
return d->TitleBar->button(which);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockAreaWidget::closeArea()
|
||||||
|
{
|
||||||
|
for (auto DockWidget : openedDockWidgets())
|
||||||
|
{
|
||||||
|
DockWidget->toggleView(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -32,32 +32,110 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
|
||||||
|
class QXmlStreamWriter;
|
||||||
|
class QAbstractButton;
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
struct DockAreaWidgetPrivate;
|
struct DockAreaWidgetPrivate;
|
||||||
class CDockManager;
|
class CDockManager;
|
||||||
class CDockContainerWidget;
|
class CDockContainerWidget;
|
||||||
class CDockWidget;
|
struct DockContainerWidgetPrivate;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DockAreaWidget manages multiple instances of DckWidgets.
|
* DockAreaWidget manages multiple instances of DockWidgets.
|
||||||
* It displays a title tab, which is clickable and will switch to
|
* It displays a title tab, which is clickable and will switch to
|
||||||
* the contents associated to the title when clicked.
|
* the contents associated to the title when clicked.
|
||||||
*/
|
*/
|
||||||
class CDockAreaWidget : public QFrame
|
class ADS_EXPORT CDockAreaWidget : public QFrame
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
DockAreaWidgetPrivate* d; ///< private data (pimpl)
|
DockAreaWidgetPrivate* d; ///< private data (pimpl)
|
||||||
friend class DockAreaWidgetPrivate;
|
friend struct DockAreaWidgetPrivate;
|
||||||
|
friend class CDockContainerWidget;
|
||||||
|
friend struct DockContainerWidgetPrivate;
|
||||||
|
friend class CDockWidgetTab;
|
||||||
|
friend struct DockWidgetPrivate;
|
||||||
|
friend class CDockWidget;
|
||||||
|
friend struct DockManagerPrivate;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDockWidgetTitleClicked();
|
void onTabCloseRequested(int Index);
|
||||||
void onTabsMenuActionTriggered(QAction* Action);
|
|
||||||
void onCloseButtonClicked();
|
/**
|
||||||
|
* Reorder the index position of DockWidget at fromIndx to toIndex
|
||||||
|
* if a tab in the tabbar is dragged from one index to another one
|
||||||
|
*/
|
||||||
|
void reorderDockWidget(int fromIndex, int toIndex);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from dock widget if it is opened or closed
|
||||||
|
*/
|
||||||
|
void toggleDockWidgetView(CDockWidget* DockWidget, bool Open);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a helper function to get the next open dock widget to activate
|
||||||
|
* if the given DockWidget will be closed or removed.
|
||||||
|
* The function returns the next widget that should be activated or
|
||||||
|
* nullptr in case there are no more open widgets in this area.
|
||||||
|
*/
|
||||||
|
CDockWidget* nextOpenDockWidget(CDockWidget* DockWidget) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the given DockWidget in the internal layout
|
||||||
|
*/
|
||||||
|
int index(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function, if you already know, that the dock does not
|
||||||
|
* contain any visible content (any open dock widgets).
|
||||||
|
*/
|
||||||
|
void hideAreaWithNoVisibleContent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dock area layout and components visibility
|
||||||
|
*/
|
||||||
|
void updateTitleBarVisibility();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the internal private function for setting the current widget.
|
||||||
|
* This function is called by the public setCurrentDockWidget() function
|
||||||
|
* and by the dock manager when restoring the state
|
||||||
|
*/
|
||||||
|
void internalSetCurrentDockWidget(CDockWidget* DockWidget);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void toggleView(bool Open);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Constructor
|
* Default Constructor
|
||||||
*/
|
*/
|
||||||
@@ -79,30 +157,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
CDockContainerWidget* dockContainer() const;
|
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
|
* Returns the rectangle of the title area
|
||||||
*/
|
*/
|
||||||
QRect titleAreaGeometry() const;
|
QRect titleBarGeometry() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the rectangle of the content
|
* Returns the rectangle of the content
|
||||||
@@ -110,15 +168,9 @@ public:
|
|||||||
QRect contentAreaGeometry() const;
|
QRect contentAreaGeometry() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tab index of the given DockWidget
|
* Returns the number of dock widgets in this area
|
||||||
*/
|
*/
|
||||||
int tabIndex(CDockWidget* DockWidget);
|
int dockWidgetsCount() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Returns a list of all dock widgets in this dock area.
|
||||||
@@ -126,56 +178,86 @@ public:
|
|||||||
*/
|
*/
|
||||||
QList<CDockWidget*> dockWidgets() const;
|
QList<CDockWidget*> dockWidgets() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of dock widgets in this area
|
||||||
|
*/
|
||||||
|
int openDockWidgetsCount() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of dock widgets that are not closed
|
* Returns a list of dock widgets that are not closed
|
||||||
*/
|
*/
|
||||||
QList<CDockWidget*> openedDockWidgets() const;
|
QList<CDockWidget*> openedDockWidgets() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of dock widgets in this area
|
|
||||||
*/
|
|
||||||
int count() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a dock widget by its index
|
* Returns a dock widget by its index
|
||||||
*/
|
*/
|
||||||
CDockWidget* dockWidget(int Index) const;
|
CDockWidget* dockWidget(int Index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reorder the index position of DockWidget at fromIndx to toIndex.
|
* Returns the index of the current active dock widget or -1 if there
|
||||||
*/
|
* are is no active dock widget (ie.e if all dock widgets are closed)
|
||||||
void reorderDockWidget(int fromIndex, int toIndex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the index of the current active dock widget
|
|
||||||
*/
|
*/
|
||||||
int currentIndex() const;
|
int currentIndex() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current active dock widget
|
* Returns the index of the first open dock widgets in the list of
|
||||||
|
* dock widgets.
|
||||||
|
* This function is here for performance reasons. Normally it would
|
||||||
|
* be possible to take the first dock widget from the list returned by
|
||||||
|
* openedDockWidgets() function. But that function enumerates all
|
||||||
|
* dock widgets while this functions stops after the first open dock widget.
|
||||||
|
* If there are no open dock widgets, the function returns -1.
|
||||||
|
*/
|
||||||
|
int indexOfFirstOpenDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current active dock widget or a nullptr if there is no
|
||||||
|
* active dock widget (i.e. if all dock widgets are closed)
|
||||||
*/
|
*/
|
||||||
CDockWidget* currentDockWidget() const;
|
CDockWidget* currentDockWidget() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the tab with tghe given dock widget
|
* Shows the tab with the given dock widget
|
||||||
*/
|
*/
|
||||||
void setCurrentDockWidget(CDockWidget* DockWidget);
|
void setCurrentDockWidget(CDockWidget* DockWidget);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the state into the given stream
|
* Saves the state into the given stream
|
||||||
*/
|
*/
|
||||||
void saveState(QDataStream& Stream) const;
|
void saveState(QXmlStreamWriter& Stream) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions returns the dock widget features of all dock widget in
|
||||||
|
* this area.
|
||||||
|
* A bitwise and is used to combine the flags of all dock widgets. That
|
||||||
|
* means, if only dock widget does not support a certain flag, the whole
|
||||||
|
* dock are does not support the flag.
|
||||||
|
*/
|
||||||
|
CDockWidget::DockWidgetFeatures features() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title bar button corresponding to the given title bar
|
||||||
|
* button identifier
|
||||||
|
*/
|
||||||
|
QAbstractButton* titleBarButton(TitleBarButton which) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the close button if visibility changed
|
||||||
|
*/
|
||||||
|
virtual void setVisible(bool Visible) override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/**
|
/**
|
||||||
* This sets the index position of the current tab page.
|
* This activates the tab for the given tab index.
|
||||||
|
* If the dock widget for the given tab is not visible, the this function
|
||||||
|
* call will make it visible.
|
||||||
*/
|
*/
|
||||||
void setCurrentIndex(int index);
|
void setCurrentIndex(int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the dock area layout and components visibility
|
* Closes the dock area and all dock widgets in this area
|
||||||
*/
|
*/
|
||||||
void updateDockArea();
|
void closeArea();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
@@ -183,12 +265,25 @@ signals:
|
|||||||
*/
|
*/
|
||||||
void tabBarClicked(int index);
|
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
|
* 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
|
* current has the given index, or -1 if there isn't a new one
|
||||||
* @param index
|
* @param index
|
||||||
*/
|
*/
|
||||||
void currentChanged(int index);
|
void currentChanged(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the visibility of this dock area is toggled
|
||||||
|
* via toggle view function
|
||||||
|
*/
|
||||||
|
void viewToggled(bool Open);
|
||||||
}; // class DockAreaWidget
|
}; // class DockAreaWidget
|
||||||
}
|
}
|
||||||
// namespace ads
|
// namespace ads
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -33,25 +33,39 @@
|
|||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
|
||||||
#include "ads_globals.h"
|
#include "ads_globals.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
|
||||||
|
class QXmlStreamWriter;
|
||||||
|
class QXmlStreamReader;
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
struct DockContainerWidgetPrivate;
|
class DockContainerWidgetPrivate;
|
||||||
class CDockAreaWidget;
|
class CDockAreaWidget;
|
||||||
class CDockWidget;
|
class CDockWidget;
|
||||||
class CDockManager;
|
class CDockManager;
|
||||||
|
struct DockManagerPrivate;
|
||||||
class CFloatingDockContainer;
|
class CFloatingDockContainer;
|
||||||
|
struct FloatingDockContainerPrivate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container that manages a number of dock areas with single dock widgets
|
* Container that manages a number of dock areas with single dock widgets
|
||||||
* or tabyfied dock widgets in each area
|
* or tabyfied dock widgets in each area
|
||||||
*/
|
*/
|
||||||
class CDockContainerWidget : public QFrame
|
class ADS_EXPORT CDockContainerWidget : public QFrame
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
DockContainerWidgetPrivate* d; ///< private data (pimpl)
|
DockContainerWidgetPrivate* d; ///< private data (pimpl)
|
||||||
friend class DockContainerWidgetPrivate;
|
friend struct DockContainerWidgetPrivate;
|
||||||
|
friend class CDockManager;
|
||||||
|
friend struct DockManagerPrivate;
|
||||||
|
friend class CDockAreaWidget;
|
||||||
|
friend struct DockAreaWidgetPrivate;
|
||||||
|
friend class CFloatingDockContainer;
|
||||||
|
friend struct FloatingDockContainerPrivate;
|
||||||
|
friend class CDockWidget;
|
||||||
|
Q_PRIVATE_SLOT(d, void onDockAreaViewToggled(bool Visible))
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@@ -64,6 +78,75 @@ protected:
|
|||||||
*/
|
*/
|
||||||
QSplitter* rootSplitter() const;
|
QSplitter* rootSplitter() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for creation of the root splitter
|
||||||
|
*/
|
||||||
|
void createRootSplitter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the last added dock area widget for the given
|
||||||
|
* area identifier or 0 if no dock area widget has been added for the given
|
||||||
|
* area
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* lastAddedDockAreaWidget(DockWidgetArea area) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if this dock area has only one single
|
||||||
|
* visible dock widget.
|
||||||
|
* A top level widget is a real floating widget. Only the isFloating()
|
||||||
|
* function of top level widgets may returns true.
|
||||||
|
*/
|
||||||
|
bool hasTopLevelDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If hasSingleVisibleDockWidget() returns true, this function returns the
|
||||||
|
* one and only visible dock widget. Otherwise it returns a nullptr.
|
||||||
|
*/
|
||||||
|
CDockWidget* topLevelDockWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the top level dock area.
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* topLevelDockArea() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns a list of all dock widgets in this floating widget.
|
||||||
|
* It may be possible, depending on the implementation, that dock widgets,
|
||||||
|
* that are not visible to the user have no parent widget. Therefore simply
|
||||||
|
* calling findChildren() would not work here. Therefore this function
|
||||||
|
* iterates over all dock areas and creates a list that contains all
|
||||||
|
* dock widgets returned from all dock areas.
|
||||||
|
*/
|
||||||
|
QList<CDockWidget*> dockWidgets() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Default Constructor
|
* Default Constructor
|
||||||
@@ -75,11 +158,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual ~CDockContainerWidget();
|
virtual ~CDockContainerWidget();
|
||||||
|
|
||||||
/**
|
|
||||||
* Drop floating widget into the container
|
|
||||||
*/
|
|
||||||
void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds dockwidget into the given area.
|
* Adds dockwidget into the given area.
|
||||||
* If DockAreaWidget is not null, then the area parameter indicates the area
|
* If DockAreaWidget is not null, then the area parameter indicates the area
|
||||||
@@ -90,16 +168,6 @@ public:
|
|||||||
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
||||||
CDockAreaWidget* DockAreaWidget = nullptr);
|
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
|
* Returns the current zOrderIndex
|
||||||
*/
|
*/
|
||||||
@@ -144,24 +212,27 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool isFloating() const;
|
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
|
* Dumps the layout for debugging purposes
|
||||||
*/
|
*/
|
||||||
void dumpLayout();
|
void dumpLayout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions returns the dock widget features of all dock widget in
|
||||||
|
* this container.
|
||||||
|
* A bitwise and is used to combine the flags of all dock widgets. That
|
||||||
|
* means, if only dock widget does not support a certain flag, the whole
|
||||||
|
* dock are does not support the flag.
|
||||||
|
*/
|
||||||
|
CDockWidget::DockWidgetFeatures features() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this dock container is in a floating widget, this function returns
|
||||||
|
* the floating widget.
|
||||||
|
* Else, it returns a nullptr.
|
||||||
|
*/
|
||||||
|
CFloatingDockContainer* floatingWidget() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* This signal is emitted if one or multiple dock areas has been added to
|
* This signal is emitted if one or multiple dock areas has been added to
|
||||||
@@ -174,6 +245,12 @@ signals:
|
|||||||
* This signal is emitted if one or multiple dock areas has been removed
|
* This signal is emitted if one or multiple dock areas has been removed
|
||||||
*/
|
*/
|
||||||
void dockAreasRemoved();
|
void dockAreasRemoved();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if a dock area is opened or closed via
|
||||||
|
* toggleView() function
|
||||||
|
*/
|
||||||
|
void dockAreaViewToggled(CDockAreaWidget* DockArea, bool Open);
|
||||||
}; // class DockContainerWidget
|
}; // class DockContainerWidget
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -28,28 +28,34 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// INCLUDES
|
// INCLUDES
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
#include <DockWidgetTab.h>
|
||||||
#include "DockManager.h"
|
#include "DockManager.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QApplication>
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
#include "FloatingDockContainer.h"
|
#include "FloatingDockContainer.h"
|
||||||
#include "DockOverlay.h"
|
#include "DockOverlay.h"
|
||||||
#include "DockWidget.h"
|
#include "DockWidget.h"
|
||||||
#include "ads_globals.h"
|
#include "ads_globals.h"
|
||||||
#include "DockStateSerialization.h"
|
|
||||||
#include "DockWidgetTitleBar.h"
|
|
||||||
#include "DockAreaWidget.h"
|
#include "DockAreaWidget.h"
|
||||||
|
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data class of CDockManager class (pimpl)
|
* Private data class of CDockManager class (pimpl)
|
||||||
*/
|
*/
|
||||||
@@ -61,6 +67,12 @@ struct DockManagerPrivate
|
|||||||
CDockOverlay* ContainerOverlay;
|
CDockOverlay* ContainerOverlay;
|
||||||
CDockOverlay* DockAreaOverlay;
|
CDockOverlay* DockAreaOverlay;
|
||||||
QMap<QString, CDockWidget*> DockWidgetsMap;
|
QMap<QString, CDockWidget*> DockWidgetsMap;
|
||||||
|
QMap<QString, QByteArray> Perspectives;
|
||||||
|
QMap<QString, QMenu*> ViewMenuGroups;
|
||||||
|
QMenu* ViewMenu;
|
||||||
|
CDockManager::eViewMenuInsertionOrder MenuInsertionOrder = CDockManager::MenuAlphabeticallySorted;
|
||||||
|
bool RestoringState = false;
|
||||||
|
CDockManager::ConfigFlags ConfigFlags{CDockManager::DefaultConfig};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data constructor
|
* Private data constructor
|
||||||
@@ -76,17 +88,48 @@ struct DockManagerPrivate
|
|||||||
/**
|
/**
|
||||||
* Restores the state
|
* Restores the state
|
||||||
*/
|
*/
|
||||||
|
bool restoreStateFromXml(const QByteArray &state, int version, bool Testing = internal::Restore);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore state
|
||||||
|
*/
|
||||||
bool restoreState(const QByteArray &state, int version);
|
bool restoreState(const QByteArray &state, int version);
|
||||||
|
|
||||||
|
void restoreDockWidgetsOpenState();
|
||||||
|
void restoreDockAreasIndices();
|
||||||
|
void emitTopLevelEvents();
|
||||||
|
|
||||||
|
void hideFloatingWidgets()
|
||||||
|
{
|
||||||
|
// Hide updates of floating widgets from use
|
||||||
|
for (auto FloatingWidget : FloatingWidgets)
|
||||||
|
{
|
||||||
|
FloatingWidget->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void markDockWidgetsDirty()
|
||||||
|
{
|
||||||
|
for (auto DockWidget : DockWidgetsMap)
|
||||||
|
{
|
||||||
|
DockWidget->setProperty("dirty", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the container with the given index
|
* 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
|
* Loads the stylesheet
|
||||||
*/
|
*/
|
||||||
void loadStylesheet();
|
void loadStylesheet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds action to menu - optionally in sorted order
|
||||||
|
*/
|
||||||
|
void addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted);
|
||||||
};
|
};
|
||||||
// struct DockManagerPrivate
|
// struct DockManagerPrivate
|
||||||
|
|
||||||
@@ -112,115 +155,254 @@ void DockManagerPrivate::loadStylesheet()
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
bool DockManagerPrivate::checkFormat(const QByteArray &state, int version)
|
bool DockManagerPrivate::restoreContainer(int Index, QXmlStreamReader& stream, bool Testing)
|
||||||
{
|
{
|
||||||
if (state.isEmpty())
|
if (Testing)
|
||||||
{
|
{
|
||||||
return false;
|
Index = 0;
|
||||||
}
|
}
|
||||||
QByteArray sd = state;
|
|
||||||
QDataStream stream(&sd, QIODevice::ReadOnly);
|
|
||||||
|
|
||||||
int marker;
|
bool Result = false;
|
||||||
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())
|
if (Index >= Containers.count())
|
||||||
{
|
{
|
||||||
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
|
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this);
|
||||||
return FloatingWidget->restoreState(stream, Testing);
|
Result = FloatingWidget->restoreState(stream, Testing);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "d->Containers[i]->restoreState ";
|
qDebug() << "d->Containers[i]->restoreState ";
|
||||||
return Containers[Index]->restoreState(stream, Testing);
|
auto Container = Containers[Index];
|
||||||
|
if (Container->isFloating())
|
||||||
|
{
|
||||||
|
Result = Container->floatingWidget()->restoreState(stream, Testing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result = Container->restoreState(stream, Testing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
bool DockManagerPrivate::restoreState(const QByteArray &state, int version)
|
bool DockManagerPrivate::checkFormat(const QByteArray &state, int version)
|
||||||
|
{
|
||||||
|
return restoreStateFromXml(state, version, internal::RestoreTesting);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version,
|
||||||
|
bool Testing)
|
||||||
{
|
{
|
||||||
if (state.isEmpty())
|
if (state.isEmpty())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QByteArray sd = state;
|
QXmlStreamReader s(state);
|
||||||
QDataStream stream(&sd, QIODevice::ReadOnly);
|
s.readNextStartElement();
|
||||||
|
if (s.name() != "QtAdvancedDockingSystem")
|
||||||
int marker;
|
|
||||||
int v;
|
|
||||||
stream >> marker;
|
|
||||||
stream >> v;
|
|
||||||
|
|
||||||
if (stream.status() != QDataStream::Ok || marker != internal::VersionMarker || v != version)
|
|
||||||
{
|
{
|
||||||
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;
|
bool Result = true;
|
||||||
int ContainerCount;
|
int DockContainers = s.attributes().value("Containers").toInt();
|
||||||
stream >> ContainerCount;
|
qDebug() << DockContainers;
|
||||||
qDebug() << "ContainerCount " << ContainerCount;
|
int DockContainerCount = 0;
|
||||||
int i;
|
while (s.readNextStartElement())
|
||||||
for (i = 0; i < ContainerCount; ++i)
|
|
||||||
{
|
{
|
||||||
Result = restoreContainer(i, stream, internal::Restore);
|
if (s.name() == "Container")
|
||||||
if (!Result)
|
|
||||||
{
|
{
|
||||||
break;
|
Result = restoreContainer(DockContainerCount, s, Testing);
|
||||||
|
if (!Result)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DockContainerCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete remaining empty floating widgets
|
if (!Testing)
|
||||||
int FloatingWidgetIndex = i - 1;
|
|
||||||
int DeleteCount = FloatingWidgets.count() - FloatingWidgetIndex;
|
|
||||||
for (int i = 0; i < DeleteCount; ++i)
|
|
||||||
{
|
{
|
||||||
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();
|
||||||
|
_this->removeDockContainer(FloatingWidgets[FloatingWidgetIndex + i]->dockContainer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::restoreDockWidgetsOpenState()
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
// They do not belong to any dock container, until the user toggles the
|
||||||
|
// toggle view action the next time
|
||||||
|
for (auto DockWidget : DockWidgetsMap)
|
||||||
|
{
|
||||||
|
if (DockWidget->property("dirty").toBool())
|
||||||
|
{
|
||||||
|
DockWidget->flagAsUnassigned();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockWidget->toggleViewInternal(!DockWidget->property("closed").toBool());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::restoreDockAreasIndices()
|
||||||
|
{
|
||||||
|
// Now all dock areas are properly restored and we setup the index of
|
||||||
|
// The dock areas because the previous toggleView() action has changed
|
||||||
|
// the dock area index
|
||||||
|
int Count = 0;
|
||||||
|
for (auto DockContainer : Containers)
|
||||||
|
{
|
||||||
|
Count++;
|
||||||
|
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
||||||
|
{
|
||||||
|
CDockAreaWidget* DockArea = DockContainer->dockArea(i);
|
||||||
|
QString DockWidgetName = DockArea->property("currentDockWidget").toString();
|
||||||
|
CDockWidget* DockWidget = nullptr;
|
||||||
|
if (!DockWidgetName.isEmpty())
|
||||||
|
{
|
||||||
|
DockWidget = _this->findDockWidget(DockWidgetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DockWidget || DockWidget->isClosed())
|
||||||
|
{
|
||||||
|
int Index = DockArea->indexOfFirstOpenDockWidget();
|
||||||
|
if (Index < 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DockArea->setCurrentIndex(Index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DockArea->internalSetCurrentDockWidget(DockWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::emitTopLevelEvents()
|
||||||
|
{
|
||||||
|
// Finally we need to send the topLevelChanged() signals for all dock
|
||||||
|
// widgets if top level changed
|
||||||
|
for (auto DockContainer : Containers)
|
||||||
|
{
|
||||||
|
CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget();
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
||||||
|
{
|
||||||
|
auto DockArea = DockContainer->dockArea(i);
|
||||||
|
for (auto DockWidget : DockArea->dockWidgets())
|
||||||
|
{
|
||||||
|
DockWidget->emitTopLevelChanged(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockManagerPrivate::restoreState(const QByteArray &state, int version)
|
||||||
|
{
|
||||||
|
if (!checkFormat(state, version))
|
||||||
|
{
|
||||||
|
qDebug() << "checkFormat: Error checking format!!!!!!!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide updates of floating widgets from use
|
||||||
|
hideFloatingWidgets();
|
||||||
|
markDockWidgetsDirty();
|
||||||
|
|
||||||
|
if (!restoreStateFromXml(state, version))
|
||||||
|
{
|
||||||
|
qDebug() << "restoreState: Error restoring state!!!!!!!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreDockWidgetsOpenState();
|
||||||
|
restoreDockAreasIndices();
|
||||||
|
emitTopLevelEvents();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockManagerPrivate::addActionToMenu(QAction* Action, QMenu* Menu, bool InsertSorted)
|
||||||
|
{
|
||||||
|
if (InsertSorted)
|
||||||
|
{
|
||||||
|
auto Actions = Menu->actions();
|
||||||
|
auto it = std::find_if(Actions.begin(), Actions.end(),
|
||||||
|
[&Action](const QAction* a)
|
||||||
|
{
|
||||||
|
return a->text().compare(Action->text(), Qt::CaseInsensitive) > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it == Actions.end())
|
||||||
|
{
|
||||||
|
Menu->addAction(Action);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Menu->insertAction(*it, Action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Menu->addAction(Action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockManager::CDockManager(QWidget *parent) :
|
CDockManager::CDockManager(QWidget *parent) :
|
||||||
CDockContainerWidget(this, parent),
|
CDockContainerWidget(this, parent),
|
||||||
d(new DockManagerPrivate(this))
|
d(new DockManagerPrivate(this))
|
||||||
{
|
{
|
||||||
|
createRootSplitter();
|
||||||
QMainWindow* MainWindow = dynamic_cast<QMainWindow*>(parent);
|
QMainWindow* MainWindow = dynamic_cast<QMainWindow*>(parent);
|
||||||
if (MainWindow)
|
if (MainWindow)
|
||||||
{
|
{
|
||||||
MainWindow->setCentralWidget(this);
|
MainWindow->setCentralWidget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d->ViewMenu = new QMenu(tr("Show View"), this);
|
||||||
d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay);
|
d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay);
|
||||||
d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
|
d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
|
||||||
d->Containers.append(this);
|
d->Containers.append(this);
|
||||||
@@ -307,75 +489,61 @@ unsigned int CDockManager::zOrderIndex() const
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
QByteArray CDockManager::saveState(int version) const
|
QByteArray CDockManager::saveState(eXmlMode XmlMode, int version) const
|
||||||
{
|
{
|
||||||
QByteArray data;
|
QByteArray xmldata;
|
||||||
QDataStream stream(&data, QIODevice::WriteOnly);
|
QXmlStreamWriter s(&xmldata);
|
||||||
stream << internal::VersionMarker;
|
s.setAutoFormatting(XmlAutoFormattingEnabled == XmlMode);
|
||||||
stream << version;
|
s.writeStartDocument();
|
||||||
|
s.writeStartElement("QtAdvancedDockingSystem");
|
||||||
|
s.writeAttribute("Version", QString::number(version));
|
||||||
|
s.writeAttribute("Containers", QString::number(d->Containers.count()));
|
||||||
|
for (auto Container : d->Containers)
|
||||||
|
{
|
||||||
|
Container->saveState(s);
|
||||||
|
}
|
||||||
|
|
||||||
stream << d->Containers.count();
|
s.writeEndElement();
|
||||||
for (auto Container : d->Containers)
|
s.writeEndDocument();
|
||||||
{
|
|
||||||
Container->saveState(stream);
|
return xmldata;
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
bool CDockManager::restoreState(const QByteArray &state, int version)
|
bool CDockManager::restoreState(const QByteArray &state, int version)
|
||||||
{
|
{
|
||||||
if (!d->checkFormat(state, version))
|
// Prevent multiple calls as long as state is not restore. This may
|
||||||
{
|
// happen, if QApplication::processEvents() is called somewhere
|
||||||
qDebug() << "checkFormat: Error checking format!!!!!!!";
|
if (d->RestoringState)
|
||||||
return false;
|
{
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto DockWidget : d->DockWidgetsMap)
|
// We hide the complete dock manager here. Restoring the state means
|
||||||
{
|
// that DockWidgets are removed from the DockArea internal stack layout
|
||||||
DockWidget->setProperty("dirty", true);
|
// which in turn means, that each time a widget is removed the stack
|
||||||
}
|
// will show and raise the next available widget which in turn
|
||||||
|
// triggers show events for the dock widgets. To avoid this we hide the
|
||||||
|
// dock manager. Because there will be no processing of application
|
||||||
|
// events until this function is finished, the user will not see this
|
||||||
|
// hiding
|
||||||
|
bool IsHidden = this->isHidden();
|
||||||
|
if (!IsHidden)
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
d->RestoringState = true;
|
||||||
|
emit restoringState();
|
||||||
|
bool Result = d->restoreState(state, version);
|
||||||
|
d->RestoringState = false;
|
||||||
|
emit stateRestored();
|
||||||
|
if (!IsHidden)
|
||||||
|
{
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
if (!d->restoreState(state, version))
|
return Result;
|
||||||
{
|
|
||||||
qDebug() << "restoreState: Error restoring state!!!!!!!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// toggle view action the next time
|
|
||||||
for (auto DockWidget : d->DockWidgetsMap)
|
|
||||||
{
|
|
||||||
if (DockWidget->property("dirty").toBool())
|
|
||||||
{
|
|
||||||
DockWidget->flagAsUnassigned();
|
|
||||||
}
|
|
||||||
else if (!DockWidget->property("closed").toBool())
|
|
||||||
{
|
|
||||||
DockWidget->toggleView(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now all dock areas are properly restored and we setup the index of
|
|
||||||
// The dock areas because the previous toggleView() action has changed
|
|
||||||
// the dock area index
|
|
||||||
for (auto DockContainer : d->Containers)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
|
||||||
{
|
|
||||||
CDockAreaWidget* DockArea = DockContainer->dockArea(i);
|
|
||||||
int CurrentIndex = DockArea->property("currentIndex").toInt();
|
|
||||||
if (CurrentIndex < DockArea->count() && DockArea->count() > 1 && CurrentIndex > -1)
|
|
||||||
{
|
|
||||||
DockArea->setCurrentIndex(CurrentIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -389,10 +557,208 @@ CDockAreaWidget* CDockManager::addDockWidget(DockWidgetArea area,
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockWidget* CDockManager::findDockWidget(const QString& ObjectName)
|
CDockAreaWidget* CDockManager::addDockWidgetTab(DockWidgetArea area,
|
||||||
|
CDockWidget* Dockwidget)
|
||||||
|
{
|
||||||
|
CDockAreaWidget* AreaWidget = lastAddedDockAreaWidget(area);
|
||||||
|
if (AreaWidget)
|
||||||
|
{
|
||||||
|
return addDockWidget(ads::CenterDockWidgetArea, Dockwidget, AreaWidget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return addDockWidget(area, Dockwidget, AreaWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget* CDockManager::addDockWidgetTabToArea(CDockWidget* Dockwidget,
|
||||||
|
CDockAreaWidget* DockAreaWidget)
|
||||||
|
{
|
||||||
|
return addDockWidget(ads::CenterDockWidgetArea, Dockwidget, DockAreaWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockManager::findDockWidget(const QString& ObjectName) const
|
||||||
{
|
{
|
||||||
return d->DockWidgetsMap.value(ObjectName, nullptr);
|
return d->DockWidgetsMap.value(ObjectName, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QMap<QString, CDockWidget*> CDockManager::dockWidgetsMap() const
|
||||||
|
{
|
||||||
|
return d->DockWidgetsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::addPerspective(const QString& UniquePrespectiveName)
|
||||||
|
{
|
||||||
|
d->Perspectives.insert(UniquePrespectiveName, saveState());
|
||||||
|
emit perspectiveListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::removePerspective(const QString& Name)
|
||||||
|
{
|
||||||
|
removePerspectives({Name});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::removePerspectives(const QStringList& Names)
|
||||||
|
{
|
||||||
|
int Count = 0;
|
||||||
|
for (auto Name : Names)
|
||||||
|
{
|
||||||
|
Count += d->Perspectives.remove(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Count)
|
||||||
|
{
|
||||||
|
emit perspectivesRemoved();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit openingPerspective(PerspectiveName);
|
||||||
|
restoreState(Iterator.value());
|
||||||
|
emit perspectiveOpened(PerspectiveName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QAction* CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
|
||||||
|
const QString& Group, const QIcon& GroupIcon)
|
||||||
|
{
|
||||||
|
bool AlphabeticallySorted = (MenuAlphabeticallySorted == d->MenuInsertionOrder);
|
||||||
|
if (!Group.isEmpty())
|
||||||
|
{
|
||||||
|
QMenu* GroupMenu = d->ViewMenuGroups.value(Group, 0);
|
||||||
|
if (!GroupMenu)
|
||||||
|
{
|
||||||
|
GroupMenu = new QMenu(Group, this);
|
||||||
|
GroupMenu->setIcon(GroupIcon);
|
||||||
|
d->addActionToMenu(GroupMenu->menuAction(), d->ViewMenu, AlphabeticallySorted);
|
||||||
|
d->ViewMenuGroups.insert(Group, GroupMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
d->addActionToMenu(ToggleViewAction, GroupMenu, AlphabeticallySorted);
|
||||||
|
return GroupMenu->menuAction();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->addActionToMenu(ToggleViewAction, d->ViewMenu, AlphabeticallySorted);
|
||||||
|
return ToggleViewAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QMenu* CDockManager::viewMenu() const
|
||||||
|
{
|
||||||
|
return d->ViewMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockManager::setViewMenuInsertionOrder(eViewMenuInsertionOrder Order)
|
||||||
|
{
|
||||||
|
d->MenuInsertionOrder = Order;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool CDockManager::isRestoringState() const
|
||||||
|
{
|
||||||
|
return d->RestoringState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
int CDockManager::startDragDistance()
|
||||||
|
{
|
||||||
|
return QApplication::startDragDistance() * 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
CDockManager::ConfigFlags CDockManager::configFlags() const
|
||||||
|
{
|
||||||
|
return d->ConfigFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockManager::setConfigFlags(const ConfigFlags Flags)
|
||||||
|
{
|
||||||
|
d->ConfigFlags = Flags;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -31,40 +31,43 @@
|
|||||||
// INCLUDES
|
// INCLUDES
|
||||||
//============================================================================
|
//============================================================================
|
||||||
#include "DockContainerWidget.h"
|
#include "DockContainerWidget.h"
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class QSettings;
|
||||||
|
class QMenu;
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
struct DockManagerPrivate;
|
struct DockManagerPrivate;
|
||||||
class CFloatingDockContainer;
|
class CFloatingDockContainer;
|
||||||
|
struct FloatingDockContainerPrivate;
|
||||||
class CDockContainerWidget;
|
class CDockContainerWidget;
|
||||||
class CDockOverlay;
|
class CDockOverlay;
|
||||||
|
class CDockAreaTabBar;
|
||||||
|
class CDockWidgetTab;
|
||||||
|
struct DockWidgetTabPrivate;
|
||||||
|
struct DockAreaWidgetPrivate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The central dock manager that maintains the complete docking system
|
* The central dock manager that maintains the complete docking system
|
||||||
**/
|
**/
|
||||||
class CDockManager : public CDockContainerWidget
|
class ADS_EXPORT CDockManager : public CDockContainerWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
DockManagerPrivate* d; ///< private data (pimpl)
|
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:
|
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
|
* Registers the given floating widget in the internal list of
|
||||||
* floating widgets
|
* floating widgets
|
||||||
@@ -98,22 +101,102 @@ public:
|
|||||||
*/
|
*/
|
||||||
CDockOverlay* dockAreaOverlay() const;
|
CDockOverlay* dockAreaOverlay() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum eViewMenuInsertionOrder
|
||||||
|
{
|
||||||
|
MenuSortedByInsertion,
|
||||||
|
MenuAlphabeticallySorted
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eXmlMode
|
||||||
|
{
|
||||||
|
XmlAutoFormattingDisabled,
|
||||||
|
XmlAutoFormattingEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These global configuration flags configure some global dock manager
|
||||||
|
* settings.
|
||||||
|
*/
|
||||||
|
enum eConfigFlag
|
||||||
|
{
|
||||||
|
ActiveTabHasCloseButton = 0x01, //!< If this flag is set, the active tab in a tab area has a close button
|
||||||
|
DockAreaHasCloseButton = 0x02, //!< If the flag is set each dock area has a close button
|
||||||
|
DockAreaCloseButtonClosesTab = 0x04,//!< If the flag is set, the dock area close button closes the active tab, if not set, it closes the complete cock area
|
||||||
|
OpaqueSplitterResize = 0x08, //!< See QSplitter::setOpaqueResize() documentation
|
||||||
|
DefaultConfig = ActiveTabHasCloseButton | DockAreaHasCloseButton | OpaqueSplitterResize, ///< the default configuration
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Constructor.
|
||||||
|
* If the given parent is a QMainWindow, the dock manager sets itself as the
|
||||||
|
* central widget.
|
||||||
|
* Before you create any dock widgets, you should properly setup the
|
||||||
|
* configuration flags via setConfigFlags()
|
||||||
|
*/
|
||||||
|
CDockManager(QWidget* parent = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual Destructor
|
||||||
|
*/
|
||||||
|
virtual ~CDockManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the global configuration flags
|
||||||
|
*/
|
||||||
|
ConfigFlags configFlags() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the global configuration flags for the whole docking system.
|
||||||
|
* Call this function before you create your first dock widget.
|
||||||
|
*/
|
||||||
|
void setConfigFlags(const ConfigFlags Flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds dockwidget into the given area.
|
* Adds dockwidget into the given area.
|
||||||
* If DockAreaWidget is not null, then the area parameter indicates the area
|
* If DockAreaWidget is not null, then the area parameter indicates the area
|
||||||
* into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will
|
* 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
|
* \return Returns the dock area widget that contains the new DockWidget
|
||||||
*/
|
*/
|
||||||
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
|
||||||
CDockAreaWidget* DockAreaWidget = nullptr);
|
CDockAreaWidget* DockAreaWidget = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will add the given Dockwidget to the given dock area as
|
||||||
|
* a new tab.
|
||||||
|
* If no dock area widget exists for the given area identifier, a new
|
||||||
|
* dock area widget is created.
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* addDockWidgetTab(DockWidgetArea area,
|
||||||
|
CDockWidget* Dockwidget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will add the given Dockwidget to the given DockAreaWidget
|
||||||
|
* as a new tab.
|
||||||
|
*/
|
||||||
|
CDockAreaWidget* addDockWidgetTabToArea(CDockWidget* Dockwidget,
|
||||||
|
CDockAreaWidget* DockAreaWidget);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for a registered doc widget with the given ObjectName
|
* Searches for a registered doc widget with the given ObjectName
|
||||||
* \return Return the found dock widget or nullptr if a dock widget with the
|
* \return Return the found dock widget or nullptr if a dock widget with the
|
||||||
* given name is not registered
|
* given name is not registered
|
||||||
*/
|
*/
|
||||||
CDockWidget* findDockWidget(const QString& ObjectName);
|
CDockWidget* findDockWidget(const QString& ObjectName) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns a readable reference to the internal dock
|
||||||
|
* widgets map so that it is possible to iterate over all dock widgets
|
||||||
|
*/
|
||||||
|
QMap<QString, CDockWidget*> dockWidgetsMap() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of all active and visible dock containers
|
* Returns the list of all active and visible dock containers
|
||||||
@@ -134,8 +217,13 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current state of the dockmanger and all its dock widgets
|
* Saves the current state of the dockmanger and all its dock widgets
|
||||||
|
* into the returned QByteArray.
|
||||||
|
* The XmlMode enables / disables the auto formatting for the XmlStreamWriter.
|
||||||
|
* If auto formatting is enabled, the output is intended and line wrapped.
|
||||||
|
* The XmlMode XmlAutoFormattingDisabled is better if you would like to have
|
||||||
|
* a more compact XML output - i.e. for storage in ini files.
|
||||||
*/
|
*/
|
||||||
QByteArray saveState(int version = 0) const;
|
QByteArray saveState(eXmlMode XmlMode = XmlAutoFormattingDisabled, int version = 0) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the state of this dockmanagers dockwidgets.
|
* Restores the state of this dockmanagers dockwidgets.
|
||||||
@@ -145,6 +233,138 @@ public:
|
|||||||
* returns true.
|
* returns true.
|
||||||
*/
|
*/
|
||||||
bool restoreState(const QByteArray &state, int version = 0);
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the perspective with the given name from the list of perspectives
|
||||||
|
*/
|
||||||
|
void removePerspective(const QString& Name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given perspectives from the dock manager
|
||||||
|
*/
|
||||||
|
void removePerspectives(const QStringList& Names);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a toggle view action to the the internal view menu.
|
||||||
|
* You can either manage the insertion of the toggle view actions in your
|
||||||
|
* application or you can add the actions to the internal view menu and
|
||||||
|
* then simply insert the menu object into your.
|
||||||
|
* \param[in] ToggleViewAction The action to insert. If no group is provided
|
||||||
|
* the action is directly inserted into the menu. If a group
|
||||||
|
* is provided, the action is inserted into the group and the
|
||||||
|
* group is inserted into the menu if it is not existing yet.
|
||||||
|
* \param[in] Group This is the text used for the group menu item
|
||||||
|
* \param[in] GroupIcon The icon used for grouping the workbenches in the
|
||||||
|
* view menu. I.e. if there is a workbench for each device
|
||||||
|
* like for spectrometer devices, it is good to group all these
|
||||||
|
* workbenches under a menu item
|
||||||
|
* \return If Group is not empty, this function returns the GroupAction
|
||||||
|
* for this group. If the group is empty, the function returns
|
||||||
|
* the given ToggleViewAction.
|
||||||
|
*/
|
||||||
|
QAction* addToggleViewActionToMenu(QAction* ToggleViewAction,
|
||||||
|
const QString& Group = QString(), const QIcon& GroupIcon = QIcon());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the internal view menu.
|
||||||
|
* To fill the view menu, you can use the addToggleViewActionToMenu()
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
QMenu* viewMenu() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the insertion order for toggle view menu items.
|
||||||
|
* The order defines how the actions are added to the view menu.
|
||||||
|
* The default insertion order is MenuAlphabeticallySorted to make it
|
||||||
|
* easier for users to find the menu entry for a certain dock widget.
|
||||||
|
* You need to call this function befor you insert the first menu item
|
||||||
|
* into the view menu.
|
||||||
|
*/
|
||||||
|
void setViewMenuInsertionOrder(eViewMenuInsertionOrder Order);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true between the restoringState() and
|
||||||
|
* stateRestored() signals.
|
||||||
|
*/
|
||||||
|
bool isRestoringState() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance the user needs to move the mouse with the left button
|
||||||
|
* hold down before a dock widget start floating
|
||||||
|
*/
|
||||||
|
static int startDragDistance();
|
||||||
|
|
||||||
|
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 perspectives have been removed
|
||||||
|
*/
|
||||||
|
void perspectivesRemoved();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, if the restore function is called, just before
|
||||||
|
* the dock manager starts restoring the state.
|
||||||
|
* If this function is called, nothing has changed yet
|
||||||
|
*/
|
||||||
|
void restoringState();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 stateRestored();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted, if the dock manager starts opening a
|
||||||
|
* perspective.
|
||||||
|
* Opening a perspective may take more than a second if there are
|
||||||
|
* many complex widgets. The application may use this signal
|
||||||
|
* to show some progress indicator or to change the mouse cursor
|
||||||
|
* into a busy cursor.
|
||||||
|
*/
|
||||||
|
void openingPerspective(const QString& PerspectiveName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the dock manager finished opening a
|
||||||
|
* perspective
|
||||||
|
*/
|
||||||
|
void perspectiveOpened(const QString& PerspectiveName);
|
||||||
}; // class DockManager
|
}; // class DockManager
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -33,160 +33,15 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
#include "DockAreaWidget.h"
|
#include "DockAreaWidget.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ads
|
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
|
* Private data class of CDockOverlay
|
||||||
@@ -219,6 +74,9 @@ struct DockOverlayCrossPrivate
|
|||||||
CDockOverlay* DockOverlay;
|
CDockOverlay* DockOverlay;
|
||||||
QHash<DockWidgetArea, QWidget*> DropIndicatorWidgets;
|
QHash<DockWidgetArea, QWidget*> DropIndicatorWidgets;
|
||||||
QGridLayout* GridLayout;
|
QGridLayout* GridLayout;
|
||||||
|
QColor IconColors[5];
|
||||||
|
bool UpdateRequired = false;
|
||||||
|
double LastDevicePixelRatio = 0.1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data constructor
|
* Private data constructor
|
||||||
@@ -231,6 +89,221 @@ struct DockOverlayCrossPrivate
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
QPoint areaGridPosition(const DockWidgetArea area);
|
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(createHighDpiDropIndicatorPixmap(size, DockWidgetArea, Mode));
|
||||||
|
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||||
|
l->setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
l->setProperty("dockWidgetArea", DockWidgetArea);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void updateDropIndicatorIcon(QWidget* DropIndicatorWidget)
|
||||||
|
{
|
||||||
|
QLabel* l = qobject_cast<QLabel*>(DropIndicatorWidget);
|
||||||
|
const qreal metric = static_cast<qreal>(l->fontMetrics().height()) * 3.f;
|
||||||
|
const QSizeF size(metric, metric);
|
||||||
|
|
||||||
|
int Area = l->property("dockWidgetArea").toInt();
|
||||||
|
l->setPixmap(createHighDpiDropIndicatorPixmap(size, (DockWidgetArea)Area, Mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QPixmap createHighDpiDropIndicatorPixmap(const QSizeF& size, DockWidgetArea DockWidgetArea,
|
||||||
|
CDockOverlay::eMode Mode)
|
||||||
|
{
|
||||||
|
QColor borderColor = iconColor(CDockOverlayCross::FrameColor);
|
||||||
|
QColor backgroundColor = iconColor(CDockOverlayCross::WindowBackgroundColor);
|
||||||
|
|
||||||
|
double DevicePixelRatio = _this->window()->devicePixelRatioF();
|
||||||
|
QSizeF PixmapSize = size * DevicePixelRatio;
|
||||||
|
QPixmap pm(PixmapSize.toSize());
|
||||||
|
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.setWidth(1);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.setDevicePixelRatio(DevicePixelRatio);
|
||||||
|
return pm;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -247,7 +320,6 @@ CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) :
|
|||||||
setAttribute(Qt::WA_NoSystemBackground);
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
setAttribute(Qt::WA_TranslucentBackground);
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
|
||||||
d->Cross->setupOverlayCross(Mode);
|
|
||||||
d->Cross->setVisible(false);
|
d->Cross->setVisible(false);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
}
|
||||||
@@ -292,7 +364,7 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DockArea->titleAreaGeometry().contains(DockArea->mapFromGlobal(QCursor::pos())))
|
if (DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(QCursor::pos())))
|
||||||
{
|
{
|
||||||
return CenterDockWidgetArea;
|
return CenterDockWidgetArea;
|
||||||
}
|
}
|
||||||
@@ -326,6 +398,7 @@ DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
|
|||||||
move(TopLeft);
|
move(TopLeft);
|
||||||
show();
|
show();
|
||||||
d->Cross->updatePosition();
|
d->Cross->updatePosition();
|
||||||
|
d->Cross->updateOverlayIcons();
|
||||||
return dropAreaUnderCursor();
|
return dropAreaUnderCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,9 +448,16 @@ void CDockOverlay::paintEvent(QPaintEvent* event)
|
|||||||
}
|
}
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
|
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
|
||||||
|
QPen Pen = painter.pen();
|
||||||
|
Pen.setColor(Color.darker(120));
|
||||||
|
Pen.setStyle(Qt::SolidLine);
|
||||||
|
Pen.setWidth(1);
|
||||||
|
Pen.setCosmetic(true);
|
||||||
|
painter.setPen(Pen);
|
||||||
|
Color = Color.lighter(130);
|
||||||
Color.setAlpha(64);
|
Color.setAlpha(64);
|
||||||
painter.setPen(Qt::NoPen);
|
painter.setBrush(Color);
|
||||||
painter.fillRect(r, Color);
|
painter.drawRect(r.adjusted(0, 0, -1, -1));
|
||||||
d->DropAreaRect = r;
|
d->DropAreaRect = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,6 +485,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)
|
static int areaAlignment(const DockWidgetArea area)
|
||||||
{
|
{
|
||||||
@@ -480,13 +572,46 @@ void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode)
|
|||||||
d->Mode = Mode;
|
d->Mode = Mode;
|
||||||
|
|
||||||
QHash<DockWidgetArea, QWidget*> areaWidgets;
|
QHash<DockWidgetArea, QWidget*> areaWidgets;
|
||||||
areaWidgets.insert(TopDockWidgetArea, createDropIndicatorWidget(TopDockWidgetArea, Mode));
|
areaWidgets.insert(TopDockWidgetArea, d->createDropIndicatorWidget(TopDockWidgetArea, Mode));
|
||||||
areaWidgets.insert(RightDockWidgetArea, createDropIndicatorWidget(RightDockWidgetArea, Mode));
|
areaWidgets.insert(RightDockWidgetArea, d->createDropIndicatorWidget(RightDockWidgetArea, Mode));
|
||||||
areaWidgets.insert(BottomDockWidgetArea, createDropIndicatorWidget(BottomDockWidgetArea, Mode));
|
areaWidgets.insert(BottomDockWidgetArea, d->createDropIndicatorWidget(BottomDockWidgetArea, Mode));
|
||||||
areaWidgets.insert(LeftDockWidgetArea, createDropIndicatorWidget(LeftDockWidgetArea, Mode));
|
areaWidgets.insert(LeftDockWidgetArea, d->createDropIndicatorWidget(LeftDockWidgetArea, Mode));
|
||||||
areaWidgets.insert(CenterDockWidgetArea, createDropIndicatorWidget(CenterDockWidgetArea, Mode));
|
areaWidgets.insert(CenterDockWidgetArea, d->createDropIndicatorWidget(CenterDockWidgetArea, Mode));
|
||||||
|
d->LastDevicePixelRatio = devicePixelRatioF();
|
||||||
|
|
||||||
setAreaWidgets(areaWidgets);
|
setAreaWidgets(areaWidgets);
|
||||||
|
d->UpdateRequired = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockOverlayCross::updateOverlayIcons()
|
||||||
|
{
|
||||||
|
if (windowHandle()->devicePixelRatio() == d->LastDevicePixelRatio)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto Widget : d->DropIndicatorWidgets)
|
||||||
|
{
|
||||||
|
d->updateDropIndicatorIcon(Widget);
|
||||||
|
}
|
||||||
|
d->LastDevicePixelRatio = devicePixelRatioF();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
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 +698,10 @@ DockWidgetArea CDockOverlayCross::cursorLocation() const
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockOverlayCross::showEvent(QShowEvent*)
|
void CDockOverlayCross::showEvent(QShowEvent*)
|
||||||
{
|
{
|
||||||
|
if (d->UpdateRequired)
|
||||||
|
{
|
||||||
|
setupOverlayCross(d->Mode);
|
||||||
|
}
|
||||||
this->updatePosition();
|
this->updatePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,6 +740,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
|
} // namespace ads
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** 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
|
* DockOverlay paints a translucent rectangle over another widget. The geometry
|
||||||
* of the rectangle is based on the mouse location.
|
* of the rectangle is based on the mouse location.
|
||||||
*/
|
*/
|
||||||
class CDockOverlay : public QFrame
|
class ADS_EXPORT CDockOverlay : public QFrame
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
DockOverlayPrivate* d; //< private data class
|
DockOverlayPrivate* d; //< private data class
|
||||||
friend class DockOverlayPrivate;
|
friend struct DockOverlayPrivate;
|
||||||
friend class DockOverlayCross;
|
friend class DockOverlayCross;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
|
|
||||||
enum eMode
|
enum eMode
|
||||||
{
|
{
|
||||||
ModeDockAreaOverlay,
|
ModeDockAreaOverlay,
|
||||||
@@ -100,6 +102,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
QRect dropOverlayRect() const;
|
QRect dropOverlayRect() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle polish events
|
||||||
|
*/
|
||||||
|
virtual bool event(QEvent *e) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void paintEvent(QPaintEvent *e) override;
|
virtual void paintEvent(QPaintEvent *e) override;
|
||||||
virtual void showEvent(QShowEvent* e) override;
|
virtual void showEvent(QShowEvent* e) override;
|
||||||
@@ -112,18 +119,71 @@ struct DockOverlayCrossPrivate;
|
|||||||
* DockOverlayCross shows a cross with 5 different drop area possibilities.
|
* DockOverlayCross shows a cross with 5 different drop area possibilities.
|
||||||
* I could have handled everything inside DockOverlay, but because of some
|
* I could have handled everything inside DockOverlay, but because of some
|
||||||
* styling issues it's better to have a separate class for the cross.
|
* 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
|
class CDockOverlayCross : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
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:
|
private:
|
||||||
DockOverlayCrossPrivate* d;
|
DockOverlayCrossPrivate* d;
|
||||||
friend class DockOverlayCrossPrivate;
|
friend struct DockOverlayCrossPrivate;
|
||||||
friend class CDockOverlay;
|
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:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates an overlay corss for the given overlay
|
* Creates an overlay cross for the given overlay
|
||||||
*/
|
*/
|
||||||
CDockOverlayCross(CDockOverlay* overlay);
|
CDockOverlayCross(CDockOverlay* overlay);
|
||||||
|
|
||||||
@@ -132,6 +192,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual ~CDockOverlayCross();
|
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.
|
* Returns the dock widget area depending on the current cursor location.
|
||||||
* The function checks, if the mouse cursor is inside of any drop indicator
|
* The function checks, if the mouse cursor is inside of any drop indicator
|
||||||
@@ -144,6 +214,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setupOverlayCross(CDockOverlay::eMode Mode);
|
void setupOverlayCross(CDockOverlay::eMode Mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recreates the overlay icons.
|
||||||
|
*/
|
||||||
|
void updateOverlayIcons();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets and updates the
|
* Resets and updates the
|
||||||
*/
|
*/
|
||||||
@@ -154,6 +229,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
void updatePosition();
|
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:
|
protected:
|
||||||
virtual void showEvent(QShowEvent* e) override;
|
virtual void showEvent(QShowEvent* e) override;
|
||||||
void setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets);
|
void setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets);
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ CDockSplitter::CDockSplitter(QWidget *parent)
|
|||||||
: QSplitter(parent),
|
: QSplitter(parent),
|
||||||
d(new DockSplitterPrivate(this))
|
d(new DockSplitterPrivate(this))
|
||||||
{
|
{
|
||||||
|
setProperty("ads-splitter", true);
|
||||||
|
setChildrenCollapsible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -78,7 +79,7 @@ bool CDockSplitter::hasVisibleContent() const
|
|||||||
// TODO Cache or precalculate this to speed up
|
// TODO Cache or precalculate this to speed up
|
||||||
for (int i = 0; i < count(); ++i)
|
for (int i = 0; i < count(); ++i)
|
||||||
{
|
{
|
||||||
if (widget(i)->isVisibleTo(this))
|
if (!widget(i)->isHidden())
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -31,6 +31,8 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
struct DockSplitterPrivate;
|
struct DockSplitterPrivate;
|
||||||
@@ -38,12 +40,12 @@ struct DockSplitterPrivate;
|
|||||||
/**
|
/**
|
||||||
* Splitter used internally instead of QSplitter
|
* Splitter used internally instead of QSplitter
|
||||||
*/
|
*/
|
||||||
class CDockSplitter : public QSplitter
|
class ADS_EXPORT CDockSplitter : public QSplitter
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
DockSplitterPrivate* d;
|
DockSplitterPrivate* d;
|
||||||
friend class DockSplitterPrivate;
|
friend struct DockSplitterPrivate;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDockSplitter(QWidget *parent = Q_NULLPTR);
|
CDockSplitter(QWidget *parent = Q_NULLPTR);
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
** 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 DockStateSerialization.cpp
|
|
||||||
/// \author Uwe Kindler
|
|
||||||
/// \date 26.02.2017
|
|
||||||
/// \brief Serialization related data, constants and stuff
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
// INCLUDES
|
|
||||||
//============================================================================
|
|
||||||
#include "DockStateSerialization.h"
|
|
||||||
|
|
||||||
@@ -28,26 +28,29 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
// INCLUDES
|
// INCLUDES
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
#include <DockWidgetTab.h>
|
||||||
#include "DockWidget.h"
|
#include "DockWidget.h"
|
||||||
|
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
|
#include <QScrollArea>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QToolBar>
|
||||||
|
#include <QXmlStreamWriter>
|
||||||
|
|
||||||
#include "DockWidgetTitleBar.h"
|
|
||||||
#include "DockContainerWidget.h"
|
#include "DockContainerWidget.h"
|
||||||
#include "DockAreaWidget.h"
|
#include "DockAreaWidget.h"
|
||||||
#include "DockManager.h"
|
#include "DockManager.h"
|
||||||
#include "FloatingDockContainer.h"
|
#include "FloatingDockContainer.h"
|
||||||
#include "DockStateSerialization.h"
|
|
||||||
#include "DockSplitter.h"
|
#include "DockSplitter.h"
|
||||||
#include "ads_globals.h"
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -58,12 +61,19 @@ struct DockWidgetPrivate
|
|||||||
CDockWidget* _this;
|
CDockWidget* _this;
|
||||||
QBoxLayout* Layout;
|
QBoxLayout* Layout;
|
||||||
QWidget* Widget = nullptr;
|
QWidget* Widget = nullptr;
|
||||||
CDockWidgetTitleBar* TitleWidget;
|
CDockWidgetTab* TabWidget;
|
||||||
CDockWidget::DockWidgetFeatures Features = CDockWidget::AllDockWidgetFeatures;
|
CDockWidget::DockWidgetFeatures Features = CDockWidget::AllDockWidgetFeatures;
|
||||||
CDockManager* DockManager = nullptr;
|
CDockManager* DockManager = nullptr;
|
||||||
CDockAreaWidget* DockArea = nullptr;
|
CDockAreaWidget* DockArea = nullptr;
|
||||||
QAction* ToggleViewAction;
|
QAction* ToggleViewAction;
|
||||||
bool Closed = false;
|
bool Closed = false;
|
||||||
|
QScrollArea* ScrollArea = nullptr;
|
||||||
|
QToolBar* ToolBar = nullptr;
|
||||||
|
Qt::ToolButtonStyle ToolBarStyleDocked = Qt::ToolButtonIconOnly;
|
||||||
|
Qt::ToolButtonStyle ToolBarStyleFloating = Qt::ToolButtonTextUnderIcon;
|
||||||
|
QSize ToolBarIconSizeDocked = QSize(16, 16);
|
||||||
|
QSize ToolBarIconSizeFloating = QSize(24, 24);
|
||||||
|
bool IsFloatingTopLevel = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data constructor
|
* Private data constructor
|
||||||
@@ -81,20 +91,21 @@ struct DockWidgetPrivate
|
|||||||
void hideDockWidget();
|
void hideDockWidget();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides a parent splitter if all dock widgets in the splitter are closed
|
* Hides a dock area if all dock widgets in the area are closed.
|
||||||
|
* This function updates the current selected tab and hides the parent
|
||||||
|
* dock area if it is empty
|
||||||
*/
|
*/
|
||||||
void hideEmptyParentSplitters();
|
void updateParentDockArea();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides a dock area if all dock widgets in the area are closed
|
* Setup the top tool bar
|
||||||
*/
|
*/
|
||||||
void hideEmptyParentDockArea();
|
void setupToolBar();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides a floating widget if all dock areas are empty - that means,
|
* Setup the main scroll area
|
||||||
* if all dock widgets in all dock areas are closed
|
|
||||||
*/
|
*/
|
||||||
void hideEmptyFloatingWidget();
|
void setupScrollArea();
|
||||||
};
|
};
|
||||||
// struct DockWidgetPrivate
|
// struct DockWidgetPrivate
|
||||||
|
|
||||||
@@ -117,9 +128,10 @@ void DockWidgetPrivate::showDockWidget()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DockArea->show();
|
DockArea->toggleView(true);
|
||||||
DockArea->setCurrentIndex(DockArea->tabIndex(_this));
|
DockArea->setCurrentDockWidget(_this);
|
||||||
QSplitter* Splitter = internal::findParent<QSplitter*>(_this);
|
TabWidget->show();
|
||||||
|
QSplitter* Splitter = internal::findParent<QSplitter*>(DockArea);
|
||||||
while (Splitter && !Splitter->isVisible())
|
while (Splitter && !Splitter->isVisible())
|
||||||
{
|
{
|
||||||
Splitter->show();
|
Splitter->show();
|
||||||
@@ -140,63 +152,52 @@ void DockWidgetPrivate::showDockWidget()
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void DockWidgetPrivate::hideDockWidget()
|
void DockWidgetPrivate::hideDockWidget()
|
||||||
{
|
{
|
||||||
TitleWidget->hide();
|
TabWidget->hide();
|
||||||
hideEmptyParentDockArea();
|
updateParentDockArea();
|
||||||
hideEmptyParentSplitters();
|
|
||||||
hideEmptyFloatingWidget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void DockWidgetPrivate::hideEmptyParentSplitters()
|
void DockWidgetPrivate::updateParentDockArea()
|
||||||
{
|
{
|
||||||
auto Splitter = internal::findParent<CDockSplitter*>(_this);
|
if (!DockArea)
|
||||||
while (Splitter && Splitter->isVisible())
|
|
||||||
{
|
{
|
||||||
if (!Splitter->hasVisibleContent())
|
return;
|
||||||
{
|
|
||||||
Splitter->hide();
|
|
||||||
}
|
|
||||||
Splitter = internal::findParent<CDockSplitter*>(Splitter);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
auto NextDockWidget = DockArea->nextOpenDockWidget(_this);
|
||||||
//============================================================================
|
if (NextDockWidget)
|
||||||
void DockWidgetPrivate::hideEmptyParentDockArea()
|
|
||||||
{
|
|
||||||
auto OpenDockWidgets = DockArea->openedDockWidgets();
|
|
||||||
if (OpenDockWidgets.count() > 1)
|
|
||||||
{
|
{
|
||||||
CDockWidget* NextDockWidget;
|
|
||||||
if (OpenDockWidgets.last() == _this)
|
|
||||||
{
|
|
||||||
NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int NextIndex = OpenDockWidgets.indexOf(_this) + 1;
|
|
||||||
NextDockWidget = OpenDockWidgets[NextIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
DockArea->setCurrentDockWidget(NextDockWidget);
|
DockArea->setCurrentDockWidget(NextDockWidget);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DockArea->hide();
|
DockArea->hideAreaWithNoVisibleContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void DockWidgetPrivate::hideEmptyFloatingWidget()
|
void DockWidgetPrivate::setupToolBar()
|
||||||
{
|
{
|
||||||
CDockContainerWidget* Container = _this->dockContainer();
|
ToolBar = new QToolBar(_this);
|
||||||
if (Container->isFloating() && Container->openedDockAreas().isEmpty())
|
ToolBar->setObjectName("dockWidgetToolBar");
|
||||||
{
|
Layout->insertWidget(0, ToolBar);
|
||||||
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(Container);
|
ToolBar->setIconSize(QSize(16, 16));
|
||||||
FloatingWidget->hide();
|
ToolBar->toggleViewAction()->setEnabled(false);
|
||||||
}
|
ToolBar->toggleViewAction()->setVisible(false);
|
||||||
|
_this->connect(_this, SIGNAL(topLevelChanged(bool)), SLOT(setToolbarFloatingStyle(bool)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetPrivate::setupScrollArea()
|
||||||
|
{
|
||||||
|
ScrollArea = new QScrollArea(_this);
|
||||||
|
ScrollArea->setObjectName("dockWidgetScrollArea");
|
||||||
|
ScrollArea->setWidgetResizable(true);
|
||||||
|
Layout->addWidget(ScrollArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -210,12 +211,14 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
|
|||||||
d->Layout->setSpacing(0);
|
d->Layout->setSpacing(0);
|
||||||
setLayout(d->Layout);
|
setLayout(d->Layout);
|
||||||
setWindowTitle(title);
|
setWindowTitle(title);
|
||||||
|
setObjectName(title);
|
||||||
|
|
||||||
d->TitleWidget = new CDockWidgetTitleBar(this);
|
d->TabWidget = new CDockWidgetTab(this);
|
||||||
d->ToggleViewAction = new QAction(title);
|
d->ToggleViewAction = new QAction(title);
|
||||||
d->ToggleViewAction->setCheckable(true);
|
d->ToggleViewAction->setCheckable(true);
|
||||||
connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this,
|
connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this,
|
||||||
SLOT(toggleView(bool)));
|
SLOT(toggleView(bool)));
|
||||||
|
setToolbarFloatingStyle(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@@ -237,11 +240,13 @@ void CDockWidget::setToggleViewActionChecked(bool Checked)
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockWidget::setWidget(QWidget* widget)
|
void CDockWidget::setWidget(QWidget* widget, eInsertMode InsertMode)
|
||||||
{
|
{
|
||||||
if (d->Widget)
|
QScrollArea* ScrollAreaWidget = qobject_cast<QScrollArea*>(widget);
|
||||||
|
if (ScrollAreaWidget || ForceNoScrollArea != InsertMode)
|
||||||
{
|
{
|
||||||
d->Layout->replaceWidget(d->Widget, widget);
|
d->setupScrollArea();
|
||||||
|
d->ScrollArea->setWidget(widget);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -249,6 +254,7 @@ void CDockWidget::setWidget(QWidget* widget)
|
|||||||
}
|
}
|
||||||
|
|
||||||
d->Widget = widget;
|
d->Widget = widget;
|
||||||
|
d->Widget->setProperty("dockWidgetContent", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -260,9 +266,9 @@ QWidget* CDockWidget::widget() const
|
|||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockWidgetTitleBar* CDockWidget::titleBar() const
|
CDockWidgetTab* CDockWidget::tabWidget() const
|
||||||
{
|
{
|
||||||
return d->TitleWidget;
|
return d->TabWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -273,6 +279,13 @@ void CDockWidget::setFeatures(DockWidgetFeatures features)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setFeature(DockWidgetFeature flag, bool on)
|
||||||
|
{
|
||||||
|
d->Features.setFlag(flag, on);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockWidget::DockWidgetFeatures CDockWidget::features() const
|
CDockWidget::DockWidgetFeatures CDockWidget::features() const
|
||||||
{
|
{
|
||||||
@@ -297,21 +310,51 @@ void CDockWidget::setDockManager(CDockManager* DockManager)
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
CDockContainerWidget* CDockWidget::dockContainer() const
|
CDockContainerWidget* CDockWidget::dockContainer() const
|
||||||
{
|
{
|
||||||
return internal::findParent<CDockContainerWidget*>(this);
|
if (d->DockArea)
|
||||||
|
{
|
||||||
|
return d->DockArea->dockContainer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CDockAreaWidget* CDockWidget::dockAreaWidget() const
|
CDockAreaWidget* CDockWidget::dockAreaWidget() const
|
||||||
{
|
{
|
||||||
return internal::findParent<CDockAreaWidget*>(this);
|
return d->DockArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
bool CDockWidget::isFloating() const
|
bool CDockWidget::isFloating() const
|
||||||
{
|
{
|
||||||
return dockContainer() ? dockContainer()->isFloating() : false;
|
if (!isInFloatingContainer())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dockContainer()->topLevelDockWidget() == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidget::isInFloatingContainer() const
|
||||||
|
{
|
||||||
|
auto Container = dockContainer();
|
||||||
|
if (!Container)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Container->isFloating())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -329,9 +372,53 @@ 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->TabWidget->icon());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockWidget::toggleView(bool Open)
|
void CDockWidget::toggleView(bool Open)
|
||||||
{
|
{
|
||||||
|
// If the toggle view action mode is ActionModeShow, then Open is always
|
||||||
|
// true if the sender is the toggle view action
|
||||||
|
QAction* Sender = qobject_cast<QAction*>(sender());
|
||||||
|
if (Sender == d->ToggleViewAction && !d->ToggleViewAction->isCheckable())
|
||||||
|
{
|
||||||
|
Open = true;
|
||||||
|
}
|
||||||
|
// If the dock widget state is different, then we really need to toggle
|
||||||
|
// the state. If we are in the right state, then we simply make this
|
||||||
|
// dock widget the current dock widget
|
||||||
|
if (d->Closed != !Open)
|
||||||
|
{
|
||||||
|
toggleViewInternal(Open);
|
||||||
|
}
|
||||||
|
else if (Open && d->DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea->setCurrentDockWidget(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::toggleViewInternal(bool Open)
|
||||||
|
{
|
||||||
|
CDockContainerWidget* DockContainer = dockContainer();
|
||||||
|
CDockWidget* TopLevelDockWidgetBefore = DockContainer
|
||||||
|
? DockContainer->topLevelDockWidget() : nullptr;
|
||||||
|
|
||||||
if (Open)
|
if (Open)
|
||||||
{
|
{
|
||||||
d->showDockWidget();
|
d->showDockWidget();
|
||||||
@@ -344,6 +431,29 @@ void CDockWidget::toggleView(bool Open)
|
|||||||
d->ToggleViewAction->blockSignals(true);
|
d->ToggleViewAction->blockSignals(true);
|
||||||
d->ToggleViewAction->setChecked(Open);
|
d->ToggleViewAction->setChecked(Open);
|
||||||
d->ToggleViewAction->blockSignals(false);
|
d->ToggleViewAction->blockSignals(false);
|
||||||
|
if (d->DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea->toggleDockWidgetView(this, Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Open && TopLevelDockWidgetBefore)
|
||||||
|
{
|
||||||
|
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetBefore, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we need to call the dockContainer() function again, because if
|
||||||
|
// this dock widget was unassigned before the call to showDockWidget() then
|
||||||
|
// it has a dock container now
|
||||||
|
DockContainer = dockContainer();
|
||||||
|
CDockWidget* TopLevelDockWidgetAfter = DockContainer
|
||||||
|
? DockContainer->topLevelDockWidget() : nullptr;
|
||||||
|
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetAfter, true);
|
||||||
|
CFloatingDockContainer* FloatingContainer = DockContainer->floatingWidget();
|
||||||
|
if (FloatingContainer)
|
||||||
|
{
|
||||||
|
FloatingContainer->updateWindowTitle();
|
||||||
|
}
|
||||||
|
|
||||||
if (!Open)
|
if (!Open)
|
||||||
{
|
{
|
||||||
emit closed();
|
emit closed();
|
||||||
@@ -356,25 +466,28 @@ void CDockWidget::toggleView(bool Open)
|
|||||||
void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
|
void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
|
||||||
{
|
{
|
||||||
d->DockArea = DockArea;
|
d->DockArea = DockArea;
|
||||||
d->ToggleViewAction->setChecked(DockArea != nullptr);
|
d->ToggleViewAction->setChecked(DockArea != nullptr && !this->isClosed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockWidget::saveState(QDataStream& stream) const
|
void CDockWidget::saveState(QXmlStreamWriter& s) const
|
||||||
{
|
{
|
||||||
stream << internal::DockWidgetMarker;
|
s.writeStartElement("Widget");
|
||||||
qDebug() << "CDockWidget::saveState " << objectName() << " closed " << d->Closed;
|
s.writeAttribute("Name", objectName());
|
||||||
stream << objectName() << d->Closed;
|
s.writeAttribute("Closed", QString::number(d->Closed ? 1 : 0));
|
||||||
|
s.writeEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CDockWidget::flagAsUnassigned()
|
void CDockWidget::flagAsUnassigned()
|
||||||
{
|
{
|
||||||
|
d->Closed = true;
|
||||||
setParent(d->DockManager);
|
setParent(d->DockManager);
|
||||||
|
setVisible(false);
|
||||||
setDockArea(nullptr);
|
setDockArea(nullptr);
|
||||||
titleBar()->setParent(this);
|
tabWidget()->setParent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -389,6 +502,174 @@ bool CDockWidget::event(QEvent *e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setIcon(const QIcon& Icon)
|
||||||
|
{
|
||||||
|
d->TabWidget->setIcon(Icon);
|
||||||
|
if (!d->ToggleViewAction->isCheckable())
|
||||||
|
{
|
||||||
|
d->ToggleViewAction->setIcon(Icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QIcon CDockWidget::icon() const
|
||||||
|
{
|
||||||
|
return d->TabWidget->icon();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QToolBar* CDockWidget::toolBar() const
|
||||||
|
{
|
||||||
|
return d->ToolBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QToolBar* CDockWidget::createDefaultToolBar()
|
||||||
|
{
|
||||||
|
if (!d->ToolBar)
|
||||||
|
{
|
||||||
|
d->setupToolBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
return d->ToolBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolBar(QToolBar* ToolBar)
|
||||||
|
{
|
||||||
|
if (d->ToolBar)
|
||||||
|
{
|
||||||
|
delete d->ToolBar;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->ToolBar = ToolBar;
|
||||||
|
d->Layout->insertWidget(0, d->ToolBar);
|
||||||
|
this->connect(this, SIGNAL(topLevelChanged(bool)), SLOT(setToolbarFloatingStyle(bool)));
|
||||||
|
setToolbarFloatingStyle(isFloating());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolBarStyle(Qt::ToolButtonStyle Style, eState State)
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
d->ToolBarStyleFloating = Style;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->ToolBarStyleDocked = Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolbarFloatingStyle(isFloating());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
Qt::ToolButtonStyle CDockWidget::toolBarStyle(eState State) const
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
return d->ToolBarStyleFloating;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return d->ToolBarStyleDocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolBarIconSize(const QSize& IconSize, eState State)
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
d->ToolBarIconSizeFloating = IconSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->ToolBarIconSizeDocked = IconSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
setToolbarFloatingStyle(isFloating());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CDockWidget::toolBarIconSize(eState State) const
|
||||||
|
{
|
||||||
|
if (StateFloating == State)
|
||||||
|
{
|
||||||
|
return d->ToolBarIconSizeFloating;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return d->ToolBarIconSizeDocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setToolbarFloatingStyle(bool Floating)
|
||||||
|
{
|
||||||
|
if (!d->ToolBar)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto IconSize = Floating ? d->ToolBarIconSizeFloating : d->ToolBarIconSizeDocked;
|
||||||
|
if (IconSize != d->ToolBar->iconSize())
|
||||||
|
{
|
||||||
|
d->ToolBar->setIconSize(IconSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ButtonStyle = Floating ? d->ToolBarStyleFloating : d->ToolBarStyleDocked;
|
||||||
|
if (ButtonStyle != d->ToolBar->toolButtonStyle())
|
||||||
|
{
|
||||||
|
d->ToolBar->setToolButtonStyle(ButtonStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::emitTopLevelEventForWidget(CDockWidget* TopLevelDockWidget, bool Floating)
|
||||||
|
{
|
||||||
|
if (TopLevelDockWidget)
|
||||||
|
{
|
||||||
|
TopLevelDockWidget->dockAreaWidget()->updateTitleBarVisibility();
|
||||||
|
TopLevelDockWidget->emitTopLevelChanged(Floating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::emitTopLevelChanged(bool Floating)
|
||||||
|
{
|
||||||
|
if (Floating != d->IsFloatingTopLevel)
|
||||||
|
{
|
||||||
|
d->IsFloatingTopLevel = Floating;
|
||||||
|
emit topLevelChanged(d->IsFloatingTopLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidget::setClosedState(bool Closed)
|
||||||
|
{
|
||||||
|
d->Closed = Closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CDockWidget::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
return QSize(60, 40);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
|
|||||||
238
src/DockWidget.h
@@ -3,17 +3,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -32,10 +32,15 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class QToolBar;
|
||||||
|
class QXmlStreamWriter;
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
struct DockWidgetPrivate;
|
struct DockWidgetPrivate;
|
||||||
class CDockWidgetTitleBar;
|
class CDockWidgetTab;
|
||||||
class CDockManager;
|
class CDockManager;
|
||||||
class CDockContainerWidget;
|
class CDockContainerWidget;
|
||||||
class CDockAreaWidget;
|
class CDockAreaWidget;
|
||||||
@@ -45,19 +50,29 @@ struct DockContainerWidgetPrivate;
|
|||||||
* The QDockWidget class provides a widget that can be docked inside a
|
* The QDockWidget class provides a widget that can be docked inside a
|
||||||
* CDockManager or floated as a top-level window on the desktop.
|
* CDockManager or floated as a top-level window on the desktop.
|
||||||
*/
|
*/
|
||||||
class CDockWidget : public QFrame
|
class ADS_EXPORT CDockWidget : public QFrame
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
DockWidgetPrivate* d; ///< private data (pimpl)
|
DockWidgetPrivate* d; ///< private data (pimpl)
|
||||||
friend class DockWidgetPrivate;
|
friend struct DockWidgetPrivate;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
/**
|
||||||
|
* Adjusts the toolbar icon sizes according to the floating state
|
||||||
|
*/
|
||||||
|
void setToolbarFloatingStyle(bool topLevel);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class CDockContainerWidget;
|
friend class CDockContainerWidget;
|
||||||
friend class CDockAreaWidget;
|
friend class CDockAreaWidget;
|
||||||
friend class CFloatingDockContainer;
|
friend class CFloatingDockContainer;
|
||||||
friend class CDockManager;
|
friend class CDockManager;
|
||||||
friend class DockContainerWidgetPrivate;
|
friend struct DockManagerPrivate;
|
||||||
|
friend struct DockContainerWidgetPrivate;
|
||||||
|
friend class CDockAreaTabBar;
|
||||||
|
friend class CDockWidgetTab;
|
||||||
|
friend struct DockWidgetTabPrivate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the dock manager that manages this dock widget
|
* Assigns the dock manager that manages this dock widget
|
||||||
@@ -81,7 +96,7 @@ protected:
|
|||||||
/**
|
/**
|
||||||
* Saves the state into the given stream
|
* 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
|
* This is a helper function for the dock manager to flag this widget
|
||||||
@@ -94,6 +109,31 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void flagAsUnassigned();
|
void flagAsUnassigned();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function to emit a topLevelChanged() signal and to update
|
||||||
|
* the dock area tool bar visibility
|
||||||
|
*/
|
||||||
|
static void emitTopLevelEventForWidget(CDockWidget* TopLevelDockWidget, bool Floating);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this function to emit a top level changed event.
|
||||||
|
* Do never use emit topLevelChanged(). Always use this function because
|
||||||
|
* it only emits a signal if the floating state has really changed
|
||||||
|
*/
|
||||||
|
void emitTopLevelChanged(bool Floating);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function for modifying the closed state when restoring
|
||||||
|
* a saved docking state
|
||||||
|
*/
|
||||||
|
void setClosedState(bool Closed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal toggle view function that does not check if the widget
|
||||||
|
* already is in the given state
|
||||||
|
*/
|
||||||
|
void toggleViewInternal(bool Open);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DockWidgetFeature
|
enum DockWidgetFeature
|
||||||
{
|
{
|
||||||
@@ -105,7 +145,6 @@ public:
|
|||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
|
Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
|
||||||
|
|
||||||
|
|
||||||
enum eState
|
enum eState
|
||||||
{
|
{
|
||||||
StateHidden,
|
StateHidden,
|
||||||
@@ -114,7 +153,56 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Constructor
|
* Sets the widget for the dock widget to widget.
|
||||||
|
* The InsertMode defines how the widget is inserted into the dock widget.
|
||||||
|
* The content of a dock widget should be resizable do a very small size to
|
||||||
|
* prevent the dock widget from blocking the resizing. To ensure, that a
|
||||||
|
* dock widget can be resized very well, it is better to insert the content+
|
||||||
|
* widget into a scroll area or to provide a widget that is already a scroll
|
||||||
|
* area or that contains a scroll area.
|
||||||
|
* If the InsertMode is AutoScrollArea, the DockWidget tries to automatically
|
||||||
|
* detect how to insert the given widget. If the widget is derived from
|
||||||
|
* QScrollArea (i.e. an QAbstractItemView), then the widget is inserted
|
||||||
|
* directly. If the given widget is not a scroll area, the widget will be
|
||||||
|
* inserted into a scroll area.
|
||||||
|
* To force insertion into a scroll area, you can also provide the InsertMode
|
||||||
|
* ForceScrollArea. To prevent insertion into a scroll area, you can
|
||||||
|
* provide the InsertMode ForceNoScrollArea
|
||||||
|
*/
|
||||||
|
enum eInsertMode
|
||||||
|
{
|
||||||
|
AutoScrollArea,
|
||||||
|
ForceScrollArea,
|
||||||
|
ForceNoScrollArea
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* Use the layoutFlags to configure the layout of the dock widget.
|
||||||
*/
|
*/
|
||||||
CDockWidget(const QString &title, QWidget* parent = 0);
|
CDockWidget(const QString &title, QWidget* parent = 0);
|
||||||
|
|
||||||
@@ -124,9 +212,28 @@ public:
|
|||||||
virtual ~CDockWidget();
|
virtual ~CDockWidget();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the widget for the dock widget to widget.
|
* We return a fixed minimum size hint for all dock widgets
|
||||||
*/
|
*/
|
||||||
void setWidget(QWidget* widget);
|
virtual QSize minimumSizeHint() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the widget for the dock widget to widget.
|
||||||
|
* The InsertMode defines how the widget is inserted into the dock widget.
|
||||||
|
* The content of a dock widget should be resizable do a very small size to
|
||||||
|
* prevent the dock widget from blocking the resizing. To ensure, that a
|
||||||
|
* dock widget can be resized very well, it is better to insert the content+
|
||||||
|
* widget into a scroll area or to provide a widget that is already a scroll
|
||||||
|
* area or that contains a scroll area.
|
||||||
|
* If the InsertMode is AutoScrollArea, the DockWidget tries to automatically
|
||||||
|
* detect how to insert the given widget. If the widget is derived from
|
||||||
|
* QScrollArea (i.e. an QAbstractItemView), then the widget is inserted
|
||||||
|
* directly. If the given widget is not a scroll area, the widget will be
|
||||||
|
* inserted into a scroll area.
|
||||||
|
* To force insertion into a scroll area, you can also provide the InsertMode
|
||||||
|
* ForceScrollArea. To prevent insertion into a scroll area, you can
|
||||||
|
* provide the InsertMode ForceNoScrollArea
|
||||||
|
*/
|
||||||
|
void setWidget(QWidget* widget, eInsertMode InsertMode = AutoScrollArea);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the widget for the dock widget. This function returns zero if
|
* Returns the widget for the dock widget. This function returns zero if
|
||||||
@@ -137,13 +244,19 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Returns the title bar widget of this dock widget
|
* Returns the title bar widget of this dock widget
|
||||||
*/
|
*/
|
||||||
CDockWidgetTitleBar* titleBar() const;
|
CDockWidgetTab* tabWidget() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets, whether the dock widget is movable, closable, and floatable.
|
* Sets, whether the dock widget is movable, closable, and floatable.
|
||||||
*/
|
*/
|
||||||
void setFeatures(DockWidgetFeatures features);
|
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
|
* This property holds whether the dock widget is movable, closable, and
|
||||||
* floatable.
|
* floatable.
|
||||||
@@ -160,7 +273,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the dock container widget this dock area widget belongs to or 0
|
* Returns the dock container widget this dock area widget belongs to or 0
|
||||||
* if this dock widget has nt been docked yet
|
* if this dock widget has not been docked yet
|
||||||
*/
|
*/
|
||||||
CDockContainerWidget* dockContainer() const;
|
CDockContainerWidget* dockContainer() const;
|
||||||
|
|
||||||
@@ -172,9 +285,19 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This property holds whether the dock widget is floating.
|
* This property holds whether the dock widget is floating.
|
||||||
|
* A dock widget is only floating, if it is the one and only widget inside
|
||||||
|
* of a floating container. If there are more than one dock widget in a
|
||||||
|
* floating container, the all dock widgets are docked and not floating.
|
||||||
*/
|
*/
|
||||||
bool isFloating() const;
|
bool isFloating() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true, if this dock widget is in a floating.
|
||||||
|
* The function returns true, if the dock widget is floating and it also
|
||||||
|
* returns true if it is docked inside of a floating container.
|
||||||
|
*/
|
||||||
|
bool isInFloatingContainer() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true, if this dock widget is closed.
|
* Returns true, if this dock widget is closed.
|
||||||
*/
|
*/
|
||||||
@@ -187,7 +310,83 @@ public:
|
|||||||
QAction* toggleViewAction() const;
|
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 the icon that has been assigned to the dock widget
|
||||||
|
*/
|
||||||
|
QIcon icon() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the WithToolBar layout flag is enabled, then this function returns
|
||||||
|
* the dock widget toolbar. If the flag is disabled, the function returns
|
||||||
|
* a nullptr.
|
||||||
|
* This function returns the dock widget top tool bar.
|
||||||
|
* If no toolbar is assigned, this function returns nullptr. To get a vaild
|
||||||
|
* toolbar you either need to create a default empty toolbar via
|
||||||
|
* createDefaultToolBar() function or you need to assign you custom
|
||||||
|
* toolbar via setToolBar().
|
||||||
|
*/
|
||||||
|
QToolBar* toolBar() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you would like to use the default top tool bar, then call this
|
||||||
|
* function to create the default tool bar.
|
||||||
|
* After this function the toolBar() function will return a valid toolBar()
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
QToolBar* createDefaultToolBar();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign a new tool bar that is shown above the content widget.
|
||||||
|
* The dock widget will become the owner of the tool bar and deletes it
|
||||||
|
* on destruction
|
||||||
|
*/
|
||||||
|
void setToolBar(QToolBar* ToolBar);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function sets the tool button style for the given dock widget state.
|
||||||
|
* It is possible to switch the tool button style depending on the state.
|
||||||
|
* If a dock widget is floating, then here are more space and it is
|
||||||
|
* possible to select a style that requires more space like
|
||||||
|
* Qt::ToolButtonTextUnderIcon. For the docked state Qt::ToolButtonIconOnly
|
||||||
|
* might be better.
|
||||||
|
*/
|
||||||
|
void setToolBarStyle(Qt::ToolButtonStyle Style, eState State);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tool button style for the given docking state.
|
||||||
|
* \see setToolBarStyle()
|
||||||
|
*/
|
||||||
|
Qt::ToolButtonStyle toolBarStyle(eState State) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function sets the tool button icon size for the given state.
|
||||||
|
* If a dock widget is floating, there is more space an increasing the
|
||||||
|
* icon size is possible. For docked widgets, small icon sizes, eg. 16 x 16
|
||||||
|
* might be better.
|
||||||
|
*/
|
||||||
|
void setToolBarIconSize(const QSize& IconSize, eState State);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the icon size for a given docking state.
|
||||||
|
* \see setToolBarIconSize()
|
||||||
|
*/
|
||||||
|
QSize toolBarIconSize(eState State) const;
|
||||||
|
|
||||||
|
|
||||||
|
public: // reimplements QFrame -----------------------------------------------
|
||||||
|
/**
|
||||||
|
* Emits titleChanged signal if title change event occurs
|
||||||
*/
|
*/
|
||||||
virtual bool event(QEvent *e) override;
|
virtual bool event(QEvent *e) override;
|
||||||
|
|
||||||
@@ -196,7 +395,7 @@ public slots:
|
|||||||
* This property controls whether the dock widget is open or closed.
|
* This property controls whether the dock widget is open or closed.
|
||||||
* The toogleViewAction triggers this slot
|
* The toogleViewAction triggers this slot
|
||||||
*/
|
*/
|
||||||
void toggleView(bool Open);
|
void toggleView(bool Open = true);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
@@ -214,6 +413,13 @@ signals:
|
|||||||
* changed
|
* changed
|
||||||
*/
|
*/
|
||||||
void titleChanged(const QString& Title);
|
void titleChanged(const QString& Title);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted when the floating property changes.
|
||||||
|
* The topLevel parameter is true if the dock widget is now floating;
|
||||||
|
* otherwise it is false.
|
||||||
|
*/
|
||||||
|
void topLevelChanged(bool topLevel);
|
||||||
}; // class DockWidget
|
}; // class DockWidget
|
||||||
}
|
}
|
||||||
// namespace ads
|
// namespace ads
|
||||||
|
|||||||
506
src/DockWidgetTab.cpp
Normal file
@@ -0,0 +1,506 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** 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 DockWidgetTab.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 27.02.2017
|
||||||
|
/// \brief Implementation of CDockWidgetTab class
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <ElidingLabel.h>
|
||||||
|
#include "DockWidgetTab.h"
|
||||||
|
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
#include "DockWidget.h"
|
||||||
|
#include "DockAreaWidget.h"
|
||||||
|
#include "FloatingDockContainer.h"
|
||||||
|
#include "DockOverlay.h"
|
||||||
|
#include "DockManager.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The different dragging states
|
||||||
|
*/
|
||||||
|
enum eDragState
|
||||||
|
{
|
||||||
|
DraggingInactive, //!< DraggingInactive
|
||||||
|
DraggingMousePressed, //!< DraggingMousePressed
|
||||||
|
DraggingTab, //!< DraggingTab
|
||||||
|
DraggingFloatingWidget//!< DraggingFloatingWidget
|
||||||
|
};
|
||||||
|
|
||||||
|
using tTabLabel = CElidingLabel;
|
||||||
|
using tCloseButton = QPushButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data class of CDockWidgetTab class (pimpl)
|
||||||
|
*/
|
||||||
|
struct DockWidgetTabPrivate
|
||||||
|
{
|
||||||
|
CDockWidgetTab* _this;
|
||||||
|
CDockWidget* DockWidget;
|
||||||
|
QLabel* IconLabel = nullptr;
|
||||||
|
tTabLabel* TitleLabel;
|
||||||
|
QPoint DragStartMousePosition;
|
||||||
|
bool IsActiveTab = false;
|
||||||
|
CDockAreaWidget* DockArea = nullptr;
|
||||||
|
eDragState DragState = DraggingInactive;
|
||||||
|
CFloatingDockContainer* FloatingWidget = nullptr;
|
||||||
|
QIcon Icon;
|
||||||
|
tCloseButton* CloseButton = nullptr;
|
||||||
|
QSpacerItem* IconTextSpacer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data constructor
|
||||||
|
*/
|
||||||
|
DockWidgetTabPrivate(CDockWidgetTab* _public);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the complete layout including all controls
|
||||||
|
*/
|
||||||
|
void createLayout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the tab depending on the position in the given mouse event
|
||||||
|
*/
|
||||||
|
void moveTab(QMouseEvent* ev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test function for current drag state
|
||||||
|
*/
|
||||||
|
bool isDraggingState(eDragState dragState)
|
||||||
|
{
|
||||||
|
return this->DragState == dragState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given global point is inside the title area geometry
|
||||||
|
* rectangle.
|
||||||
|
* The position is given as global position.
|
||||||
|
*/
|
||||||
|
bool titleAreaGeometryContains(const QPoint& GlobalPos) const
|
||||||
|
{
|
||||||
|
return DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(GlobalPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts floating of the dock widget that belongs to this title bar
|
||||||
|
* Returns true, if floating has been started and false if floating
|
||||||
|
* is not possible for any reason
|
||||||
|
*/
|
||||||
|
bool startFloating();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given config flag is set
|
||||||
|
*/
|
||||||
|
bool testConfigFlag(CDockManager::eConfigFlag Flag) const
|
||||||
|
{
|
||||||
|
return DockArea->dockManager()->configFlags().testFlag(Flag);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// struct DockWidgetTabPrivate
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
DockWidgetTabPrivate::DockWidgetTabPrivate(CDockWidgetTab* _public) :
|
||||||
|
_this(_public)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetTabPrivate::createLayout()
|
||||||
|
{
|
||||||
|
TitleLabel = new tTabLabel();
|
||||||
|
TitleLabel->setElideMode(Qt::ElideRight);
|
||||||
|
TitleLabel->setText(DockWidget->windowTitle());
|
||||||
|
TitleLabel->setObjectName("dockWidgetTabLabel");
|
||||||
|
TitleLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
CloseButton = new tCloseButton();
|
||||||
|
CloseButton->setObjectName("tabCloseButton");
|
||||||
|
// The standard icons do does not look good on high DPI screens
|
||||||
|
QIcon CloseIcon = _this->style()->standardIcon(QStyle::SP_TitleBarCloseButton);
|
||||||
|
QPixmap normalPixmap = _this->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, CloseButton);
|
||||||
|
QPixmap disabledPixmap = internal::createTransparentPixmap(normalPixmap, 0.25);
|
||||||
|
CloseIcon.addPixmap(disabledPixmap, QIcon::Disabled);
|
||||||
|
CloseButton->setIcon(CloseIcon);
|
||||||
|
CloseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
CloseButton->setVisible(false);
|
||||||
|
CloseButton->setToolTip(QObject::tr("Close Tab"));
|
||||||
|
_this->connect(CloseButton, SIGNAL(clicked()), SIGNAL(closeRequested()));
|
||||||
|
|
||||||
|
QFontMetrics fm(TitleLabel->font());
|
||||||
|
int Spacing = qRound(fm.height() / 4.0);
|
||||||
|
|
||||||
|
// Fill the layout
|
||||||
|
QBoxLayout* Layout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
|
Layout->setContentsMargins(2 * Spacing,0,0,0);
|
||||||
|
Layout->setSpacing(0);
|
||||||
|
_this->setLayout(Layout);
|
||||||
|
Layout->addWidget(TitleLabel, 1);
|
||||||
|
Layout->addSpacing(Spacing);
|
||||||
|
Layout->addWidget(CloseButton);
|
||||||
|
Layout->addSpacing(qRound(Spacing * 4.0 / 3.0));
|
||||||
|
Layout->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
TitleLabel->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void DockWidgetTabPrivate::moveTab(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
int left, top, right, bottom;
|
||||||
|
_this->getContentsMargins(&left, &top, &right, &bottom);
|
||||||
|
QPoint moveToPos = _this->mapToParent(ev->pos()) - DragStartMousePosition;
|
||||||
|
moveToPos.setY(0);
|
||||||
|
_this->move(moveToPos);
|
||||||
|
_this->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool DockWidgetTabPrivate::startFloating()
|
||||||
|
{
|
||||||
|
auto dockContainer = DockWidget->dockContainer();
|
||||||
|
qDebug() << "isFloating " << dockContainer->isFloating();
|
||||||
|
qDebug() << "areaCount " << dockContainer->dockAreaCount();
|
||||||
|
qDebug() << "widgetCount " << DockWidget->dockAreaWidget()->dockWidgetsCount();
|
||||||
|
// if this is the last dock widget inside of this floating widget,
|
||||||
|
// then it does not make any sense, to make it floating because
|
||||||
|
// it is already floating
|
||||||
|
if (dockContainer->isFloating()
|
||||||
|
&& (dockContainer->visibleDockAreaCount() == 1)
|
||||||
|
&& (DockWidget->dockAreaWidget()->dockWidgetsCount() == 1))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "startFloating";
|
||||||
|
DragState = DraggingFloatingWidget;
|
||||||
|
QSize Size = DockArea->size();
|
||||||
|
CFloatingDockContainer* FloatingWidget = nullptr;
|
||||||
|
if (DockArea->dockWidgetsCount() > 1)
|
||||||
|
{
|
||||||
|
// If section widget has multiple tabs, we take only one tab
|
||||||
|
FloatingWidget = new CFloatingDockContainer(DockWidget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If section widget has only one content widget, we can move the complete
|
||||||
|
// dock area into floating widget
|
||||||
|
FloatingWidget = new CFloatingDockContainer(DockArea);
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingWidget->startFloating(DragStartMousePosition, Size);
|
||||||
|
auto Overlay = DockWidget->dockManager()->containerOverlay();
|
||||||
|
Overlay->setAllowedAreas(OuterDockAreas);
|
||||||
|
this->FloatingWidget = FloatingWidget;
|
||||||
|
DockWidget->emitTopLevelChanged(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) :
|
||||||
|
QFrame(parent),
|
||||||
|
d(new DockWidgetTabPrivate(this))
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_NoMousePropagation, true);
|
||||||
|
d->DockWidget = DockWidget;
|
||||||
|
d->createLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidgetTab::~CDockWidgetTab()
|
||||||
|
{
|
||||||
|
qDebug() << "~CDockWidgetTab()";
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::mousePressEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (ev->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
d->DragStartMousePosition = ev->pos();
|
||||||
|
d->DragState = DraggingMousePressed;
|
||||||
|
emit clicked();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QFrame::mousePressEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::mouseReleaseEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
// End of tab moving, emit signal
|
||||||
|
if (d->isDraggingState(DraggingTab) && d->DockArea)
|
||||||
|
{
|
||||||
|
emit moved(ev->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
d->DragStartMousePosition = QPoint();
|
||||||
|
d->DragState = DraggingInactive;
|
||||||
|
QFrame::mouseReleaseEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
{
|
||||||
|
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
|
||||||
|
{
|
||||||
|
d->DragState = DraggingInactive;
|
||||||
|
QFrame::mouseMoveEvent(ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move floating window
|
||||||
|
if (d->isDraggingState(DraggingFloatingWidget))
|
||||||
|
{
|
||||||
|
d->FloatingWidget->moveFloating();
|
||||||
|
QFrame::mouseMoveEvent(ev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move tab
|
||||||
|
if (d->isDraggingState(DraggingTab))
|
||||||
|
{
|
||||||
|
// Moving the tab is always allowed because it does not mean moving the
|
||||||
|
// dock widget around
|
||||||
|
d->moveTab(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe a fixed drag distance is better here ?
|
||||||
|
int DragDistanceY = qAbs(d->DragStartMousePosition.y() - ev->pos().y());
|
||||||
|
if (DragDistanceY >= CDockManager::startDragDistance())
|
||||||
|
{
|
||||||
|
// If this is the last dock area in a dock container with only
|
||||||
|
// one single dock widget 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->openDockWidgetsCount() == 1
|
||||||
|
&& d->DockArea->dockContainer()->visibleDockAreaCount() == 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating is only allowed for widgets that are movable
|
||||||
|
if (d->DockWidget->features().testFlag(CDockWidget::DockWidgetMovable))
|
||||||
|
{
|
||||||
|
d->startFloating();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (d->DockArea->openDockWidgetsCount() > 1
|
||||||
|
&& (ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving
|
||||||
|
{
|
||||||
|
d->DragState = DraggingTab;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFrame::mouseMoveEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev)
|
||||||
|
{
|
||||||
|
ev->accept();
|
||||||
|
std::cout << "CDockAreaTabBar::onTabContextMenuRequested" << std::endl;
|
||||||
|
|
||||||
|
d->DragStartMousePosition = ev->pos();
|
||||||
|
QMenu Menu(this);
|
||||||
|
Menu.addAction(tr("Detach"), this, SLOT(onDetachActionTriggered()));
|
||||||
|
Menu.addSeparator();
|
||||||
|
auto Action = Menu.addAction(tr("Close"), this, SIGNAL(closeRequested()));
|
||||||
|
Action->setEnabled(isClosable());
|
||||||
|
Menu.addAction(tr("Close Others"), this, SIGNAL(closeOtherTabsRequested()));
|
||||||
|
Menu.exec(mapToGlobal(ev->pos()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidgetTab::isActiveTab() const
|
||||||
|
{
|
||||||
|
return d->IsActiveTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setActiveTab(bool active)
|
||||||
|
{
|
||||||
|
bool DockWidgetClosable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetClosable);
|
||||||
|
bool TabHasCloseButton = d->testConfigFlag(CDockManager::ActiveTabHasCloseButton);
|
||||||
|
d->CloseButton->setVisible(active && DockWidgetClosable && TabHasCloseButton);
|
||||||
|
if (d->IsActiveTab == active)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->IsActiveTab = active;
|
||||||
|
style()->unpolish(this);
|
||||||
|
style()->polish(this);
|
||||||
|
d->TitleLabel->style()->unpolish(d->TitleLabel);
|
||||||
|
d->TitleLabel->style()->polish(d->TitleLabel);
|
||||||
|
update();
|
||||||
|
|
||||||
|
emit activeTabChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CDockWidgetTab::dockWidget() const
|
||||||
|
{
|
||||||
|
return d->DockWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setDockAreaWidget(CDockAreaWidget* DockArea)
|
||||||
|
{
|
||||||
|
d->DockArea = DockArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockAreaWidget* CDockWidgetTab::dockAreaWidget() const
|
||||||
|
{
|
||||||
|
return d->DockArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setIcon(const QIcon& Icon)
|
||||||
|
{
|
||||||
|
QBoxLayout* Layout = qobject_cast<QBoxLayout*>(layout());
|
||||||
|
if (!d->IconLabel && Icon.isNull())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d->IconLabel)
|
||||||
|
{
|
||||||
|
d->IconLabel = new QLabel();
|
||||||
|
d->IconLabel->setAlignment(Qt::AlignVCenter);
|
||||||
|
d->IconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||||
|
d->IconLabel->setToolTip(d->TitleLabel->toolTip());
|
||||||
|
Layout->insertWidget(0, d->IconLabel, Qt::AlignVCenter);
|
||||||
|
Layout->insertSpacing(1, qRound(1.5 * Layout->contentsMargins().left() / 2.0));
|
||||||
|
}
|
||||||
|
else if (Icon.isNull())
|
||||||
|
{
|
||||||
|
// Remove icon label and spacer item
|
||||||
|
Layout->removeWidget(d->IconLabel);
|
||||||
|
Layout->removeItem(Layout->itemAt(0));
|
||||||
|
delete d->IconLabel;
|
||||||
|
d->IconLabel = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->Icon = Icon;
|
||||||
|
if (d->IconLabel)
|
||||||
|
{
|
||||||
|
d->IconLabel->setPixmap(Icon.pixmap(this->windowHandle(), QSize(16, 16)));
|
||||||
|
d->IconLabel->setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
const QIcon& CDockWidgetTab::icon() const
|
||||||
|
{
|
||||||
|
return d->Icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QString CDockWidgetTab::text() const
|
||||||
|
{
|
||||||
|
return d->TitleLabel->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::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->dockWidgetsCount() > 1)
|
||||||
|
{
|
||||||
|
d->DragStartMousePosition = event->pos();
|
||||||
|
d->startFloating();
|
||||||
|
}
|
||||||
|
|
||||||
|
Super::mouseDoubleClickEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CDockWidgetTab::setVisible(bool visible)
|
||||||
|
{
|
||||||
|
// Just here for debugging to insert debug output
|
||||||
|
Super::setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CDockWidgetTab::isClosable() const
|
||||||
|
{
|
||||||
|
return d->DockWidget && d->DockWidget->features().testFlag(CDockWidget::DockWidgetClosable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CDockWidgetTab::onDetachActionTriggered()
|
||||||
|
{
|
||||||
|
d->DragStartMousePosition = mapFromGlobal(QCursor::pos());
|
||||||
|
d->startFloating();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ads
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF DockWidgetTab.cpp
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
#ifndef DockWidgetTitleBarH
|
#ifndef DockWidgetTabH
|
||||||
#define DockWidgetTitleBarH
|
#define DockWidgetTabH
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
/// \file DockWidgetTitleBar.h
|
/// \file DockWidgetTab.h
|
||||||
/// \author Uwe Kindler
|
/// \author Uwe Kindler
|
||||||
/// \date 27.02.2017
|
/// \date 27.02.2017
|
||||||
/// \brief Declaration of CDockWidgetTitleBar class
|
/// \brief Declaration of CDockWidgetTab class
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
|
||||||
@@ -32,41 +32,55 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
class CDockWidget;
|
class CDockWidget;
|
||||||
class CDockAreaWidget;
|
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_OBJECT
|
||||||
Q_PROPERTY(bool activeTab READ isActiveTab WRITE setActiveTab NOTIFY activeTabChanged)
|
Q_PROPERTY(bool activeTab READ isActiveTab WRITE setActiveTab NOTIFY activeTabChanged)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DockWidgetTitleBarPrivate* d; ///< private data (pimpl)
|
DockWidgetTabPrivate* d; ///< private data (pimpl)
|
||||||
friend class DockWidgetTitleBarPrivate;
|
friend struct DockWidgetTabPrivate;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onDetachActionTriggered();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void mousePressEvent(QMouseEvent* ev) override;
|
virtual void mousePressEvent(QMouseEvent* ev) override;
|
||||||
virtual void mouseReleaseEvent(QMouseEvent* ev) override;
|
virtual void mouseReleaseEvent(QMouseEvent* ev) override;
|
||||||
virtual void mouseMoveEvent(QMouseEvent* ev) override;
|
virtual void mouseMoveEvent(QMouseEvent* ev) override;
|
||||||
|
virtual void contextMenuEvent(QContextMenuEvent* ev) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double clicking the tab widget makes the assigned dock widget floating
|
||||||
|
*/
|
||||||
|
virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using Super = QFrame;
|
||||||
/**
|
/**
|
||||||
* Default Constructor
|
* Default Constructor
|
||||||
* param[in] DockWidget The dock widget this title bar belongs to
|
* param[in] DockWidget The dock widget this title bar belongs to
|
||||||
* param[in] parent The parent widget of this title bar
|
* 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 Destructor
|
||||||
*/
|
*/
|
||||||
virtual ~CDockWidgetTitleBar();
|
virtual ~CDockWidgetTab();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true, if this is the active tab
|
* Returns true, if this is the active tab
|
||||||
@@ -96,11 +110,37 @@ public:
|
|||||||
*/
|
*/
|
||||||
CDockAreaWidget* dockAreaWidget() const;
|
CDockAreaWidget* dockAreaWidget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the icon to show in title bar
|
||||||
|
*/
|
||||||
|
void setIcon(const QIcon& Icon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the icon
|
||||||
|
*/
|
||||||
|
const QIcon& icon() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tab text
|
||||||
|
*/
|
||||||
|
QString text() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns true if the assigned dock widget is closeable
|
||||||
|
*/
|
||||||
|
bool isClosable() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void activeTabChanged();
|
void activeTabChanged();
|
||||||
void clicked();
|
void clicked();
|
||||||
}; // class DockWidgetTitleBar
|
void closeRequested();
|
||||||
|
void closeOtherTabsRequested();
|
||||||
|
void moved(const QPoint& GlobalPos);
|
||||||
|
}; // class DockWidgetTab
|
||||||
}
|
}
|
||||||
// namespace ads
|
// namespace ads
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#endif // DockWidgetTitleBarH
|
#endif // DockWidgetTabH
|
||||||
@@ -1,356 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
** 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.cpp
|
|
||||||
/// \author Uwe Kindler
|
|
||||||
/// \date 27.02.2017
|
|
||||||
/// \brief Implementation of CDockWidgetTitleBar class
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
// INCLUDES
|
|
||||||
//============================================================================
|
|
||||||
#include "DockWidgetTitleBar.h"
|
|
||||||
|
|
||||||
#include <QBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QMouseEvent>
|
|
||||||
#include <QStyle>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QSplitter>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#include "ads_globals.h"
|
|
||||||
#include "DockWidget.h"
|
|
||||||
#include "DockAreaWidget.h"
|
|
||||||
#include "FloatingDockContainer.h"
|
|
||||||
#include "DockOverlay.h"
|
|
||||||
#include "DockManager.h"
|
|
||||||
|
|
||||||
namespace ads
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The different dragging states
|
|
||||||
*/
|
|
||||||
enum eDragState
|
|
||||||
{
|
|
||||||
DraggingInactive, //!< DraggingInactive
|
|
||||||
DraggingMousePressed, //!< DraggingMousePressed
|
|
||||||
DraggingTab, //!< DraggingTab
|
|
||||||
DraggingFloatingWidget//!< DraggingFloatingWidget
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private data class of CDockWidgetTitleBar class (pimpl)
|
|
||||||
*/
|
|
||||||
struct DockWidgetTitleBarPrivate
|
|
||||||
{
|
|
||||||
CDockWidgetTitleBar* _this;
|
|
||||||
CDockWidget* DockWidget;
|
|
||||||
QLabel* IconLabel;
|
|
||||||
QLabel* TitleLabel;
|
|
||||||
QPoint DragStartMousePosition;
|
|
||||||
bool IsActiveTab = false;
|
|
||||||
CDockAreaWidget* DockArea = nullptr;
|
|
||||||
eDragState DragState = DraggingInactive;
|
|
||||||
CFloatingDockContainer* FloatingWidget = nullptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private data constructor
|
|
||||||
*/
|
|
||||||
DockWidgetTitleBarPrivate(CDockWidgetTitleBar* _public);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the complete layout including all controls
|
|
||||||
*/
|
|
||||||
void createLayout();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the tab depending on the position in the given mouse event
|
|
||||||
*/
|
|
||||||
void moveTab(QMouseEvent* ev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test function for current drag state
|
|
||||||
*/
|
|
||||||
bool isDraggingState(eDragState dragState)
|
|
||||||
{
|
|
||||||
return this->DragState == dragState;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the given global point is inside the title area geometry
|
|
||||||
* rectangle.
|
|
||||||
* The position is given as global position.
|
|
||||||
*/
|
|
||||||
bool titleAreaGeometryContains(const QPoint& GlobalPos) const
|
|
||||||
{
|
|
||||||
return DockArea->titleAreaGeometry().contains(DockArea->mapFromGlobal(GlobalPos));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts floating of the dock widget that belongs to this title bar
|
|
||||||
* Returns true, if floating has been started and false if floating
|
|
||||||
* is not possible for any reason
|
|
||||||
*/
|
|
||||||
bool startFloating();
|
|
||||||
};
|
|
||||||
// struct DockWidgetTitleBarPrivate
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
DockWidgetTitleBarPrivate::DockWidgetTitleBarPrivate(CDockWidgetTitleBar* _public) :
|
|
||||||
_this(_public)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void DockWidgetTitleBarPrivate::createLayout()
|
|
||||||
{
|
|
||||||
QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight);
|
|
||||||
l->setContentsMargins(0, 0, 0, 0);
|
|
||||||
_this->setLayout(l);
|
|
||||||
|
|
||||||
IconLabel = new QLabel();
|
|
||||||
IconLabel->setAlignment(Qt::AlignVCenter);
|
|
||||||
l->addWidget(IconLabel, Qt::AlignVCenter);
|
|
||||||
|
|
||||||
TitleLabel = new QLabel();
|
|
||||||
l->addWidget(TitleLabel, 1);
|
|
||||||
|
|
||||||
IconLabel->setVisible(false);
|
|
||||||
TitleLabel->setVisible(true);
|
|
||||||
TitleLabel->setText(DockWidget->windowTitle());
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void DockWidgetTitleBarPrivate::moveTab(QMouseEvent* ev)
|
|
||||||
{
|
|
||||||
ev->accept();
|
|
||||||
int left, top, right, bottom;
|
|
||||||
_this->getContentsMargins(&left, &top, &right, &bottom);
|
|
||||||
QPoint moveToPos = _this->mapToParent(ev->pos()) - DragStartMousePosition;
|
|
||||||
moveToPos.setY(0);
|
|
||||||
_this->move(moveToPos);
|
|
||||||
_this->raise();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
bool DockWidgetTitleBarPrivate::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
|
|
||||||
// it is already floating
|
|
||||||
if (DockWidget->dockContainer()->isFloating()
|
|
||||||
&& (DockWidget->dockContainer()->visibleDockAreaCount() == 1)
|
|
||||||
&& (DockWidget->dockAreaWidget()->count() == 1))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "startFloating";
|
|
||||||
DragState = DraggingFloatingWidget;
|
|
||||||
QSize Size = DockArea->size();
|
|
||||||
CFloatingDockContainer* FloatingWidget = nullptr;
|
|
||||||
if (DockArea->count() > 1)
|
|
||||||
{
|
|
||||||
// If section widget has multiple tabs, we take only one tab
|
|
||||||
FloatingWidget = new CFloatingDockContainer(DockWidget);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qDebug() << "DockWidgetTitleBarPrivate::startFloating DockArea";
|
|
||||||
// If section widget has only one content widget, we can move the complete
|
|
||||||
// dock area into floating widget
|
|
||||||
FloatingWidget = new CFloatingDockContainer(DockArea);
|
|
||||||
}
|
|
||||||
|
|
||||||
FloatingWidget->startFloating(DragStartMousePosition, Size);
|
|
||||||
auto Overlay = DockWidget->dockManager()->containerOverlay();
|
|
||||||
Overlay->setAllowedAreas(OuterDockAreas);
|
|
||||||
this->FloatingWidget = FloatingWidget;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
CDockWidgetTitleBar::CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget *parent) :
|
|
||||||
QFrame(parent),
|
|
||||||
d(new DockWidgetTitleBarPrivate(this))
|
|
||||||
{
|
|
||||||
setAttribute(Qt::WA_NoMousePropagation, true);
|
|
||||||
d->DockWidget = DockWidget;
|
|
||||||
d->createLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
CDockWidgetTitleBar::~CDockWidgetTitleBar()
|
|
||||||
{
|
|
||||||
qDebug() << "~CDockWidgetTitleBar()";
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void CDockWidgetTitleBar::mousePressEvent(QMouseEvent* ev)
|
|
||||||
{
|
|
||||||
if (ev->button() == Qt::LeftButton)
|
|
||||||
{
|
|
||||||
qDebug() << "CDockWidgetTitleBar::mousePressEvent";
|
|
||||||
ev->accept();
|
|
||||||
d->DragStartMousePosition = ev->pos();
|
|
||||||
d->DragState = DraggingMousePressed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QFrame::mousePressEvent(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void CDockWidgetTitleBar::mouseReleaseEvent(QMouseEvent* ev)
|
|
||||||
{
|
|
||||||
qDebug() << "CDockWidgetTitleBar::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->DragStartMousePosition.isNull())
|
|
||||||
{
|
|
||||||
emit clicked();
|
|
||||||
}
|
|
||||||
|
|
||||||
d->DragStartMousePosition = QPoint();
|
|
||||||
d->DragState = DraggingInactive;
|
|
||||||
QFrame::mouseReleaseEvent(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
|
|
||||||
{
|
|
||||||
/*std::cout << "CDockWidgetTitleBar::mouseMoveEventmouseMoveEvent DragState "
|
|
||||||
<< d->DragState << std::endl;*/
|
|
||||||
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
|
|
||||||
{
|
|
||||||
d->DragState = DraggingInactive;
|
|
||||||
QFrame::mouseMoveEvent(ev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->isDraggingState(DraggingFloatingWidget))
|
|
||||||
{
|
|
||||||
//std::cout << "DraggingFloatingWidget" << std::endl;
|
|
||||||
d->FloatingWidget->moveFloating();
|
|
||||||
QFrame::mouseMoveEvent(ev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move tab
|
|
||||||
if (d->isDraggingState(DraggingTab))
|
|
||||||
{
|
|
||||||
d->moveTab(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MouseInsideTitleArea = d->titleAreaGeometryContains(ev->globalPos());
|
|
||||||
if (!MouseInsideTitleArea)
|
|
||||||
{
|
|
||||||
d->startFloating();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (d->DockArea->count() > 1
|
|
||||||
&& (ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving
|
|
||||||
{
|
|
||||||
d->DragState = DraggingTab;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFrame::mouseMoveEvent(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
bool CDockWidgetTitleBar::isActiveTab() const
|
|
||||||
{
|
|
||||||
return d->IsActiveTab;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void CDockWidgetTitleBar::setActiveTab(bool active)
|
|
||||||
{
|
|
||||||
if (d->IsActiveTab == active)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->IsActiveTab = active;
|
|
||||||
style()->unpolish(this);
|
|
||||||
style()->polish(this);
|
|
||||||
d->TitleLabel->style()->unpolish(d->TitleLabel);
|
|
||||||
d->TitleLabel->style()->polish(d->TitleLabel);
|
|
||||||
update();
|
|
||||||
|
|
||||||
emit activeTabChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
CDockWidget* CDockWidgetTitleBar::dockWidget() const
|
|
||||||
{
|
|
||||||
return d->DockWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void CDockWidgetTitleBar::setDockAreaWidget(CDockAreaWidget* DockArea)
|
|
||||||
{
|
|
||||||
d->DockArea = DockArea;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
CDockAreaWidget* CDockWidgetTitleBar::dockAreaWidget() const
|
|
||||||
{
|
|
||||||
return d->DockArea;
|
|
||||||
}
|
|
||||||
} // namespace ads
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
// EOF DockWidgetTitleBar.cpp
|
|
||||||
200
src/ElidingLabel.cpp
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
** 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 ElidingLabel.cpp
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 05.11.2018
|
||||||
|
/// \brief Implementation of CElidingLabel
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <ElidingLabel.h>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Private data of public CClickableLabel
|
||||||
|
*/
|
||||||
|
struct ElidingLabelPrivate
|
||||||
|
{
|
||||||
|
CElidingLabel* _this;
|
||||||
|
Qt::TextElideMode ElideMode = Qt::ElideNone;
|
||||||
|
QString Text;
|
||||||
|
|
||||||
|
ElidingLabelPrivate(CElidingLabel* _public) : _this(_public) {}
|
||||||
|
|
||||||
|
void elideText(int Width);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to check if the
|
||||||
|
*/
|
||||||
|
bool isModeElideNone() const
|
||||||
|
{
|
||||||
|
return Qt::ElideNone == ElideMode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void ElidingLabelPrivate::elideText(int Width)
|
||||||
|
{
|
||||||
|
if (isModeElideNone())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QFontMetrics fm = _this->fontMetrics();
|
||||||
|
QString str = fm.elidedText(Text, ElideMode, Width - _this->margin() * 2 - _this->indent());
|
||||||
|
if (str == "…")
|
||||||
|
{
|
||||||
|
str = Text.at(0);
|
||||||
|
}
|
||||||
|
_this->QLabel::setText(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CElidingLabel::CElidingLabel(QWidget* parent, Qt::WindowFlags f)
|
||||||
|
: QLabel(parent, f),
|
||||||
|
d(new ElidingLabelPrivate(this))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CElidingLabel::CElidingLabel(const QString& text, QWidget* parent, Qt::WindowFlags f)
|
||||||
|
: QLabel(text, parent,f),
|
||||||
|
d(new ElidingLabelPrivate(this))
|
||||||
|
{
|
||||||
|
d->Text = text;
|
||||||
|
setToolTip(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CElidingLabel::~CElidingLabel()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
Qt::TextElideMode CElidingLabel::elideMode() const
|
||||||
|
{
|
||||||
|
return d->ElideMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::setElideMode(Qt::TextElideMode mode)
|
||||||
|
{
|
||||||
|
d->ElideMode = mode;
|
||||||
|
d->elideText(size().width());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::mouseReleaseEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
Super::mouseReleaseEvent(event);
|
||||||
|
if (event->button() != Qt::LeftButton)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit clicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::mouseDoubleClickEvent( QMouseEvent *ev )
|
||||||
|
{
|
||||||
|
Q_UNUSED(ev)
|
||||||
|
emit doubleClicked();
|
||||||
|
Super::mouseDoubleClickEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
if (!d->isModeElideNone())
|
||||||
|
{
|
||||||
|
d->elideText(event->size().width());
|
||||||
|
}
|
||||||
|
Super::resizeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CElidingLabel::minimumSizeHint() const
|
||||||
|
{
|
||||||
|
if (pixmap() != nullptr || d->isModeElideNone())
|
||||||
|
{
|
||||||
|
return QLabel::minimumSizeHint();
|
||||||
|
}
|
||||||
|
const QFontMetrics &fm = fontMetrics();
|
||||||
|
QSize size(fm.width(d->Text.left(2) + "…"), fm.height());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QSize CElidingLabel::sizeHint() const
|
||||||
|
{
|
||||||
|
if (pixmap() != nullptr || d->isModeElideNone())
|
||||||
|
{
|
||||||
|
return QLabel::sizeHint();
|
||||||
|
}
|
||||||
|
const QFontMetrics& fm = fontMetrics();
|
||||||
|
QSize size(fm.width(d->Text), QLabel::sizeHint().height());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CElidingLabel::setText(const QString &text)
|
||||||
|
{
|
||||||
|
if (d->isModeElideNone())
|
||||||
|
{
|
||||||
|
Super::setText(text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d->Text = text;
|
||||||
|
setToolTip( text );
|
||||||
|
d->elideText(this->size().width());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QString CElidingLabel::text() const
|
||||||
|
{
|
||||||
|
return d->Text;
|
||||||
|
}
|
||||||
|
} // namespace QtLabb
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// EOF ClickableLabel.cpp
|
||||||
97
src/ElidingLabel.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#ifndef ElidingLabelH
|
||||||
|
#define ElidingLabelH
|
||||||
|
/*******************************************************************************
|
||||||
|
** 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 ElidingLabel.h
|
||||||
|
/// \author Uwe Kindler
|
||||||
|
/// \date 05.11.2018
|
||||||
|
/// \brief Declaration of CElidingLabel
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// INCLUDES
|
||||||
|
//============================================================================
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
namespace ads
|
||||||
|
{
|
||||||
|
struct ElidingLabelPrivate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A QLabel that supports eliding text.
|
||||||
|
* Because the functions setText() and text() are no virtual functions setting
|
||||||
|
* and reading the text via a pointer to the base class QLabel does not work
|
||||||
|
* properly
|
||||||
|
*/
|
||||||
|
class CElidingLabel : public QLabel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
ElidingLabelPrivate* d;
|
||||||
|
friend class ElidingLabelPrivate;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
virtual void resizeEvent( QResizeEvent *event ) override;
|
||||||
|
virtual void mouseDoubleClickEvent( QMouseEvent *ev ) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Super = QLabel;
|
||||||
|
|
||||||
|
CElidingLabel(QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||||
|
CElidingLabel(const QString& text, QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||||
|
virtual ~CElidingLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the text elide mode.
|
||||||
|
* The default mode is ElideNone
|
||||||
|
*/
|
||||||
|
Qt::TextElideMode elideMode() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text elide mode
|
||||||
|
*/
|
||||||
|
void setElideMode(Qt::TextElideMode mode);
|
||||||
|
|
||||||
|
|
||||||
|
public: // reimplements QLabel ----------------------------------------------
|
||||||
|
virtual QSize minimumSizeHint() const override;
|
||||||
|
virtual QSize sizeHint() const override;
|
||||||
|
void setText(const QString &text);
|
||||||
|
QString text() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the user clicks on the label (i.e. pressed
|
||||||
|
* down then released while the mouse cursor is inside the label)
|
||||||
|
*/
|
||||||
|
void clicked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This signal is emitted if the user does a double click on the label
|
||||||
|
*/
|
||||||
|
void doubleClicked();
|
||||||
|
}; //class CElidingLabel
|
||||||
|
|
||||||
|
} // namespace QtLabb
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#endif // ElidingLabelH
|
||||||
@@ -36,6 +36,8 @@
|
|||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QAbstractButton>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
#include "DockContainerWidget.h"
|
#include "DockContainerWidget.h"
|
||||||
#include "DockAreaWidget.h"
|
#include "DockAreaWidget.h"
|
||||||
@@ -48,6 +50,15 @@
|
|||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
static unsigned int zOrderCounter = 0;
|
static unsigned int zOrderCounter = 0;
|
||||||
|
/**
|
||||||
|
* The different dragging states
|
||||||
|
*/
|
||||||
|
enum eDragState
|
||||||
|
{
|
||||||
|
StateInactive, //!< DraggingInactive
|
||||||
|
StateMousePressed, //!< DraggingMousePressed
|
||||||
|
StateDraggingActive//!< DraggingFloatingWidget
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data class of CFloatingDockContainer class (pimpl)
|
* Private data class of CFloatingDockContainer class (pimpl)
|
||||||
@@ -58,7 +69,7 @@ struct FloatingDockContainerPrivate
|
|||||||
CDockContainerWidget* DockContainer;
|
CDockContainerWidget* DockContainer;
|
||||||
unsigned int zOrderIndex = ++zOrderCounter;
|
unsigned int zOrderIndex = ++zOrderCounter;
|
||||||
QPointer<CDockManager> DockManager;
|
QPointer<CDockManager> DockManager;
|
||||||
bool DraggingActive = false;
|
eDragState DraggingState = StateInactive;
|
||||||
QPoint DragStartMousePosition;
|
QPoint DragStartMousePosition;
|
||||||
CDockContainerWidget* DropContainer = nullptr;
|
CDockContainerWidget* DropContainer = nullptr;
|
||||||
CDockAreaWidget* SingleDockArea = nullptr;
|
CDockAreaWidget* SingleDockArea = nullptr;
|
||||||
@@ -70,10 +81,24 @@ struct FloatingDockContainerPrivate
|
|||||||
|
|
||||||
void titleMouseReleaseEvent();
|
void titleMouseReleaseEvent();
|
||||||
void updateDropOverlays(const QPoint& GlobalPos);
|
void updateDropOverlays(const QPoint& GlobalPos);
|
||||||
void setDraggingActive(bool Active);
|
|
||||||
|
/**
|
||||||
|
* Tests is a certain state is active
|
||||||
|
*/
|
||||||
|
bool isState(eDragState StateId) const
|
||||||
|
{
|
||||||
|
return StateId == DraggingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setState(eDragState StateId)
|
||||||
|
{
|
||||||
|
DraggingState = StateId;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// struct FloatingDockContainerPrivate
|
// struct FloatingDockContainerPrivate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContainer* _public) :
|
FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContainer* _public) :
|
||||||
_this(_public)
|
_this(_public)
|
||||||
@@ -86,25 +111,36 @@ FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContaine
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void FloatingDockContainerPrivate::titleMouseReleaseEvent()
|
void FloatingDockContainerPrivate::titleMouseReleaseEvent()
|
||||||
{
|
{
|
||||||
setDraggingActive(false);
|
setState(StateInactive);
|
||||||
if (!DropContainer)
|
if (!DropContainer)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize the floating widget to the size of the highlighted drop area
|
if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
|
||||||
// rectangle
|
|| DockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea)
|
||||||
QRect Rect = DockManager->containerOverlay()->dropOverlayRect();
|
|
||||||
if (!Rect.isValid())
|
|
||||||
{
|
{
|
||||||
Rect = DockManager->dockAreaOverlay()->rect();
|
// Resize the floating widget to the size of the highlighted drop area
|
||||||
|
// rectangle
|
||||||
|
CDockOverlay* Overlay = DockManager->containerOverlay();
|
||||||
|
if (!Overlay->dropOverlayRect().isValid())
|
||||||
|
{
|
||||||
|
Overlay = DockManager->dockAreaOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect Rect = Overlay->dropOverlayRect();
|
||||||
|
int FrameWidth = (_this->frameSize().width() - _this->rect().width()) / 2;
|
||||||
|
int TitleBarHeight = _this->frameSize().height() - _this->rect().height() - FrameWidth;
|
||||||
|
if (Rect.isValid())
|
||||||
|
{
|
||||||
|
QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft());
|
||||||
|
TopLeft.ry() += TitleBarHeight;
|
||||||
|
_this->setGeometry(QRect(TopLeft, QSize(Rect.width(), Rect.height() - TitleBarHeight)));
|
||||||
|
QApplication::processEvents();
|
||||||
|
}
|
||||||
|
DropContainer->dropFloatingWidget(_this, QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Rect.isValid())
|
|
||||||
{
|
|
||||||
_this->resize(Rect.size());
|
|
||||||
}
|
|
||||||
DropContainer->dropFloatingWidget(_this, QCursor::pos());
|
|
||||||
DockManager->containerOverlay()->hideOverlay();
|
DockManager->containerOverlay()->hideOverlay();
|
||||||
DockManager->dockAreaOverlay()->hideOverlay();
|
DockManager->dockAreaOverlay()->hideOverlay();
|
||||||
}
|
}
|
||||||
@@ -157,15 +193,29 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
|
|||||||
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
|
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
|
||||||
ContainerOverlay->setAllowedAreas(VisibleDockAreas > 1 ?
|
ContainerOverlay->setAllowedAreas(VisibleDockAreas > 1 ?
|
||||||
OuterDockAreas : AllDockAreas);
|
OuterDockAreas : AllDockAreas);
|
||||||
ContainerOverlay->showOverlay(TopContainer);
|
DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
|
||||||
|
ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
|
||||||
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
|
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
|
||||||
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
|
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
|
||||||
{
|
{
|
||||||
|
DockAreaOverlay->enableDropPreview(true);
|
||||||
DockAreaOverlay->setAllowedAreas((VisibleDockAreas == 1) ?
|
DockAreaOverlay->setAllowedAreas((VisibleDockAreas == 1) ?
|
||||||
NoDockWidgetArea : AllDockAreas);
|
NoDockWidgetArea : AllDockAreas);
|
||||||
DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -174,19 +224,11 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
void FloatingDockContainerPrivate::setDraggingActive(bool Active)
|
|
||||||
{
|
|
||||||
DraggingActive = Active;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) :
|
CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) :
|
||||||
QWidget(DockManager, Qt::Window),
|
QWidget(DockManager, Qt::Window),
|
||||||
d(new FloatingDockContainerPrivate(this))
|
d(new FloatingDockContainerPrivate(this))
|
||||||
{
|
{
|
||||||
//setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
d->DockManager = DockManager;
|
d->DockManager = DockManager;
|
||||||
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
|
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||||
l->setContentsMargins(0, 0, 0, 0);
|
l->setContentsMargins(0, 0, 0, 0);
|
||||||
@@ -257,18 +299,18 @@ void CFloatingDockContainer::changeEvent(QEvent *event)
|
|||||||
void CFloatingDockContainer::moveEvent(QMoveEvent *event)
|
void CFloatingDockContainer::moveEvent(QMoveEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::moveEvent(event);
|
QWidget::moveEvent(event);
|
||||||
if (!qApp->mouseButtons().testFlag(Qt::LeftButton))
|
switch (d->DraggingState)
|
||||||
{
|
{
|
||||||
if (d->DraggingActive)
|
case StateMousePressed:
|
||||||
{
|
d->setState(StateDraggingActive);
|
||||||
d->setDraggingActive(false);
|
d->updateDropOverlays(QCursor::pos());
|
||||||
}
|
break;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->DraggingActive)
|
case StateDraggingActive:
|
||||||
{
|
d->updateDropOverlays(QCursor::pos());
|
||||||
d->updateDropOverlays(QCursor::pos());
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,23 +318,29 @@ void CFloatingDockContainer::moveEvent(QMoveEvent *event)
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
|
void CFloatingDockContainer::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
d->setDraggingActive(false);
|
qDebug() << "CFloatingDockContainer closeEvent";
|
||||||
QWidget::closeEvent(event);
|
d->setState(StateInactive);
|
||||||
|
|
||||||
|
if (isClosable())
|
||||||
|
{
|
||||||
|
QWidget::closeEvent(event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CFloatingDockContainer::hideEvent(QHideEvent *event)
|
void CFloatingDockContainer::hideEvent(QHideEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::hideEvent(event);
|
Super::hideEvent(event);
|
||||||
auto OpenDockAreas = d->DockContainer->openedDockAreas();
|
for (auto DockArea : d->DockContainer->openedDockAreas())
|
||||||
for (auto DockArea : OpenDockAreas)
|
|
||||||
{
|
{
|
||||||
auto OpenDockWidgets = DockArea->openedDockWidgets();
|
for (auto DockWidget : DockArea->openedDockWidgets())
|
||||||
for (auto DockWidget : OpenDockWidgets)
|
|
||||||
{
|
{
|
||||||
DockWidget->setToggleViewActionChecked(false);
|
DockWidget->toggleView(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,41 +349,73 @@ void CFloatingDockContainer::hideEvent(QHideEvent *event)
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
void CFloatingDockContainer::showEvent(QShowEvent *event)
|
void CFloatingDockContainer::showEvent(QShowEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::showEvent(event);
|
Super::showEvent(event);
|
||||||
CDockContainerWidget* DockContainer = dockContainer();
|
/*for (auto DockArea : d->DockContainer->openedDockAreas())
|
||||||
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
|
|
||||||
{
|
{
|
||||||
auto DockArea = DockContainer->dockArea(i);
|
|
||||||
for (auto DockWidget : DockArea->openedDockWidgets())
|
for (auto DockWidget : DockArea->openedDockWidgets())
|
||||||
{
|
{
|
||||||
DockWidget->setToggleViewActionChecked(true);
|
DockWidget->setToggleViewActionChecked(true);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
bool CFloatingDockContainer::event(QEvent *e)
|
bool CFloatingDockContainer::event(QEvent *e)
|
||||||
{
|
{
|
||||||
if ((e->type() == QEvent::NonClientAreaMouseButtonPress))
|
switch (d->DraggingState)
|
||||||
{
|
{
|
||||||
if (QGuiApplication::mouseButtons() == Qt::LeftButton)
|
case StateInactive:
|
||||||
|
if (e->type() == QEvent::NonClientAreaMouseButtonPress && QGuiApplication::mouseButtons() == Qt::LeftButton)
|
||||||
{
|
{
|
||||||
qDebug() << "FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type();
|
qDebug() << "FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type();
|
||||||
d->setDraggingActive(true);
|
d->setState(StateMousePressed);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
else if (e->type() == QEvent::NonClientAreaMouseButtonDblClick)
|
|
||||||
{
|
case StateMousePressed:
|
||||||
qDebug() << "FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick";
|
switch (e->type())
|
||||||
d->setDraggingActive(false);
|
{
|
||||||
}
|
case QEvent::NonClientAreaMouseButtonDblClick:
|
||||||
else if ((e->type() == QEvent::NonClientAreaMouseButtonRelease) && d->DraggingActive)
|
qDebug() << "FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick";
|
||||||
{
|
d->setState(StateInactive);
|
||||||
qDebug() << "FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease";
|
break;
|
||||||
d->titleMouseReleaseEvent();
|
|
||||||
|
case QEvent::Resize:
|
||||||
|
// If the first event after the mouse press is a resize event, then
|
||||||
|
// the user resizes the window instead of dragging it around.
|
||||||
|
// But there is one exception. 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->setState(StateInactive);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StateDraggingActive:
|
||||||
|
if (e->type() == QEvent::NonClientAreaMouseButtonRelease)
|
||||||
|
{
|
||||||
|
qDebug() << "FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease";
|
||||||
|
d->titleMouseReleaseEvent();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (ADS_DEBUG_LEVEL > 0)
|
||||||
|
qDebug() << "CFloatingDockContainer::event " << e->type();
|
||||||
|
#endif
|
||||||
return QWidget::event(e);
|
return QWidget::event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +424,7 @@ bool CFloatingDockContainer::event(QEvent *e)
|
|||||||
bool CFloatingDockContainer::eventFilter(QObject *watched, QEvent *event)
|
bool CFloatingDockContainer::eventFilter(QObject *watched, QEvent *event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(watched);
|
Q_UNUSED(watched);
|
||||||
if (event->type() == QEvent::MouseButtonRelease && d->DraggingActive)
|
if (event->type() == QEvent::MouseButtonRelease && d->isState(StateDraggingActive))
|
||||||
{
|
{
|
||||||
qDebug() << "FloatingWidget::eventFilter QEvent::MouseButtonRelease";
|
qDebug() << "FloatingWidget::eventFilter QEvent::MouseButtonRelease";
|
||||||
d->titleMouseReleaseEvent();
|
d->titleMouseReleaseEvent();
|
||||||
@@ -358,7 +438,7 @@ bool CFloatingDockContainer::eventFilter(QObject *watched, QEvent *event)
|
|||||||
void CFloatingDockContainer::startFloating(const QPoint& Pos, const QSize& Size)
|
void CFloatingDockContainer::startFloating(const QPoint& Pos, const QSize& Size)
|
||||||
{
|
{
|
||||||
resize(Size);
|
resize(Size);
|
||||||
d->setDraggingActive(true);
|
d->setState(StateDraggingActive);
|
||||||
QPoint TargetPos = QCursor::pos() - Pos;
|
QPoint TargetPos = QCursor::pos() - Pos;
|
||||||
move(TargetPos);
|
move(TargetPos);
|
||||||
show();
|
show();
|
||||||
@@ -375,13 +455,21 @@ void CFloatingDockContainer::moveFloating()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CFloatingDockContainer::isClosable() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->features().testFlag(CDockWidget::DockWidgetClosable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CFloatingDockContainer::onDockAreasAddedOrRemoved()
|
void CFloatingDockContainer::onDockAreasAddedOrRemoved()
|
||||||
{
|
{
|
||||||
qDebug() << "CFloatingDockContainer::onDockAreasAddedOrRemoved()";
|
qDebug() << "CFloatingDockContainer::onDockAreasAddedOrRemoved()";
|
||||||
if (d->DockContainer->dockAreaCount() == 1)
|
auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
|
||||||
|
if (TopLevelDockArea)
|
||||||
{
|
{
|
||||||
d->SingleDockArea = d->DockContainer->dockArea(0);
|
d->SingleDockArea = TopLevelDockArea;
|
||||||
this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle());
|
this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle());
|
||||||
connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
|
connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
|
||||||
SLOT(onDockAreaCurrentChanged(int)));
|
SLOT(onDockAreaCurrentChanged(int)));
|
||||||
@@ -399,6 +487,21 @@ void CFloatingDockContainer::onDockAreasAddedOrRemoved()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void CFloatingDockContainer::updateWindowTitle()
|
||||||
|
{
|
||||||
|
auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
|
||||||
|
if (TopLevelDockArea)
|
||||||
|
{
|
||||||
|
this->setWindowTitle(TopLevelDockArea->currentDockWidget()->windowTitle());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->setWindowTitle(qApp->applicationDisplayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void CFloatingDockContainer::onDockAreaCurrentChanged(int Index)
|
void CFloatingDockContainer::onDockAreaCurrentChanged(int Index)
|
||||||
{
|
{
|
||||||
@@ -408,17 +511,39 @@ 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))
|
if (!d->DockContainer->restoreState(Stream, Testing))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onDockAreasAddedOrRemoved();
|
onDockAreasAddedOrRemoved();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
bool CFloatingDockContainer::hasTopLevelDockWidget() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->hasTopLevelDockWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
CDockWidget* CFloatingDockContainer::topLevelDockWidget() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->topLevelDockWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QList<CDockWidget*> CFloatingDockContainer::dockWidgets() const
|
||||||
|
{
|
||||||
|
return d->DockContainer->dockWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -31,30 +31,77 @@
|
|||||||
//============================================================================
|
//============================================================================
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "ads_globals.h"
|
||||||
|
|
||||||
|
class QXmlStreamReader;
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
struct FloatingDockContainerPrivate;
|
struct FloatingDockContainerPrivate;
|
||||||
|
class CDockManager;
|
||||||
|
struct DockManagerPrivate;
|
||||||
class CDockAreaWidget;
|
class CDockAreaWidget;
|
||||||
class CDockContainerWidget;
|
class CDockContainerWidget;
|
||||||
class CDockWidget;
|
class CDockWidget;
|
||||||
class CDockManager;
|
class CDockManager;
|
||||||
|
class CDockAreaTabBar;
|
||||||
|
class CDockWidgetTab;
|
||||||
|
struct DockWidgetTabPrivate;
|
||||||
|
class CDockAreaTitleBar;
|
||||||
|
struct DockAreaTitleBarPrivate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This implements a floating widget that is a dock container that accepts
|
* 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
|
* docking of dock widgets like the main window and that can be docked into
|
||||||
* another dock container
|
* another dock container
|
||||||
*/
|
*/
|
||||||
class CFloatingDockContainer : public QWidget
|
class ADS_EXPORT CFloatingDockContainer : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private:
|
private:
|
||||||
FloatingDockContainerPrivate* d; ///< private data (pimpl)
|
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;
|
||||||
|
friend class CDockAreaTitleBar;
|
||||||
|
friend struct DockAreaTitleBarPrivate;
|
||||||
|
friend class CDockWidget;
|
||||||
|
friend class CDockAreaWidget;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDockAreasAddedOrRemoved();
|
void onDockAreasAddedOrRemoved();
|
||||||
void onDockAreaCurrentChanged(int Index);
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function to update the window title
|
||||||
|
*/
|
||||||
|
void updateWindowTitle();
|
||||||
|
|
||||||
|
|
||||||
protected: // reimplements QWidget
|
protected: // reimplements QWidget
|
||||||
virtual void changeEvent(QEvent *event) override;
|
virtual void changeEvent(QEvent *event) override;
|
||||||
@@ -66,6 +113,8 @@ protected: // reimplements QWidget
|
|||||||
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
virtual bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using Super = QWidget;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create empty flatingb widget - required for restore state
|
* Create empty flatingb widget - required for restore state
|
||||||
*/
|
*/
|
||||||
@@ -92,25 +141,32 @@ public:
|
|||||||
CDockContainerWidget* dockContainer() const;
|
CDockContainerWidget* dockContainer() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts floating at the given global position.
|
* This function returns true, if it can be closed.
|
||||||
* Use moveToGlobalPos() to move the widget to a new position
|
* It can be closed, if all dock widgets in all dock areas can be closed
|
||||||
* depending on the start position given in Pos parameter
|
|
||||||
*/
|
*/
|
||||||
void startFloating(const QPoint& Pos, const QSize& Size = QSize());
|
bool isClosable() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the widget to a new position relative to the position given when
|
* This function returns true, if this floating widget has only one single
|
||||||
* startFloating() was called
|
* visible dock widget in a single visible dock area.
|
||||||
*/
|
* The single dock widget is a real top level floating widget because no
|
||||||
void moveFloating();
|
* other widgets are docked.
|
||||||
|
*/
|
||||||
|
bool hasTopLevelDockWidget() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the state from given stream.
|
* This function returns the first dock widget in the first dock area.
|
||||||
* If Testing is true, the function only parses the data from the given
|
* If the function hasSingleDockWidget() returns true, then this function
|
||||||
* stream but does not restore anything. You can use this check for
|
* returns this single dock widget.
|
||||||
* faulty files before you start restoring the state
|
*/
|
||||||
*/
|
CDockWidget* topLevelDockWidget() const;
|
||||||
bool restoreState(QDataStream& Stream, bool Testing);
|
|
||||||
|
/**
|
||||||
|
* This function returns a list of all dock widget in this floating widget.
|
||||||
|
* This is a simple convenience function that simply calls the dockWidgets()
|
||||||
|
* function of the internal container widget.
|
||||||
|
*/
|
||||||
|
QList<CDockWidget*> dockWidgets() const;
|
||||||
}; // class FloatingDockContainer
|
}; // class FloatingDockContainer
|
||||||
}
|
}
|
||||||
// namespace ads
|
// namespace ads
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/ads">
|
<qresource prefix="/ads">
|
||||||
<file>stylesheets/default.css</file>
|
<file>stylesheets/default.css</file>
|
||||||
|
<file>images/close-button.svg</file>
|
||||||
|
<file>images/close-button-disabled.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Qt Advanced Docking System
|
** Qt Advanced Docking System
|
||||||
** Copyright (C) 2017 Uwe Kindler
|
** Copyright (C) 2017 Uwe Kindler
|
||||||
**
|
**
|
||||||
** This library is free software; you can redistribute it and/or
|
** This library is free software; you can redistribute it and/or
|
||||||
** modify it under the terms of the GNU Lesser General Public
|
** modify it under the terms of the GNU Lesser General Public
|
||||||
** License as published by the Free Software Foundation; either
|
** License as published by the Free Software Foundation; either
|
||||||
** version 2.1 of the License, or (at your option) any later version.
|
** 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,
|
** This library is distributed in the hope that it will be useful,
|
||||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
** Lesser General Public License for more details.
|
** Lesser General Public License for more details.
|
||||||
**
|
**
|
||||||
** You should have received a copy of the GNU Lesser General Public
|
** 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/>.
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
// INCLUDES
|
// INCLUDES
|
||||||
//============================================================================
|
//============================================================================
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
#include "DockSplitter.h"
|
#include "DockSplitter.h"
|
||||||
#include "ads_globals.h"
|
#include "ads_globals.h"
|
||||||
@@ -39,16 +40,6 @@ namespace ads
|
|||||||
|
|
||||||
namespace internal
|
namespace internal
|
||||||
{
|
{
|
||||||
//============================================================================
|
|
||||||
QSplitter* newSplitter(Qt::Orientation orientation, QWidget* parent)
|
|
||||||
{
|
|
||||||
QSplitter* s = new CDockSplitter(orientation, parent);
|
|
||||||
s->setProperty("ads-splitter", QVariant(true));
|
|
||||||
s->setChildrenCollapsible(false);
|
|
||||||
s->setOpaqueResize(false);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To)
|
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To)
|
||||||
{
|
{
|
||||||
@@ -62,17 +53,44 @@ CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area)
|
|||||||
{
|
{
|
||||||
switch (Area)
|
switch (Area)
|
||||||
{
|
{
|
||||||
case TopDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Vertical, false);
|
case TopDockWidgetArea: return CDockInsertParam(Qt::Vertical, false);
|
||||||
case RightDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Horizontal, true);
|
case RightDockWidgetArea: return CDockInsertParam(Qt::Horizontal, true);
|
||||||
case CenterDockWidgetArea:
|
case CenterDockWidgetArea:
|
||||||
case BottomDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Vertical, true);
|
case BottomDockWidgetArea: return CDockInsertParam(Qt::Vertical, true);
|
||||||
case LeftDockWidgetArea: return QPair<Qt::Orientation, bool>(Qt::Horizontal, false);
|
case LeftDockWidgetArea: return CDockInsertParam(Qt::Horizontal, false);
|
||||||
default: QPair<Qt::Orientation, bool>(Qt::Vertical, false);
|
default: CDockInsertParam(Qt::Vertical, false);
|
||||||
} // switch (Area)
|
} // switch (Area)
|
||||||
|
|
||||||
return CDockInsertParam(Qt::Vertical, false);
|
return CDockInsertParam(Qt::Vertical, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity)
|
||||||
|
{
|
||||||
|
QPixmap TransparentPixmap(Source.size());
|
||||||
|
TransparentPixmap.fill(Qt::transparent);
|
||||||
|
QPainter p(&TransparentPixmap);
|
||||||
|
p.setOpacity(Opacity);
|
||||||
|
p.drawPixmap(0, 0, Source);
|
||||||
|
return TransparentPixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void hideEmptyParentSplitters(CDockSplitter* Splitter)
|
||||||
|
{
|
||||||
|
while (Splitter && Splitter->isVisible())
|
||||||
|
{
|
||||||
|
if (!Splitter->hasVisibleContent())
|
||||||
|
{
|
||||||
|
Splitter->hide();
|
||||||
|
}
|
||||||
|
Splitter = internal::findParent<CDockSplitter*>(Splitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,24 @@
|
|||||||
// INCLUDES
|
// INCLUDES
|
||||||
//============================================================================
|
//============================================================================
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#ifdef ADS_SHARED_EXPORT
|
||||||
|
#define ADS_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
#define ADS_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ADS_DEBUG_LEVEL 0
|
||||||
|
|
||||||
class QSplitter;
|
class QSplitter;
|
||||||
|
|
||||||
namespace ads
|
namespace ads
|
||||||
{
|
{
|
||||||
|
class CDockSplitter;
|
||||||
|
|
||||||
enum DockWidgetArea
|
enum DockWidgetArea
|
||||||
{
|
{
|
||||||
NoDockWidgetArea = 0x00,
|
NoDockWidgetArea = 0x00,
|
||||||
@@ -52,20 +65,29 @@ enum DockWidgetArea
|
|||||||
Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea)
|
Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea)
|
||||||
|
|
||||||
|
|
||||||
|
enum TitleBarButton
|
||||||
|
{
|
||||||
|
TitleBarButtonTabsMenu,
|
||||||
|
TitleBarButtonUndock,
|
||||||
|
TitleBarButtonClose
|
||||||
|
};
|
||||||
|
|
||||||
namespace internal
|
namespace internal
|
||||||
{
|
{
|
||||||
|
static const bool RestoreTesting = true;
|
||||||
|
static const bool Restore = false;
|
||||||
/**
|
|
||||||
* Helper function to create new splitter widgets
|
|
||||||
*/
|
|
||||||
QSplitter* newSplitter(Qt::Orientation orientation, QWidget* parent = 0);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace the from widget in the given splitter with the To widget
|
* Replace the from widget in the given splitter with the To widget
|
||||||
*/
|
*/
|
||||||
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To);
|
void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function walks the splitter tree upwards to hides all splitters
|
||||||
|
* that do not have visible content
|
||||||
|
*/
|
||||||
|
void hideEmptyParentSplitters(CDockSplitter* FirstParentSplitter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience class for QPair to provide better naming than first and
|
* Convenience class for QPair to provide better naming than first and
|
||||||
* second
|
* second
|
||||||
@@ -88,6 +110,10 @@ CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area);
|
|||||||
* Searches for the parent widget of the given type.
|
* Searches for the parent widget of the given type.
|
||||||
* Returns the parent widget of the given widget or 0 if the widget is not
|
* Returns the parent widget of the given widget or 0 if the widget is not
|
||||||
* child of any widget of type T
|
* child of any widget of type T
|
||||||
|
*
|
||||||
|
* It is not safe to use this function in in CDockWidget because only
|
||||||
|
* the current dock widget has a parent. All dock widgets that are not the
|
||||||
|
* current dock widget in a dock area have no parent.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
T findParent(const QWidget* w)
|
T findParent(const QWidget* w)
|
||||||
@@ -95,7 +121,7 @@ T findParent(const QWidget* w)
|
|||||||
QWidget* parentWidget = w->parentWidget();
|
QWidget* parentWidget = w->parentWidget();
|
||||||
while (parentWidget)
|
while (parentWidget)
|
||||||
{
|
{
|
||||||
T ParentImpl = dynamic_cast<T>(parentWidget);
|
T ParentImpl = qobject_cast<T>(parentWidget);
|
||||||
if (ParentImpl)
|
if (ParentImpl)
|
||||||
{
|
{
|
||||||
return ParentImpl;
|
return ParentImpl;
|
||||||
@@ -105,6 +131,13 @@ T findParent(const QWidget* w)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a semi transparent pixmap from the given pixmap Source.
|
||||||
|
* The Opacity parameter defines the opacity from completely transparent (0.0)
|
||||||
|
* to completely opaque (1.0)
|
||||||
|
*/
|
||||||
|
QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity);
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace ads
|
} // namespace ads
|
||||||
|
|
||||||
|
|||||||
122
src/images/close-button-disabled.svg
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Capa_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="close-button-disabled.svg"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
|
||||||
|
id="metadata897"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs895" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
id="namedview893"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:zoom="0.85862966"
|
||||||
|
inkscape:cx="345.29142"
|
||||||
|
inkscape:cy="32.731258"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Capa_1" />
|
||||||
|
<g
|
||||||
|
id="g860"
|
||||||
|
transform="matrix(0.71708683,0,0,0.71708683,128,128)"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081">
|
||||||
|
<g
|
||||||
|
id="close"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081">
|
||||||
|
<polygon
|
||||||
|
points="357,321.3 214.2,178.5 357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 "
|
||||||
|
id="polygon857"
|
||||||
|
style="stroke:none;stroke-opacity:1;fill:#000000;fill-opacity:0.50196081" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g862"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g864"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g866"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g868"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g870"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g872"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g874"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g876"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g878"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g880"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g882"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g884"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g886"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g888"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g890"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
119
src/images/close-button.svg
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Capa_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="close-button.svg"
|
||||||
|
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
|
||||||
|
id="metadata897"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs895" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1017"
|
||||||
|
id="namedview893"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:zoom="0.85862966"
|
||||||
|
inkscape:cx="345.29142"
|
||||||
|
inkscape:cy="32.731258"
|
||||||
|
inkscape:window-x="-8"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Capa_1" />
|
||||||
|
<g
|
||||||
|
id="g860"
|
||||||
|
transform="matrix(0.71708683,0,0,0.71708683,128,128)">
|
||||||
|
<g
|
||||||
|
id="close">
|
||||||
|
<polygon
|
||||||
|
points="357,321.3 214.2,178.5 357,35.7 321.3,0 178.5,142.8 35.7,0 0,35.7 142.8,178.5 0,321.3 35.7,357 178.5,214.2 321.3,357 "
|
||||||
|
id="polygon857" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g862"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g864"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g866"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g868"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g870"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g872"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g874"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g876"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g878"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g880"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g882"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g884"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g886"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g888"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g890"
|
||||||
|
transform="translate(0,155)">
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
18
src/src.pro
@@ -1,7 +1,7 @@
|
|||||||
ADS_ROOT = $${PWD}/..
|
ADS_ROOT = $${PWD}/..
|
||||||
ADS_OUT_ROOT = $${OUT_PWD}/..
|
ADS_OUT_ROOT = $${OUT_PWD}/..
|
||||||
|
|
||||||
TARGET = $$qtLibraryTarget(AdvancedDockingSystem)
|
TARGET = $$qtLibraryTarget(qtadvanceddocking)
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
DESTDIR = $${ADS_OUT_ROOT}/lib
|
DESTDIR = $${ADS_OUT_ROOT}/lib
|
||||||
QT += core gui widgets
|
QT += core gui widgets
|
||||||
@@ -11,7 +11,7 @@ CONFIG += adsBuildShared
|
|||||||
|
|
||||||
adsBuildShared {
|
adsBuildShared {
|
||||||
CONFIG += shared
|
CONFIG += shared
|
||||||
DEFINES += ADS_EXPORT
|
DEFINES += ADS_SHARED_EXPORT
|
||||||
}
|
}
|
||||||
!adsBuildShared {
|
!adsBuildShared {
|
||||||
CONFIG += staticlib
|
CONFIG += staticlib
|
||||||
@@ -33,23 +33,29 @@ RESOURCES += ads.qrc
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
ads_globals.h \
|
ads_globals.h \
|
||||||
DockAreaWidget.h \
|
DockAreaWidget.h \
|
||||||
|
DockAreaTabBar.h \
|
||||||
DockContainerWidget.h \
|
DockContainerWidget.h \
|
||||||
DockManager.h \
|
DockManager.h \
|
||||||
DockWidget.h \
|
DockWidget.h \
|
||||||
DockWidgetTitleBar.h \
|
DockWidgetTab.h \
|
||||||
FloatingDockContainer.h \
|
FloatingDockContainer.h \
|
||||||
DockOverlay.h \
|
DockOverlay.h \
|
||||||
DockSplitter.h
|
DockSplitter.h \
|
||||||
|
DockAreaTitleBar.h \
|
||||||
|
ElidingLabel.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
ads_globals.cpp \
|
ads_globals.cpp \
|
||||||
DockAreaWidget.cpp \
|
DockAreaWidget.cpp \
|
||||||
|
DockAreaTabBar.cpp \
|
||||||
DockContainerWidget.cpp \
|
DockContainerWidget.cpp \
|
||||||
DockManager.cpp \
|
DockManager.cpp \
|
||||||
DockWidget.cpp \
|
DockWidget.cpp \
|
||||||
DockWidgetTitleBar.cpp \
|
DockWidgetTab.cpp \
|
||||||
FloatingDockContainer.cpp \
|
FloatingDockContainer.cpp \
|
||||||
DockOverlay.cpp \
|
DockOverlay.cpp \
|
||||||
DockSplitter.cpp
|
DockSplitter.cpp \
|
||||||
|
DockAreaTitleBar.cpp \
|
||||||
|
ElidingLabel.cpp
|
||||||
|
|||||||
@@ -25,26 +25,28 @@ ads--CDockAreaWidget #tabsMenuButton::menu-indicator
|
|||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
ads--CDockWidgetTitleBar
|
|
||||||
|
ads--CDockWidgetTab
|
||||||
{
|
{
|
||||||
background: palette(window);
|
background: palette(window);
|
||||||
border-color: palette(light);
|
border-color: palette(light);
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 0 1px 0 0;
|
border-width: 0 1px 0 0;
|
||||||
padding: 0 9px;
|
padding: 0 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
background: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:0.5, stop:0 palette(window), stop:1 palette(light));
|
||||||
|
/*background: palette(highlight);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
ads--CDockWidgetTitleBar QLabel
|
ads--CDockWidgetTab QLabel
|
||||||
{
|
{
|
||||||
color: palette(dark);
|
color: palette(dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
ads--CDockWidgetTitleBar[activeTab="true"] QLabel
|
ads--CDockWidgetTab[activeTab="true"] QLabel
|
||||||
{
|
{
|
||||||
color: palette(foreground);
|
color: palette(foreground);
|
||||||
}
|
}
|
||||||
@@ -57,10 +59,38 @@ ads--CDockWidget
|
|||||||
border-width: 1px 0 0 0;
|
border-width: 1px 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton#closeButton,
|
#tabsMenuButton,
|
||||||
QPushButton#tabsMenuButton
|
#closeButton,
|
||||||
|
#undockButton
|
||||||
{
|
{
|
||||||
padding: 2px;
|
padding: 0 -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QScrollArea#dockWidgetScrollArea
|
||||||
|
{
|
||||||
|
padding: 0px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#tabCloseButton
|
||||||
|
{
|
||||||
|
margin-top: 2px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0px -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabCloseButton:hover
|
||||||
|
{
|
||||||
|
border: 1px solid rgba(0, 0, 0, 32);
|
||||||
|
background: rgba(0, 0, 0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabCloseButton:pressed
|
||||||
|
{
|
||||||
|
background: rgba(0, 0, 0, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||