ADS: Integrate newest base repository commits

* Update to newest version of ADS
* Remove native window and title bar support on linux

Base repository was merged until commit
8d4507e9d83434be976ff8c7bc9f59733937a08d

Task-number: QDS-10242
Change-Id: If74b6b50421be3b759c61b0f76f4a330991f71fa
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Henning Gruendl
2023-06-23 19:58:25 +02:00
committed by Henning Gründl
parent 21983a8377
commit 16ef838f23
47 changed files with 10507 additions and 5668 deletions

View File

@@ -3,6 +3,9 @@ add_qtc_library(AdvancedDockingSystem
SOURCES
ads_globals.cpp ads_globals.h
advanceddockingsystemtr.h
autohidedockcontainer.cpp autohidedockcontainer.h
autohidesidebar.cpp autohidesidebar.h
autohidetab.cpp autohidetab.h
dockareatabbar.cpp dockareatabbar.h
dockareatitlebar.cpp dockareatitlebar.h
dockareawidget.cpp dockareawidget.h
@@ -19,6 +22,8 @@ add_qtc_library(AdvancedDockingSystem
floatingdockcontainer.cpp floatingdockcontainer.h
floatingdragpreview.cpp floatingdragpreview.h
iconprovider.cpp iconprovider.h
pushbutton.cpp pushbutton.h
resizehandle.cpp resizehandle.h
workspace.cpp workspace.h
workspacedialog.cpp workspacedialog.h
workspaceinputdialog.cpp workspaceinputdialog.h
@@ -28,6 +33,7 @@ add_qtc_library(AdvancedDockingSystem
extend_qtc_library(AdvancedDockingSystem
INCLUDES linux
CONDITION UNIX AND NOT APPLE
SOURCES
linux/floatingwidgettitlebar.cpp linux/floatingwidgettitlebar.h
)

View File

@@ -14,10 +14,19 @@
#include <QStyle>
#include <QVariant>
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
#include <QApplication>
#include <QFile>
#include <QSettings>
#endif
namespace ADS {
namespace internal {
const int g_floatingWidgetDragStartEvent = QEvent::registerEventType();
const int g_dockedWidgetDragStartEvent = QEvent::registerEventType();
void replaceSplitterWidget(QSplitter *splitter, QWidget *from, QWidget *to)
{
int index = splitter->indexOf(from);
@@ -25,6 +34,16 @@ void replaceSplitterWidget(QSplitter *splitter, QWidget *from, QWidget *to)
splitter->insertWidget(index, to);
}
void hideEmptyParentSplitters(DockSplitter *splitter)
{
while (splitter && splitter->isVisible()) {
if (!splitter->hasVisibleContent())
splitter->hide();
splitter = internal::findParent<DockSplitter *>(splitter);
}
}
DockInsertParam dockAreaInsertParameters(DockWidgetArea area)
{
switch (area) {
@@ -54,18 +73,8 @@ QPixmap createTransparentPixmap(const QPixmap &source, qreal opacity)
return transparentPixmap;
}
void hideEmptyParentSplitters(DockSplitter *splitter)
{
while (splitter && splitter->isVisible()) {
if (!splitter->hasVisibleContent()) {
splitter->hide();
}
splitter = internal::findParent<DockSplitter *>(splitter);
}
}
void setButtonIcon(QAbstractButton *button,
QStyle::StandardPixmap standarPixmap,
QStyle::StandardPixmap standardPixmap,
ADS::eIcon customIconId)
{
// First we try to use custom icons if available
@@ -75,12 +84,12 @@ void setButtonIcon(QAbstractButton *button,
return;
}
if (Utils::HostOsInfo::isLinuxHost()) {
button->setIcon(button->style()->standardIcon(standarPixmap));
if (Utils::HostOsInfo::isAnyUnixHost() && !Utils::HostOsInfo::isMacHost()) {
button->setIcon(button->style()->standardIcon(standardPixmap));
} else {
// The standard icons does not look good on high DPI screens so we create
// our own "standard" icon here.
QPixmap normalPixmap = button->style()->standardPixmap(standarPixmap, nullptr, button);
QPixmap normalPixmap = button->style()->standardPixmap(standardPixmap, nullptr, button);
icon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25), QIcon::Disabled);
icon.addPixmap(normalPixmap, QIcon::Normal);
button->setIcon(icon);
@@ -98,14 +107,22 @@ void repolishStyle(QWidget *widget, eRepolishChildOptions options)
if (RepolishIgnoreChildren == options)
return;
QList<QWidget*> children = widget->findChildren<QWidget *>(QString(),
(RepolishDirectChildren == options) ? Qt::FindDirectChildrenOnly : Qt::FindChildrenRecursively);
for (auto w : children)
{
QList<QWidget *> children = widget->findChildren<QWidget *>(QString(),
(RepolishDirectChildren == options)
? Qt::FindDirectChildrenOnly
: Qt::FindChildrenRecursively);
for (auto w : children) {
w->style()->unpolish(w);
w->style()->polish(w);
}
}
QRect globalGeometry(QWidget *w)
{
QRect g = w->geometry();
g.moveTopLeft(w->mapToGlobal(QPoint(0, 0)));
return g;
}
} // namespace internal
} // namespace ADS

View File

@@ -55,7 +55,12 @@ enum DockWidgetArea {
};
Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea)
enum eTitleBarButton { TitleBarButtonTabsMenu, TitleBarButtonUndock, TitleBarButtonClose };
enum eTitleBarButton {
TitleBarButtonTabsMenu,
TitleBarButtonUndock,
TitleBarButtonClose,
TitleBarButtonAutoHide
};
/**
* The different dragging states
@@ -71,42 +76,49 @@ enum eDragState {
* The different icons used in the UI
*/
enum eIcon {
TabCloseIcon, //!< TabCloseIcon
DockAreaMenuIcon, //!< DockAreaMenuIcon
DockAreaUndockIcon, //!< DockAreaUndockIcon
DockAreaCloseIcon, //!< DockAreaCloseIcon
FloatingWidgetCloseIcon, //!< FloatingWidgetCloseIcon
TabCloseIcon, //!< TabCloseIcon
AutoHideIcon, //!< AutoHideIcon
DockAreaMenuIcon, //!< DockAreaMenuIcon
DockAreaUndockIcon, //!< DockAreaUndockIcon
DockAreaCloseIcon, //!< DockAreaCloseIcon
FloatingWidgetCloseIcon, //!< FloatingWidgetCloseIcon
FloatingWidgetNormalIcon, //!< FloatingWidgetNormalIcon
FloatingWidgetMaximizeIcon, //!< FloatingWidgetMaximizeIcon
IconCount, //!< just a delimiter for range checks
IconCount, //!< just a delimiter for range checks
};
/**
* For bitwise combination of dock wdget features
* For bitwise combination of dock widget features
*/
enum eBitwiseOperator
{
BitwiseAnd,
BitwiseOr
};
enum eBitwiseOperator { BitwiseAnd, BitwiseOr };
/**
* Each dock container supports 4 sidebars
*/
enum SideBarLocation { SideBarTop, SideBarLeft, SideBarRight, SideBarBottom, SideBarNone };
namespace internal {
const char *const closedProperty = "close";
const char *const dirtyProperty = "dirty";
const char *const g_closedProperty = "close";
const char *const g_dirtyProperty = "dirty";
extern const int g_floatingWidgetDragStartEvent;
extern const int g_dockedWidgetDragStartEvent;
/**
* Replace the from widget in the given splitter with the To widget
* Replace the \p from widget in the given splitter with the \p to widget.
*/
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
* This function walks the splitter tree upwards to hide all splitters that do not
* have visible content.
*/
void hideEmptyParentSplitters(DockSplitter *firstParentSplitter);
/**
* Convenience class for QPair to provide better naming than first and
* second
* Convenience class for QPair to provide better naming than first and second.
*/
class DockInsertParam : public QPair<Qt::Orientation, bool>
{
@@ -121,18 +133,15 @@ public:
};
/**
* Returns the insertion parameters for the given dock area
* Returns the insertion parameters for the given dock area.
*/
DockInsertParam dockAreaInsertParameters(DockWidgetArea area);
/**
* Searches for the parent widget of the given type.
* Returns the parent widget of the given widget or 0 if the widget is not
* child of any widget of type T
*
* It is not safe to use this function in in DockWidget 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.
* Searches for the parent widget of the given type. Returns the parent widget of the given
* widget or 0 if the widget is not child of any widget of type T.
* It is not safe to use this function in in DockWidget 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>
T findParent(const QWidget *widget)
@@ -149,14 +158,13 @@ T findParent(const QWidget *widget)
}
/**
* 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)
* 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);
/**
* Helper function for settings flags in a QFlags instance.
* Helper function for setting flags in a QFlags instance.
*/
template<class T>
void setFlag(T &flags, typename T::enum_type flag, bool on = true)
@@ -165,8 +173,7 @@ void setFlag(T &flags, typename T::enum_type flag, bool on = true)
}
/**
* Helper function for settings tooltips without cluttering the code with
* tests for preprocessor macros
* Helper function for setting tooltips without cluttering the code with tests for preprocessor macros.
*/
template <class QObjectPtr>
void setToolTip(QObjectPtr obj, const QString &tip)
@@ -180,20 +187,20 @@ void setToolTip(QObjectPtr obj, const QString &tip)
}
/**
* Helper function to set the icon of a certain button.
* Use this function to set the icons for the dock area and dock widget buttons.
* The function first uses the CustomIconId to get an icon from the
* IconProvider. You can register your custom icons with the icon provider, if
* you do not want to use the default buttons and if you do not want to use
* stylesheets.
* If the IconProvider does not return a valid icon (icon is null), the function
* fetches the given standard pixmap from the QStyle.
* param[in] Button The button whose icons are to be set
* param[in] StandardPixmap The standard pixmap to be used for the button
* param[in] CustomIconId The identifier for the custom icon.
* Helper function to set the icon of a certain button. Use this function to set the icons for
* the dock area and dock widget buttons.
* The function first uses the \p customIconId to get an icon from the IconProvider. You can
* register your custom icons with the icon provider, if you do not want to use the default buttons
* and if you do not want to use stylesheets.
* If the IconProvider does not return a valid icon (icon is null), the function fetches the given
* standard pixmap from the QStyle.
* param[in] button The button whose icons are to be set
* param[in] standardPixmap The standard pixmap to be used for the button
* param[in] customIconId The identifier for the custom icon.
*/
void setButtonIcon(QAbstractButton *button, QStyle::StandardPixmap standarPixmap,
ADS::eIcon CustomIconId);
void setButtonIcon(QAbstractButton *button,
QStyle::StandardPixmap standardPixmap,
ADS::eIcon customIconId);
enum eRepolishChildOptions
{
@@ -203,10 +210,14 @@ enum eRepolishChildOptions
};
/**
* Calls unpolish() / polish for the style of the given widget to update
* stylesheet if a property changes
* Calls unpolish() / polish for the style of the given widget to update stylesheet if a property changes.
*/
void repolishStyle(QWidget *widget, eRepolishChildOptions options = RepolishIgnoreChildren);
/**
* Returns the geometry of the given widget in global space.
*/
QRect globalGeometry(QWidget *widget);
} // namespace internal
} // namespace ADS

View File

@@ -15,6 +15,9 @@ QtcLibrary {
files: [
"ads_globals.cpp", "ads_globals.h",
"advanceddockingsystemtr.h",
"autohidedockcontainer.cpp", "autohidedockcontainer.h",
"autohidesidebar.cpp", "autohidesidebar.h",
"autohidetab.cpp", "autohidetab.h",
"dockareatabbar.cpp", "dockareatabbar.h",
"dockareatitlebar.cpp", "dockareatitlebar.h",
"dockareawidget.cpp", "dockareawidget.h",
@@ -31,6 +34,8 @@ QtcLibrary {
"floatingdockcontainer.cpp", "floatingdockcontainer.h",
"floatingdragpreview.cpp", "floatingdragpreview.h",
"iconprovider.cpp", "iconprovider.h",
"pushbutton.cpp", "pushbutton.h",
"resizehandle.cpp", "resizehandle.h",
"workspace.cpp", "workspace.h",
"workspacedialog.cpp", "workspacedialog.h",
"workspaceinputdialog.cpp", "workspaceinputdialog.h",

View File

@@ -0,0 +1,512 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#include "autohidedockcontainer.h"
#include "ads_globals_p.h"
#include "autohidesidebar.h"
#include "autohidetab.h"
#include "dockareawidget.h"
#include "dockcomponentsfactory.h"
#include "dockmanager.h"
#include "resizehandle.h"
#include <QApplication>
#include <QBoxLayout>
#include <QCursor>
#include <QPainter>
#include <QPointer>
#include <QSplitter>
#include <QXmlStreamWriter>
#include <iostream>
namespace ADS {
static const int resizeMargin = 30;
bool static isHorizontalArea(SideBarLocation area)
{
switch (area) {
case SideBarLocation::SideBarTop:
case SideBarLocation::SideBarBottom:
return true;
case SideBarLocation::SideBarLeft:
case SideBarLocation::SideBarRight:
return false;
default:
return true;
}
return true;
}
Qt::Edge static edgeFromSideTabBarArea(SideBarLocation area)
{
switch (area) {
case SideBarLocation::SideBarTop:
return Qt::BottomEdge;
case SideBarLocation::SideBarBottom:
return Qt::TopEdge;
case SideBarLocation::SideBarLeft:
return Qt::RightEdge;
case SideBarLocation::SideBarRight:
return Qt::LeftEdge;
default:
return Qt::LeftEdge;
}
return Qt::LeftEdge;
}
int resizeHandleLayoutPosition(SideBarLocation area)
{
switch (area) {
case SideBarLocation::SideBarBottom:
case SideBarLocation::SideBarRight:
return 0;
case SideBarLocation::SideBarTop:
case SideBarLocation::SideBarLeft:
return 1;
default:
return 0;
}
return 0;
}
/**
* Private data of CAutoHideDockContainer - pimpl
*/
struct AutoHideDockContainerPrivate
{
AutoHideDockContainer *q;
DockAreaWidget *m_dockArea{nullptr};
DockWidget *m_dockWidget{nullptr};
SideBarLocation m_sideTabBarArea = SideBarNone;
QBoxLayout *m_layout = nullptr;
ResizeHandle *m_resizeHandle = nullptr;
QSize m_size; // creates invalid size
QPointer<AutoHideTab> m_sideTab;
/**
* Private data constructor
*/
AutoHideDockContainerPrivate(AutoHideDockContainer *parent);
/**
* Convenience function to get a dock widget area
*/
DockWidgetArea getDockWidgetArea(SideBarLocation area)
{
switch (area) {
case SideBarLocation::SideBarLeft:
return LeftDockWidgetArea;
case SideBarLocation::SideBarRight:
return RightDockWidgetArea;
case SideBarLocation::SideBarBottom:
return BottomDockWidgetArea;
case SideBarLocation::SideBarTop:
return TopDockWidgetArea;
default:
return LeftDockWidgetArea;
}
return LeftDockWidgetArea;
}
/**
* Update the resize limit of the resize handle
*/
void updateResizeHandleSizeLimitMax()
{
auto rect = q->dockContainer()->contentRect();
const auto maxResizeHandleSize = m_resizeHandle->orientation() == Qt::Horizontal
? rect.width()
: rect.height();
m_resizeHandle->setMaxResizeSize(maxResizeHandleSize - resizeMargin);
}
/**
* Convenience function to check, if this is an horizontal area
*/
bool isHorizontal() const { return isHorizontalArea(m_sideTabBarArea); }
/**
* Forward this event to the dock container
*/
void forwardEventToDockContainer(QEvent *event)
{
auto dockContainer = q->dockContainer();
if (dockContainer)
dockContainer->handleAutoHideWidgetEvent(event, q);
}
}; // struct AutoHideDockContainerPrivate
AutoHideDockContainerPrivate::AutoHideDockContainerPrivate(AutoHideDockContainer *parent)
: q(parent)
{}
DockContainerWidget *AutoHideDockContainer::dockContainer() const
{
return internal::findParent<DockContainerWidget *>(this);
}
AutoHideDockContainer::AutoHideDockContainer(DockWidget *dockWidget,
SideBarLocation area,
DockContainerWidget *parent)
: QFrame(parent)
, d(new AutoHideDockContainerPrivate(this))
{
hide(); // auto hide dock container is initially always hidden
d->m_sideTabBarArea = area;
d->m_sideTab = componentsFactory()->createDockWidgetSideTab(nullptr);
connect(d->m_sideTab, &AutoHideTab::pressed, this, &AutoHideDockContainer::toggleCollapseState);
d->m_dockArea = new DockAreaWidget(dockWidget->dockManager(), parent);
d->m_dockArea->setObjectName("autoHideDockArea");
d->m_dockArea->setAutoHideDockContainer(this);
setObjectName("autoHideDockContainer");
d->m_layout = new QBoxLayout(isHorizontalArea(area) ? QBoxLayout::TopToBottom
: QBoxLayout::LeftToRight);
d->m_layout->setContentsMargins(0, 0, 0, 0);
d->m_layout->setSpacing(0);
setLayout(d->m_layout);
d->m_resizeHandle = new ResizeHandle(edgeFromSideTabBarArea(area), this);
d->m_resizeHandle->setMinResizeSize(64);
bool opaqueResize = DockManager::testConfigFlag(DockManager::OpaqueSplitterResize);
d->m_resizeHandle->setOpaqueResize(opaqueResize);
d->m_size = d->m_dockArea->size();
addDockWidget(dockWidget);
parent->registerAutoHideWidget(this);
// The dock area should not be added to the layout before it contains the dock widget. If you
// add it to the layout before it contains the dock widget then you will likely see this
// warning for OpenGL widgets or QAxWidgets:
// setGeometry: Unable to set geometry XxY+Width+Height on QWidgetWindow/'WidgetClassWindow
d->m_layout->addWidget(d->m_dockArea);
d->m_layout->insertWidget(resizeHandleLayoutPosition(area), d->m_resizeHandle);
}
void AutoHideDockContainer::updateSize()
{
auto dockContainerParent = dockContainer();
if (!dockContainerParent)
return;
auto rect = dockContainerParent->contentRect();
switch (sideBarLocation()) {
case SideBarLocation::SideBarTop:
resize(rect.width(), qMin(rect.height() - resizeMargin, d->m_size.height()));
move(rect.topLeft());
break;
case SideBarLocation::SideBarLeft:
resize(qMin(d->m_size.width(), rect.width() - resizeMargin), rect.height());
move(rect.topLeft());
break;
case SideBarLocation::SideBarRight: {
resize(qMin(d->m_size.width(), rect.width() - resizeMargin), rect.height());
QPoint p = rect.topRight();
p.rx() -= (width() - 1);
move(p);
} break;
case SideBarLocation::SideBarBottom: {
resize(rect.width(), qMin(rect.height() - resizeMargin, d->m_size.height()));
QPoint p = rect.bottomLeft();
p.ry() -= (height() - 1);
move(p);
} break;
default:
break;
}
}
AutoHideDockContainer::~AutoHideDockContainer()
{
qCInfo(adsLog) << Q_FUNC_INFO;
// Remove event filter in case there are any queued messages
qApp->removeEventFilter(this);
if (dockContainer())
dockContainer()->removeAutoHideWidget(this);
if (d->m_sideTab)
delete d->m_sideTab;
delete d;
}
AutoHideSideBar *AutoHideDockContainer::sideBar() const
{
if (d->m_sideTab) {
return d->m_sideTab->sideBar();
} else {
auto container = dockContainer();
return container ? container->sideTabBar(d->m_sideTabBarArea) : nullptr;
}
}
AutoHideTab *AutoHideDockContainer::autoHideTab() const
{
return d->m_sideTab;
}
DockWidget *AutoHideDockContainer::dockWidget() const
{
return d->m_dockWidget;
}
void AutoHideDockContainer::addDockWidget(DockWidget *dockWidget)
{
if (d->m_dockWidget) {
// Remove the old dock widget at this area
d->m_dockArea->removeDockWidget(d->m_dockWidget);
}
d->m_dockWidget = dockWidget;
d->m_sideTab->setDockWidget(dockWidget);
DockAreaWidget *oldDockArea = dockWidget->dockAreaWidget();
auto isRestoringState = dockWidget->dockManager()->isRestoringState();
if (oldDockArea && !isRestoringState) {
// The initial size should be a little bit bigger than the original dock
// area size to prevent that the resize handle of this auto hid dock area
// is near of the splitter of the old dock area.
d->m_size = oldDockArea->size() + QSize(16, 16);
oldDockArea->removeDockWidget(dockWidget);
}
d->m_dockArea->addDockWidget(dockWidget);
updateSize();
}
SideBarLocation AutoHideDockContainer::sideBarLocation() const
{
return d->m_sideTabBarArea;
}
void AutoHideDockContainer::setSideBarLocation(SideBarLocation sideBarLocation)
{
if (d->m_sideTabBarArea == sideBarLocation)
return;
d->m_sideTabBarArea = sideBarLocation;
d->m_layout->removeWidget(d->m_resizeHandle);
d->m_layout->setDirection(isHorizontalArea(sideBarLocation) ? QBoxLayout::TopToBottom
: QBoxLayout::LeftToRight);
d->m_layout->insertWidget(resizeHandleLayoutPosition(sideBarLocation), d->m_resizeHandle);
d->m_resizeHandle->setHandlePosition(edgeFromSideTabBarArea(sideBarLocation));
internal::repolishStyle(this, internal::RepolishDirectChildren);
}
DockAreaWidget *AutoHideDockContainer::dockAreaWidget() const
{
return d->m_dockArea;
}
void AutoHideDockContainer::moveContentsToParent()
{
cleanupAndDelete();
// If we unpin the auto hide dock widget, then we insert it into the same
// location like it had as a auto hide widget. This brings the least surprise
// to the user and he does not have to search where the widget was inserted.
d->m_dockWidget->setDockArea(nullptr);
auto DockContainer = dockContainer();
DockContainer->addDockWidget(d->getDockWidgetArea(d->m_sideTabBarArea), d->m_dockWidget);
}
void AutoHideDockContainer::cleanupAndDelete()
{
const auto dockWidget = d->m_dockWidget;
if (dockWidget) {
auto sideTab = d->m_sideTab;
sideTab->removeFromSideBar();
sideTab->setParent(nullptr);
sideTab->hide();
}
hide();
deleteLater();
}
void AutoHideDockContainer::saveState(QXmlStreamWriter &s)
{
s.writeStartElement("widget");
s.writeAttribute("name", d->m_dockWidget->objectName());
s.writeAttribute("closed", QString::number(d->m_dockWidget->isClosed() ? 1 : 0));
s.writeAttribute("size",
QString::number(d->isHorizontal() ? d->m_size.height() : d->m_size.width()));
s.writeEndElement();
}
void AutoHideDockContainer::toggleView(bool enable)
{
if (enable) {
if (d->m_sideTab)
d->m_sideTab->show();
} else {
if (d->m_sideTab)
d->m_sideTab->hide();
hide();
qApp->removeEventFilter(this);
}
}
void AutoHideDockContainer::collapseView(bool enable)
{
if (enable) {
hide();
qApp->removeEventFilter(this);
} else {
updateSize();
d->updateResizeHandleSizeLimitMax();
raise();
show();
d->m_dockWidget->dockManager()->setDockWidgetFocused(d->m_dockWidget);
qApp->installEventFilter(this);
}
qCInfo(adsLog) << Q_FUNC_INFO << enable;
d->m_sideTab->updateStyle();
}
void AutoHideDockContainer::toggleCollapseState()
{
collapseView(isVisible());
}
void AutoHideDockContainer::setSize(int size)
{
if (d->isHorizontal())
d->m_size.setHeight(size);
else
d->m_size.setWidth(size);
updateSize();
}
/**
* Returns true if the object given in ancestor is an ancestor of the object given in descendant
*/
static bool objectIsAncestorOf(const QObject* descendant, const QObject* ancestor)
{
if (!ancestor)
return false;
while (descendant) {
if (descendant == ancestor)
return true;
descendant = descendant->parent();
}
return false;
}
/**
* Returns true if the object given in ancestor is the object given in descendant
* or if it is an ancestor of the object given in descendant
*/
static bool isObjectOrAncestor(const QObject *descendant, const QObject *ancestor)
{
if (ancestor && (descendant == ancestor))
return true;
else
return objectIsAncestorOf(descendant, ancestor);
}
bool AutoHideDockContainer::eventFilter(QObject *watched, QEvent *event)
{
// A switch case statement would be nicer here, but we cannot use
// internal::FloatingWidgetDragStartEvent in a switch case
if (event->type() == QEvent::Resize) {
if (!d->m_resizeHandle->isResizing())
updateSize();
} else if (event->type() == QEvent::MouseButtonPress) {
auto widget = qobject_cast<QWidget *>(watched);
// Ignore non widget events
if (!widget)
return QFrame::eventFilter(watched, event);
// Now check, if the user clicked into the side tab and ignore this event,
// because the side tab click handler will call collapseView(). If we
// do not ignore this here, then we will collapse the container and the side tab
// click handler will uncollapse it
if (widget == d->m_sideTab.data())
return QFrame::eventFilter(watched, event);
// Now we check, if the user clicked inside of this auto hide container.
// If the click is inside of this auto hide container, then we can
// ignore the event, because the auto hide overlay should not get collapsed if
// user works in it
if (isObjectOrAncestor(widget, this))
return QFrame::eventFilter(watched, event);
// Ignore the mouse click if it is not inside of this container
if (!isObjectOrAncestor(widget, dockContainer()))
return QFrame::eventFilter(watched, event);
// User clicked into container - collapse the auto hide widget
collapseView(true);
} else if (event->type() == internal::g_floatingWidgetDragStartEvent) {
// If we are dragging our own floating widget, the we do not need to collapse the view
auto widget = dockContainer()->floatingWidget();
if (widget != watched)
collapseView(true);
} else if (event->type() == internal::g_dockedWidgetDragStartEvent) {
collapseView(true);
}
return QFrame::eventFilter(watched, event);
}
void AutoHideDockContainer::resizeEvent(QResizeEvent *event)
{
QFrame::resizeEvent(event);
if (d->m_resizeHandle->isResizing()) {
d->m_size = this->size();
d->updateResizeHandleSizeLimitMax();
}
}
void AutoHideDockContainer::leaveEvent(QEvent *event)
{
// Resizing of the dock container via the resize handle in non opaque mode
// mays cause a leave event that is not really a leave event. Therefore
// we check here, if we are really outside of our rect.
auto pos = mapFromGlobal(QCursor::pos());
if (!rect().contains(pos))
d->forwardEventToDockContainer(event);
QFrame::leaveEvent(event);
}
bool AutoHideDockContainer::event(QEvent *event)
{
switch (event->type()) {
case QEvent::Enter:
case QEvent::Hide:
d->forwardEventToDockContainer(event);
break;
case QEvent::MouseButtonPress:
return true;
break;
default:
break;
}
return QFrame::event(event);
}
} // namespace ADS

View File

@@ -0,0 +1,142 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#pragma once
#include "ads_globals.h"
#include "autohidetab.h"
#include <QSplitter>
QT_BEGIN_NAMESPACE
class QXmlStreamWriter;
QT_BEGIN_NAMESPACE
namespace ADS {
struct AutoHideDockContainerPrivate;
class DockManager;
class DockWidget;
class DockContainerWidget;
class AutoHideSideBar;
class DockAreaWidget;
class DockingStateReader;
struct SideTabBarPrivate;
/**
* Auto hide container for hosting an auto hide dock widget
*/
class ADS_EXPORT AutoHideDockContainer : public QFrame
{
Q_OBJECT
Q_PROPERTY(int sideBarLocation READ sideBarLocation CONSTANT) // TODO
private:
AutoHideDockContainerPrivate *d; ///< private data (pimpl)
friend struct AutoHideDockContainerPrivate;
friend AutoHideSideBar;
friend SideTabBarPrivate;
protected:
virtual bool eventFilter(QObject *watched, QEvent *event) override;
virtual void resizeEvent(QResizeEvent *event) override;
virtual void leaveEvent(QEvent *event) override;
virtual bool event(QEvent *event) override;
/**
* Updates the size considering the size limits and the resize margins
*/
void updateSize();
/*
* Saves the state and size
*/
void saveState(QXmlStreamWriter &Stream);
public:
/**
* Create Auto Hide widget with the given dock widget
*/
AutoHideDockContainer(DockWidget *dockWidget, SideBarLocation area, DockContainerWidget *parent);
/**
* Virtual Destructor
*/
virtual ~AutoHideDockContainer();
/**
* Get's the side tab bar
*/
AutoHideSideBar *sideBar() const;
/**
* Returns the side tab
*/
AutoHideTab *autoHideTab() const;
/**
* Get's the dock widget in this dock container
*/
DockWidget *dockWidget() const;
/**
* Adds a dock widget and removes the previous dock widget
*/
void addDockWidget(DockWidget *dockWidget);
/**
* Returns the side tab bar area of this Auto Hide dock container
*/
SideBarLocation sideBarLocation() const;
/**
* Sets a new SideBarLocation.
* If a new side bar location is set, the auto hide dock container needs
* to update its resize handle position
*/
void setSideBarLocation(SideBarLocation sideBarLocation);
/**
* Returns the dock area widget of this Auto Hide dock container
*/
DockAreaWidget *dockAreaWidget() const;
/**
* Returns the parent container that hosts this auto hide container
*/
DockContainerWidget *dockContainer() const;
/**
* Moves the contents to the parent container widget
* Used before removing this Auto Hide dock container
*/
void moveContentsToParent();
/**
* Cleanups up the side tab widget and then deletes itself
*/
void cleanupAndDelete();
/**
* Toggles the auto Hide dock container widget. This will also hide the side tab widget.
*/
void toggleView(bool enable);
/**
* Collapses the auto hide dock container widget
* Does not hide the side tab widget
*/
void collapseView(bool enable);
/**
* Toggles the current collapse state
*/
void toggleCollapseState();
/**
* Use this instead of resize.
* Depending on the sidebar location this will set the width or height of this auto hide container.
*/
void setSize(int size);
};
} // namespace ADS

View File

@@ -0,0 +1,316 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#include "autohidesidebar.h"
#include "ads_globals_p.h"
#include "autohidedockcontainer.h"
#include "autohidetab.h"
#include "dockareawidget.h"
#include "dockcontainerwidget.h"
#include "dockfocuscontroller.h"
#include "dockingstatereader.h"
#include "dockwidgettab.h"
#include <QBoxLayout>
#include <QPainter>
#include <QResizeEvent>
#include <QStyleOption>
#include <QXmlStreamWriter>
namespace ADS {
class TabsWidget;
/**
* Private data class of CSideTabBar class (pimpl)
*/
struct AutoHideSideBarPrivate
{
/**
* Private data constructor
*/
AutoHideSideBarPrivate(AutoHideSideBar *parent);
AutoHideSideBar *q;
DockContainerWidget *m_containerWidget;
TabsWidget *m_tabsContainerWidget;
QBoxLayout *m_tabsLayout;
Qt::Orientation m_orientation;
SideBarLocation m_sideTabArea = SideBarLocation::SideBarLeft;
/**
* Convenience function to check if this is a horizontal side bar
*/
bool isHorizontal() const { return Qt::Horizontal == m_orientation; }
/**
* Called from viewport to forward event handling to this
*/
void handleViewportEvent(QEvent* e);
}; // struct AutoHideSideBarPrivate
/**
* This widget stores the tab buttons
*/
class TabsWidget : public QWidget
{
public:
using QWidget::QWidget;
using Super = QWidget;
AutoHideSideBarPrivate *eventHandler;
/**
* Returns the size hint as minimum size hint
*/
virtual QSize minimumSizeHint() const override { return Super::sizeHint(); }
/**
* Forward event handling to EventHandler
*/
virtual bool event(QEvent *e) override
{
eventHandler->handleViewportEvent(e);
return Super::event(e);
}
};
AutoHideSideBarPrivate::AutoHideSideBarPrivate(AutoHideSideBar *parent)
: q(parent)
{}
void AutoHideSideBarPrivate::handleViewportEvent(QEvent* e)
{
switch (e->type()) {
case QEvent::ChildRemoved:
if (m_tabsLayout->isEmpty())
q->hide();
break;
default:
break;
}
}
AutoHideSideBar::AutoHideSideBar(DockContainerWidget *parent, SideBarLocation area)
: Super(parent)
, d(new AutoHideSideBarPrivate(this))
{
d->m_sideTabArea = area;
d->m_containerWidget = parent;
d->m_orientation = (area == SideBarLocation::SideBarBottom
|| area == SideBarLocation::SideBarTop)
? Qt::Horizontal
: Qt::Vertical;
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
setFrameStyle(QFrame::NoFrame);
setWidgetResizable(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->m_tabsContainerWidget = new TabsWidget();
d->m_tabsContainerWidget->eventHandler = d;
d->m_tabsContainerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
d->m_tabsContainerWidget->setObjectName("sideTabsContainerWidget");
d->m_tabsLayout = new QBoxLayout(d->m_orientation == Qt::Vertical ? QBoxLayout::TopToBottom
: QBoxLayout::LeftToRight);
d->m_tabsLayout->setContentsMargins(0, 0, 0, 0);
d->m_tabsLayout->setSpacing(12);
d->m_tabsLayout->addStretch(1);
d->m_tabsContainerWidget->setLayout(d->m_tabsLayout);
setWidget(d->m_tabsContainerWidget);
setFocusPolicy(Qt::NoFocus);
if (d->isHorizontal())
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
else
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
hide();
}
AutoHideSideBar::~AutoHideSideBar()
{
qCInfo(adsLog) << Q_FUNC_INFO;
// The SideTabeBar is not the owner of the tabs and to prevent deletion
// we set the parent here to nullptr to remove it from the children
auto tabs = findChildren<AutoHideTab *>(QString(), Qt::FindDirectChildrenOnly);
for (auto tab : tabs)
tab->setParent(nullptr);
delete d;
}
void AutoHideSideBar::insertTab(int index, AutoHideTab *sideTab)
{
sideTab->setSideBar(this);
sideTab->installEventFilter(this);
if (index < 0)
d->m_tabsLayout->insertWidget(d->m_tabsLayout->count() - 1, sideTab);
else
d->m_tabsLayout->insertWidget(index, sideTab);
show();
}
AutoHideDockContainer *AutoHideSideBar::insertDockWidget(int index, DockWidget *dockWidget)
{
auto autoHideContainer = new AutoHideDockContainer(dockWidget,
d->m_sideTabArea,
d->m_containerWidget);
dockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(dockWidget);
auto tab = autoHideContainer->autoHideTab();
dockWidget->setSideTabWidget(tab);
insertTab(index, tab);
return autoHideContainer;
}
void AutoHideSideBar::removeAutoHideWidget(AutoHideDockContainer *autoHideWidget)
{
autoHideWidget->autoHideTab()->removeFromSideBar();
auto dockContainer = autoHideWidget->dockContainer();
if (dockContainer)
dockContainer->removeAutoHideWidget(autoHideWidget);
autoHideWidget->setParent(nullptr);
}
void AutoHideSideBar::addAutoHideWidget(AutoHideDockContainer *autoHideWidget)
{
auto sideBar = autoHideWidget->autoHideTab()->sideBar();
if (sideBar == this)
return;
if (sideBar)
sideBar->removeAutoHideWidget(autoHideWidget);
autoHideWidget->setParent(d->m_containerWidget);
autoHideWidget->setSideBarLocation(d->m_sideTabArea);
d->m_containerWidget->registerAutoHideWidget(autoHideWidget);
insertTab(-1, autoHideWidget->autoHideTab());
}
void AutoHideSideBar::removeTab(AutoHideTab *sideTab)
{
sideTab->removeEventFilter(this);
d->m_tabsLayout->removeWidget(sideTab);
if (d->m_tabsLayout->isEmpty())
hide();
}
bool AutoHideSideBar::eventFilter(QObject *watched, QEvent *event)
{
auto tab = qobject_cast<AutoHideTab *>(watched);
if (!tab)
return false;
switch (event->type()) {
case QEvent::ShowToParent:
show();
break;
case QEvent::HideToParent:
if (!hasVisibleTabs())
hide();
break;
default:
break;
}
return false;
}
Qt::Orientation AutoHideSideBar::orientation() const
{
return d->m_orientation;
}
AutoHideTab *AutoHideSideBar::tabAt(int index) const
{
return qobject_cast<AutoHideTab *>(d->m_tabsLayout->itemAt(index)->widget());
}
int AutoHideSideBar::tabCount() const
{
return d->m_tabsLayout->count() - 1;
}
int AutoHideSideBar::visibleTabCount() const
{
int count = 0;
auto parent = parentWidget();
for (auto i = 0; i < tabCount(); i++) {
if (tabAt(i)->isVisibleTo(parent))
count++;
}
return count;
}
bool AutoHideSideBar::hasVisibleTabs() const
{
auto parent = parentWidget();
for (auto i = 0; i < tabCount(); i++) {
if (tabAt(i)->isVisibleTo(parent))
return true;
}
return false;
}
SideBarLocation AutoHideSideBar::sideBarLocation() const
{
return d->m_sideTabArea;
}
void AutoHideSideBar::saveState(QXmlStreamWriter &s) const
{
if (!tabCount())
return;
s.writeStartElement("sideBar");
s.writeAttribute("area", QString::number(sideBarLocation()));
s.writeAttribute("tabs", QString::number(tabCount()));
for (auto i = 0; i < tabCount(); ++i) {
auto tab = tabAt(i);
if (!tab)
continue;
tab->dockWidget()->autoHideDockContainer()->saveState(s);
}
s.writeEndElement();
}
QSize AutoHideSideBar::minimumSizeHint() const
{
QSize size = sizeHint();
size.setWidth(10);
return size;
}
QSize AutoHideSideBar::sizeHint() const
{
return d->m_tabsContainerWidget->sizeHint();
}
int AutoHideSideBar::spacing() const
{
return d->m_tabsLayout->spacing();
}
void AutoHideSideBar::setSpacing(int spacing)
{
d->m_tabsLayout->setSpacing(spacing);
}
DockContainerWidget *AutoHideSideBar::dockContainer() const
{
return d->m_containerWidget;
}
} // namespace ADS

View File

@@ -0,0 +1,157 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#pragma once
#include "ads_globals.h"
#include "autohidetab.h"
#include <QScrollArea>
class QXmlStreamWriter;
namespace ADS {
struct AutoHideSideBarPrivate;
class DockContainerWidgetPrivate;
class DockContainerWidget;
class AutoHideTab;
class AutoHideDockContainer;
class DockingStateReader;
/**
* Side tab bar widget that is shown at the edges of a dock container.
* The tab bar is only visible, if it contains visible content, that means if
* it contains visible tabs. If it is empty or all tabs are hidden, then the
* side bar is also hidden. As soon as one single tab becomes visible, this
* tab bar will be shown.
* The CAutoHideSideBar uses a QScrollArea here, to enable proper resizing.
* If the side bar contains many tabs, then the tabs are simply clipped - this
* is the same like in visual studio
*/
class ADS_EXPORT AutoHideSideBar : public QScrollArea
{
Q_OBJECT
Q_PROPERTY(int sideBarLocation READ sideBarLocation)
Q_PROPERTY(Qt::Orientation orientation READ orientation)
Q_PROPERTY(int spacing READ spacing WRITE setSpacing)
private:
AutoHideSideBarPrivate* d; ///< private data (pimpl)
friend struct AutoHideSideBarPrivate;
friend class DockWidgetSideTab;
friend DockContainerWidgetPrivate;
friend DockContainerWidget;
protected:
virtual bool eventFilter(QObject *watched, QEvent *event) override;
/**
* Saves the state into the given stream
*/
void saveState(QXmlStreamWriter &stream) const;
/**
* Inserts the given dock widget tab at the given position.
* An Index value of -1 appends the side tab at the end.
*/
void insertTab(int index, AutoHideTab *sideTab);
public:
using Super = QScrollArea;
/**
* Default Constructor
*/
AutoHideSideBar(DockContainerWidget *parent, SideBarLocation area);
/**
* Virtual Destructor
*/
virtual ~AutoHideSideBar();
/**
* Removes the given DockWidgetSideTab from the tabbar
*/
void removeTab(AutoHideTab *sideTab);
/**
* Insert dock widget into the side bar. The function creates the auto hide dock container,
* inserts the auto hide tab
*/
AutoHideDockContainer *insertDockWidget(int index, DockWidget *dockWidget);
/**
* Removes the auto hide widget from this side bar
*/
void removeAutoHideWidget(AutoHideDockContainer *autoHideWidget);
/**
* Adds the given AutoHideWidget to this sidebar. If the AutoHideWidget is in another sidebar,
* then it will be removed from this sidebar.
*/
void addAutoHideWidget(AutoHideDockContainer *autoHideWidget);
/**
* Returns orientation of side tab.
*/
Qt::Orientation orientation() const;
/**
* Get the side tab widget at position, returns nullptr if it's out of bounds.
*/
AutoHideTab *tabAt(int index) const;
/**
* Gets the count of the tab widgets.
*/
int tabCount() const;
/**
* Returns the number of visible tabs to its parent widget.
*/
int visibleTabCount() const;
/**
* Returns true, if the sidebar contains visible tabs to its parent widget.
* The function returns as soon as it finds the first visible tab. That means, if you just want
* to find out if there are visible tabs then this function is quicker than visibleTabCount().
*/
bool hasVisibleTabs() const;
/**
* Getter for side tab bar area property
*/
SideBarLocation sideBarLocation() const;
/**
* Overrides the minimumSizeHint() function of QScrollArea
* The minimumSizeHint() is bigger than the sizeHint () for the scroll
* area because even if the scrollbars are invisible, the required speace
* is reserved in the minimumSizeHint(). This override simply returns sizeHint();
*/
virtual QSize minimumSizeHint() const override;
/**
* The function provides a sizeHint that matches the height of the internal viewport.
*/
virtual QSize sizeHint() const override;
/**
* Getter for spacing property - returns the spacing of the tabs
*/
int spacing() const;
/**
* Setter for spacing property - sets the spacing
*/
void setSpacing(int spacing);
/**
* Returns the dock container that hosts this sideBar()
*/
DockContainerWidget *dockContainer() const;
};
} // namespace ADS

View File

@@ -0,0 +1,203 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#include "autohidetab.h"
#include "ads_globals_p.h"
#include "autohidedockcontainer.h"
#include "autohidesidebar.h"
#include "dockmanager.h"
#include "dockwidget.h"
#include <QApplication>
#include <QBoxLayout>
#include <QElapsedTimer>
namespace ADS {
/**
* Private data class of CDockWidgetTab class (pimpl)
*/
struct AutoHideTabPrivate
{
AutoHideTab *q;
DockWidget *m_dockWidget = nullptr;
AutoHideSideBar *m_sideBar = nullptr;
Qt::Orientation m_orientation{Qt::Vertical};
QElapsedTimer m_timeSinceHoverMousePress;
/**
* Private data constructor
*/
AutoHideTabPrivate(AutoHideTab *parent);
/**
* Update the orientation, visibility and spacing based on the area of the side bar
*/
void updateOrientation();
/**
* Convenience function to ease dock container access
*/
DockContainerWidget *dockContainer() const
{
return m_dockWidget ? m_dockWidget->dockContainer() : nullptr;
}
/**
* Forward this event to the dock container
*/
void forwardEventToDockContainer(QEvent *event)
{
auto container = dockContainer();
if (container)
container->handleAutoHideWidgetEvent(event, q);
}
}; // struct DockWidgetTabPrivate
AutoHideTabPrivate::AutoHideTabPrivate(AutoHideTab *parent)
: q(parent)
{}
void AutoHideTabPrivate::updateOrientation()
{
bool iconOnly = DockManager::testAutoHideConfigFlag(DockManager::AutoHideSideBarsIconOnly);
if (iconOnly && !q->icon().isNull()) {
q->setText("");
q->setOrientation(Qt::Horizontal);
} else {
auto area = m_sideBar->sideBarLocation();
q->setOrientation((area == SideBarBottom || area == SideBarTop) ? Qt::Horizontal
: Qt::Vertical);
}
}
void AutoHideTab::setSideBar(AutoHideSideBar *sideTabBar)
{
d->m_sideBar = sideTabBar;
if (d->m_sideBar)
d->updateOrientation();
}
AutoHideSideBar *AutoHideTab::sideBar() const
{
return d->m_sideBar;
}
void AutoHideTab::removeFromSideBar()
{
if (d->m_sideBar == nullptr)
return;
d->m_sideBar->removeTab(this);
setSideBar(nullptr);
}
AutoHideTab::AutoHideTab(QWidget *parent)
: PushButton(parent)
, d(new AutoHideTabPrivate(this))
{
setAttribute(Qt::WA_NoMousePropagation);
setFocusPolicy(Qt::NoFocus);
}
AutoHideTab::~AutoHideTab()
{
qCInfo(adsLog) << Q_FUNC_INFO;
delete d;
}
void AutoHideTab::updateStyle()
{
internal::repolishStyle(this, internal::RepolishDirectChildren);
update();
}
SideBarLocation AutoHideTab::sideBarLocation() const
{
if (d->m_sideBar)
return d->m_sideBar->sideBarLocation();
return SideBarLeft;
}
void AutoHideTab::setOrientation(Qt::Orientation value)
{
d->m_orientation = value;
if (orientation() == Qt::Horizontal) {
setMinimumWidth(100);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
} else {
setMinimumHeight(100);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
}
PushButton::setButtonOrientation((Qt::Horizontal == value) ? PushButton::Horizontal
: PushButton::VerticalTopToBottom);
updateStyle();
}
Qt::Orientation AutoHideTab::orientation() const
{
return d->m_orientation;
}
bool AutoHideTab::isActiveTab() const
{
if (d->m_dockWidget && d->m_dockWidget->autoHideDockContainer())
return d->m_dockWidget->autoHideDockContainer()->isVisible();
return false;
}
DockWidget *AutoHideTab::dockWidget() const
{
return d->m_dockWidget;
}
void AutoHideTab::setDockWidget(DockWidget *dockWidget)
{
if (!dockWidget)
return;
d->m_dockWidget = dockWidget;
setText(dockWidget->windowTitle());
setIcon(d->m_dockWidget->icon());
setToolTip(dockWidget->windowTitle());
}
bool AutoHideTab::event(QEvent *event)
{
if (!DockManager::testAutoHideConfigFlag(DockManager::AutoHideShowOnMouseOver))
return Super::event(event);
switch (event->type()) {
case QEvent::Enter:
case QEvent::Leave:
d->forwardEventToDockContainer(event);
break;
case QEvent::MouseButtonPress:
// If AutoHideShowOnMouseOver is active, then the showing is triggered by a MousePressEvent
// sent to this tab. To prevent accidental hiding of the tab by a mouse click, we wait at
// least 500 ms before we accept the mouse click.
if (!event->spontaneous()) {
d->m_timeSinceHoverMousePress.restart();
d->forwardEventToDockContainer(event);
} else if (d->m_timeSinceHoverMousePress.hasExpired(500)) {
d->forwardEventToDockContainer(event);
}
break;
default:
break;
}
return Super::event(event);
}
bool AutoHideTab::iconOnly() const
{
return DockManager::testAutoHideConfigFlag(DockManager::AutoHideSideBarsIconOnly)
&& !icon().isNull();
}
} // namespace ADS

View File

@@ -0,0 +1,107 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#pragma once
#include "pushbutton.h"
#include "ads_globals.h"
namespace ADS {
struct AutoHideTabPrivate;
class DockWidget;
class AutoHideSideBar;
class DockWidgetTab;
class DockContainerWidgetPrivate;
/**
* A dock widget Side tab that shows a title or an icon.
* The dock widget tab is shown in the side tab bar to switch between pinned dock widgets.
*/
class ADS_EXPORT AutoHideTab : public PushButton
{
Q_OBJECT
Q_PROPERTY(int sideBarLocation READ sideBarLocation CONSTANT)
Q_PROPERTY(Qt::Orientation orientation READ orientation CONSTANT)
Q_PROPERTY(bool activeTab READ isActiveTab CONSTANT)
Q_PROPERTY(bool iconOnly READ iconOnly CONSTANT)
private:
AutoHideTabPrivate *d; ///< private data (pimpl)
friend struct AutoHideTabPrivate;
friend class DockWidget;
friend class AutoHideDockContainer;
friend class AutoHideSideBar;
friend class DockAreaWidget;
friend class DockContainerWidget;
friend DockContainerWidgetPrivate;
protected:
void setSideBar(AutoHideSideBar *sideTabBar);
void removeFromSideBar();
virtual bool event(QEvent *event) override;
public:
using Super = PushButton;
/**
* Default Constructor
* param[in] parent The parent widget of this title bar
*/
AutoHideTab(QWidget *parent = nullptr);
/**
* Virtual Destructor
*/
virtual ~AutoHideTab();
/**
* Update stylesheet style if a property changes.
*/
void updateStyle();
/**
* Getter for side tab bar area property.
*/
SideBarLocation sideBarLocation() const;
/**
* Set orientation vertical or horizontal.
*/
void setOrientation(Qt::Orientation value);
/**
* Returns the current orientation.
*/
Qt::Orientation orientation() const;
/**
* Returns true, if this is the active tab. The tab is active if the auto hide widget is visible.
*/
bool isActiveTab() const;
/**
* Returns the dock widget this belongs to.
*/
DockWidget *dockWidget() const;
/**
* Sets the dock widget that is controlled by this tab.
*/
void setDockWidget(DockWidget *dockWidget);
/**
* Returns true if the auto hide config flag AutoHideSideBarsIconOnly is set and if
* the tab has an icon - that means the icon is not null.
*/
bool iconOnly() const;
/**
* Returns the side bar that contains this tab or a nullptr if the tab is not in a side bar.
*/
AutoHideSideBar *sideBar() const;
}; // class AutoHideTab
} // namespace ADS

View File

@@ -13,340 +13,353 @@
#include <QLoggingCategory>
#include <QMouseEvent>
#include <QScrollBar>
#include <QTimer>
#include <QtGlobal>
#include <iostream>
namespace ADS
namespace ADS {
/**
* Private data class of DockAreaTabBar class (pimpl)
*/
class DockAreaTabBarPrivate
{
public:
DockAreaTabBar *q;
DockAreaWidget *m_dockArea = nullptr;
QWidget *m_tabsContainerWidget = nullptr;
QBoxLayout *m_tabsLayout = nullptr;
int m_currentIndex = -1;
/**
* Private data class of DockAreaTabBar class (pimpl)
* Private data constructor
*/
class DockAreaTabBarPrivate
{
public:
DockAreaTabBar *q;
DockAreaWidget *m_dockArea = nullptr;
QWidget *m_tabsContainerWidget = nullptr;
QBoxLayout *m_tabsLayout = nullptr;
int m_currentIndex = -1;
DockAreaTabBarPrivate(DockAreaTabBar *parent);
/**
* Private data constructor
*/
DockAreaTabBarPrivate(DockAreaTabBar *parent);
/**
* Update tabs after current index changed or when tabs are removed.
* The function reassigns the stylesheet to update the tabs.
*/
void updateTabs();
/**
* Update tabs after current index changed or when tabs are removed.
* The function reassigns the stylesheet to update the tabs
*/
void updateTabs();
/**
* Convenience function to access first tab.
*/
DockWidgetTab *firstTab() const { return q->tab(0); }
/**
* Convenience function to access first tab
*/
DockWidgetTab *firstTab() const { return q->tab(0); }
/**
* Convenience function to access last tab.
*/
DockWidgetTab *lastTab() const { return q->tab(q->count() - 1); }
}; // class DockAreaTabBarPrivate
/**
* Convenience function to access last tab
*/
DockWidgetTab *lastTab() const { return q->tab(q->count() - 1); }
}; // class DockAreaTabBarPrivate
DockAreaTabBarPrivate::DockAreaTabBarPrivate(DockAreaTabBar *parent)
: q(parent)
{}
DockAreaTabBarPrivate::DockAreaTabBarPrivate(DockAreaTabBar *parent)
: q(parent)
{}
void DockAreaTabBarPrivate::updateTabs()
{
// Set active TAB and update all other tabs to be inactive
for (int i = 0; i < q->count(); ++i) {
auto tabWidget = q->tab(i);
if (!tabWidget)
continue;
void DockAreaTabBarPrivate::updateTabs()
{
// Set active TAB and update all other tabs to be inactive
for (int i = 0; i < q->count(); ++i) {
auto tabWidget = q->tab(i);
if (!tabWidget)
continue;
if (i == m_currentIndex) {
tabWidget->show();
tabWidget->setActiveTab(true);
// Sometimes the synchronous calculation of the rectangular area fails. Therefore we
// use QTimer::singleShot here to execute the call within the event loop - see #520.
QTimer::singleShot(0, q, [&, tabWidget] { q->ensureWidgetVisible(tabWidget); });
} else {
tabWidget->setActiveTab(false);
}
}
}
if (i == m_currentIndex) {
tabWidget->show();
tabWidget->setActiveTab(true);
q->ensureWidgetVisible(tabWidget);
} else {
tabWidget->setActiveTab(false);
DockAreaTabBar::DockAreaTabBar(DockAreaWidget *parent)
: QScrollArea(parent)
, d(new DockAreaTabBarPrivate(this))
{
d->m_dockArea = parent;
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
setFrameStyle(QFrame::NoFrame);
setWidgetResizable(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->m_tabsContainerWidget = new QWidget();
d->m_tabsContainerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
d->m_tabsContainerWidget->setObjectName("tabsContainerWidget");
d->m_tabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
d->m_tabsLayout->setContentsMargins(0, 0, 0, 0);
d->m_tabsLayout->setSpacing(0);
d->m_tabsLayout->addStretch(1);
d->m_tabsContainerWidget->setLayout(d->m_tabsLayout);
setWidget(d->m_tabsContainerWidget);
}
DockAreaTabBar::~DockAreaTabBar()
{
delete d;
}
void DockAreaTabBar::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 DockAreaTabBar::setCurrentIndex(int index)
{
if (index == d->m_currentIndex)
return;
if (index < -1 || index > (count() - 1)) {
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
return;
}
emit currentChanging(index);
d->m_currentIndex = index;
d->updateTabs();
updateGeometry();
emit currentChanged(index);
}
int DockAreaTabBar::count() const
{
// The tab bar contains a stretch item as last item
return d->m_tabsLayout->count() - 1;
}
void DockAreaTabBar::insertTab(int index, DockWidgetTab *dockWidgetTab)
{
d->m_tabsLayout->insertWidget(index, dockWidgetTab);
connect(dockWidgetTab, &DockWidgetTab::clicked, this, [this, dockWidgetTab] {
onTabClicked(dockWidgetTab);
});
connect(dockWidgetTab, &DockWidgetTab::closeRequested, this, [this, dockWidgetTab] {
onTabCloseRequested(dockWidgetTab);
});
connect(dockWidgetTab, &DockWidgetTab::closeOtherTabsRequested, this, [this, dockWidgetTab] {
onCloseOtherTabsRequested(dockWidgetTab);
});
connect(dockWidgetTab,
&DockWidgetTab::moved,
this,
[this, dockWidgetTab](const QPoint &globalPosition) {
onTabWidgetMoved(dockWidgetTab, globalPosition);
});
connect(dockWidgetTab, &DockWidgetTab::elidedChanged, this, &DockAreaTabBar::elidedChanged);
dockWidgetTab->installEventFilter(this);
emit tabInserted(index);
if (index <= d->m_currentIndex)
setCurrentIndex(d->m_currentIndex + 1);
else if (d->m_currentIndex == -1)
setCurrentIndex(index);
updateGeometry();
}
void DockAreaTabBar::removeTab(DockWidgetTab *dockWidgetTab)
{
if (!count())
return;
qCInfo(adsLog) << Q_FUNC_INFO;
int newCurrentIndex = currentIndex();
int removeIndex = d->m_tabsLayout->indexOf(dockWidgetTab);
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;
}
}
}
DockAreaTabBar::DockAreaTabBar(DockAreaWidget *parent)
: QScrollArea(parent)
, d(new DockAreaTabBarPrivate(this))
{
d->m_dockArea = parent;
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
setFrameStyle(QFrame::NoFrame);
setWidgetResizable(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
d->m_tabsContainerWidget = new QWidget();
d->m_tabsContainerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
d->m_tabsContainerWidget->setObjectName("tabsContainerWidget");
d->m_tabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
d->m_tabsLayout->setContentsMargins(0, 0, 0, 0);
d->m_tabsLayout->setSpacing(0);
d->m_tabsLayout->addStretch(1);
d->m_tabsContainerWidget->setLayout(d->m_tabsLayout);
setWidget(d->m_tabsContainerWidget);
}
DockAreaTabBar::~DockAreaTabBar() { delete d; }
void DockAreaTabBar::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 DockAreaTabBar::setCurrentIndex(int index)
{
if (index == d->m_currentIndex)
return;
if (index < -1 || index > (count() - 1)) {
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
return;
}
emit currentChanging(index);
d->m_currentIndex = index;
d->updateTabs();
updateGeometry();
emit currentChanged(index);
}
int DockAreaTabBar::count() const
{
// The tab bar contains a stretch item as last item
return d->m_tabsLayout->count() - 1;
}
void DockAreaTabBar::insertTab(int index, DockWidgetTab *dockWidgetTab)
{
d->m_tabsLayout->insertWidget(index, dockWidgetTab);
connect(dockWidgetTab, &DockWidgetTab::clicked,
this, [this, dockWidgetTab] { onTabClicked(dockWidgetTab); });
connect(dockWidgetTab, &DockWidgetTab::closeRequested,
this, [this, dockWidgetTab] { onTabCloseRequested(dockWidgetTab); });
connect(dockWidgetTab, &DockWidgetTab::closeOtherTabsRequested,
this, [this, dockWidgetTab] { onCloseOtherTabsRequested(dockWidgetTab); });
connect(dockWidgetTab, &DockWidgetTab::moved,
this, [this, dockWidgetTab](const QPoint &globalPosition) {
onTabWidgetMoved(dockWidgetTab, globalPosition);
});
connect(dockWidgetTab, &DockWidgetTab::elidedChanged,
this, &DockAreaTabBar::elidedChanged);
dockWidgetTab->installEventFilter(this);
emit tabInserted(index);
if (index <= d->m_currentIndex)
setCurrentIndex(d->m_currentIndex + 1);
else if (d->m_currentIndex == -1)
setCurrentIndex(index);
updateGeometry();
}
void DockAreaTabBar::removeTab(DockWidgetTab *dockWidgetTab)
{
if (!count())
return;
qCInfo(adsLog) << Q_FUNC_INFO;
int newCurrentIndex = currentIndex();
int removeIndex = d->m_tabsLayout->indexOf(dockWidgetTab);
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 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 - 1;
newCurrentIndex = i;
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->m_tabsLayout->removeWidget(dockWidgetTab);
dockWidgetTab->disconnect(this);
dockWidgetTab->removeEventFilter(this);
qCInfo(adsLog) << "NewCurrentIndex " << newCurrentIndex;
if (newCurrentIndex != d->m_currentIndex)
setCurrentIndex(newCurrentIndex);
else
d->updateTabs();
updateGeometry();
}
int DockAreaTabBar::currentIndex() const { return d->m_currentIndex; }
DockWidgetTab *DockAreaTabBar::currentTab() const
{
if (d->m_currentIndex < 0)
return nullptr;
else
return qobject_cast<DockWidgetTab *>(
d->m_tabsLayout->itemAt(d->m_currentIndex)->widget());
}
void DockAreaTabBar::onTabClicked(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
if (index < 0)
return;
setCurrentIndex(index);
emit tabBarClicked(index);
}
void DockAreaTabBar::onTabCloseRequested(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
closeTab(index);
}
void DockAreaTabBar::onCloseOtherTabsRequested(DockWidgetTab *sourceTab)
{
for (int i = 0; i < count(); ++i) {
auto currentTab = tab(i);
if (currentTab->isClosable() && !currentTab->isHidden() && currentTab != sourceTab) {
// If the dock widget is deleted with the closeTab() call, its tab it will no longer
// be in the layout, and thus the index needs to be updated to not skip any tabs
int offset = currentTab->dockWidget()->features().testFlag(
DockWidget::DockWidgetDeleteOnClose)
? 1
: 0;
closeTab(i);
// If the the dock widget blocks closing, i.e. if the flag
// CustomCloseHandling is set, and the dock widget is still open,
// then we do not need to correct the index
if (currentTab->dockWidget()->isClosed())
i -= offset;
}
}
}
DockWidgetTab *DockAreaTabBar::tab(int index) const
{
if (index >= count() || index < 0)
return nullptr;
emit removingTab(removeIndex);
d->m_tabsLayout->removeWidget(dockWidgetTab);
dockWidgetTab->disconnect(this);
dockWidgetTab->removeEventFilter(this);
qCInfo(adsLog) << "NewCurrentIndex" << newCurrentIndex;
if (newCurrentIndex != d->m_currentIndex)
setCurrentIndex(newCurrentIndex);
else
d->updateTabs();
return qobject_cast<DockWidgetTab *>(d->m_tabsLayout->itemAt(index)->widget());
}
updateGeometry();
}
void DockAreaTabBar::onTabWidgetMoved(DockWidgetTab *sourceTab, const QPoint &globalPosition)
{
const int fromIndex = d->m_tabsLayout->indexOf(sourceTab);
auto mousePos = mapFromGlobal(globalPosition);
mousePos.rx() = qMax(d->firstTab()->geometry().left(), mousePos.x());
mousePos.rx() = qMin(d->lastTab()->geometry().right(), mousePos.x());
int toIndex = -1;
// Find tab under mouse
for (int i = 0; i < count(); ++i) {
DockWidgetTab *dropTab = tab(i);
if (dropTab == sourceTab || !dropTab->isVisibleTo(this)
|| !dropTab->geometry().contains(mousePos))
continue;
int DockAreaTabBar::currentIndex() const
{
return d->m_currentIndex;
}
toIndex = d->m_tabsLayout->indexOf(dropTab);
if (toIndex == fromIndex)
toIndex = -1;
DockWidgetTab *DockAreaTabBar::currentTab() const
{
if (d->m_currentIndex < 0)
return nullptr;
else
return qobject_cast<DockWidgetTab *>(d->m_tabsLayout->itemAt(d->m_currentIndex)->widget());
}
break;
}
void DockAreaTabBar::onTabClicked(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
if (index < 0)
return;
if (toIndex > -1) {
d->m_tabsLayout->removeWidget(sourceTab);
d->m_tabsLayout->insertWidget(toIndex, sourceTab);
qCInfo(adsLog) << "tabMoved from" << fromIndex << "to" << toIndex;
emit tabMoved(fromIndex, toIndex);
setCurrentIndex(toIndex);
} else {
// Ensure that the moved tab is reset to its start position
d->m_tabsLayout->update();
setCurrentIndex(index);
emit tabBarClicked(index);
}
void DockAreaTabBar::onTabCloseRequested(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
closeTab(index);
}
void DockAreaTabBar::onCloseOtherTabsRequested(DockWidgetTab *sourceTab)
{
for (int i = 0; i < count(); ++i) {
auto currentTab = tab(i);
if (currentTab->isClosable() && !currentTab->isHidden() && currentTab != sourceTab) {
// If the dock widget is deleted with the closeTab() call, its tab it will no longer
// be in the layout, and thus the index needs to be updated to not skip any tabs.
int offset = currentTab->dockWidget()->features().testFlag(
DockWidget::DockWidgetDeleteOnClose)
? 1
: 0;
closeTab(i);
// If the the dock widget blocks closing, i.e. if the flag CustomCloseHandling is set,
// and the dock widget is still open, then we do not need to correct the index.
if (currentTab->dockWidget()->isClosed())
i -= offset;
}
}
}
void DockAreaTabBar::closeTab(int index)
{
if (index < 0 || index >= count())
return;
DockWidgetTab *DockAreaTabBar::tab(int index) const
{
if (index >= count() || index < 0)
return nullptr;
auto dockWidgetTab = tab(index);
if (dockWidgetTab->isHidden())
return;
return qobject_cast<DockWidgetTab *>(d->m_tabsLayout->itemAt(index)->widget());
}
emit tabCloseRequested(index);
void DockAreaTabBar::onTabWidgetMoved(DockWidgetTab *sourceTab, const QPoint &globalPosition)
{
const int fromIndex = d->m_tabsLayout->indexOf(sourceTab);
auto mousePos = mapFromGlobal(globalPosition);
mousePos.rx() = qMax(d->firstTab()->geometry().left(), mousePos.x());
mousePos.rx() = qMin(d->lastTab()->geometry().right(), mousePos.x());
int toIndex = -1;
// Find tab under mouse
for (int i = 0; i < count(); ++i) {
DockWidgetTab *dropTab = tab(i);
if (dropTab == sourceTab || !dropTab->isVisibleTo(this)
|| !dropTab->geometry().contains(mousePos))
continue;
toIndex = d->m_tabsLayout->indexOf(dropTab);
if (toIndex == fromIndex)
toIndex = -1;
break;
}
bool DockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
{
bool result = Super::eventFilter(watched, event);
DockWidgetTab *dockWidgetTab = qobject_cast<DockWidgetTab *>(watched);
if (!dockWidgetTab)
return result;
if (toIndex > -1) {
d->m_tabsLayout->removeWidget(sourceTab);
d->m_tabsLayout->insertWidget(toIndex, sourceTab);
qCInfo(adsLog) << "tabMoved from" << fromIndex << "to" << toIndex;
emit tabMoved(fromIndex, toIndex);
setCurrentIndex(toIndex);
} else {
// Ensure that the moved tab is reset to its start position
d->m_tabsLayout->update();
}
}
switch (event->type()) {
case QEvent::Hide:
emit tabClosed(d->m_tabsLayout->indexOf(dockWidgetTab));
updateGeometry();
break;
case QEvent::Show:
emit tabOpened(d->m_tabsLayout->indexOf(dockWidgetTab));
updateGeometry();
break;
default:
break;
}
void DockAreaTabBar::closeTab(int index)
{
if (index < 0 || index >= count())
return;
auto dockWidgetTab = tab(index);
if (dockWidgetTab->isHidden())
return;
emit tabCloseRequested(index);
}
bool DockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
{
bool result = Super::eventFilter(watched, event);
DockWidgetTab *dockWidgetTab = qobject_cast<DockWidgetTab *>(watched);
if (!dockWidgetTab)
return result;
switch (event->type()) {
case QEvent::Hide:
emit tabClosed(d->m_tabsLayout->indexOf(dockWidgetTab));
updateGeometry();
break;
case QEvent::Show:
emit tabOpened(d->m_tabsLayout->indexOf(dockWidgetTab));
updateGeometry();
break;
// Setting the text of a tab will cause a LayoutRequest event
case QEvent::LayoutRequest:
updateGeometry();
break;
default:
break;
}
bool DockAreaTabBar::isTabOpen(int index) const
{
if (index < 0 || index >= count())
return false;
return result;
}
return !tab(index)->isHidden();
}
bool DockAreaTabBar::isTabOpen(int index) const
{
if (index < 0 || index >= count())
return false;
QSize DockAreaTabBar::minimumSizeHint() const
{
QSize size = sizeHint();
size.setWidth(10);
return size;
}
return !tab(index)->isHidden();
}
QSize DockAreaTabBar::sizeHint() const
{
return d->m_tabsContainerWidget->sizeHint();
}
QSize DockAreaTabBar::minimumSizeHint() const
{
QSize size = sizeHint();
size.setWidth(10);
return size;
}
QSize DockAreaTabBar::sizeHint() const
{
return d->m_tabsContainerWidget->sizeHint();
}
} // namespace ADS

View File

@@ -101,7 +101,7 @@ public:
/**
* Overrides the minimumSizeHint() function of QScrollArea
* The minimumSizeHint() is bigger than the sizeHint () for the scroll
* area because even if the scrollbars are invisible, the required speace
* area because even if the scrollbars are invisible, the required space
* is reserved in the minimumSizeHint(). This override simply returns
* sizeHint();
*/

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@ namespace ADS {
class DockAreaTabBar;
class DockAreaWidget;
class DockAreaTitleBarPrivate;
class ElidingLabel;
using TitleBarButtonType = QToolButton;
@@ -81,6 +82,9 @@ private:
void onUndockButtonClicked();
void onTabsMenuActionTriggered(QAction *action);
void onCurrentTabChanged(int index);
void onAutoHideButtonClicked();
void onAutoHideDockAreaActionClicked();
void onAutoHideToActionClicked();
protected:
/**
@@ -137,6 +141,11 @@ public:
*/
QAbstractButton *button(eTitleBarButton which) const;
/**
* Returns the auto hide title label, used when the dock area is expanded and auto hidden
*/
ElidingLabel* autoHideTitleLabel() const;
/**
* Updates the visibility of the dock widget actions in the title bar
*/
@@ -166,6 +175,12 @@ public:
*/
int indexOf(QWidget *widget) const;
/**
* Close group tool tip based on the current state
* Auto hide widgets can only have one dock widget so it does not make sense for the tooltip to show close group
*/
QString titleBarButtonToolTip(eTitleBarButton button) const;
signals:
/**
* This signal is emitted if a tab in the tab bar is clicked by the user

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
#pragma once
#include "ads_globals.h"
#include "autohidetab.h"
#include "dockwidget.h"
#include <QFrame>
@@ -20,6 +21,8 @@ class DockManager;
class DockContainerWidget;
class DockContainerWidgetPrivate;
class DockAreaTitleBar;
class DockingStateReader;
class AutoHideDockContainer;
/**
* DockAreaWidget manages multiple instances of DockWidgets.
@@ -39,6 +42,9 @@ private:
friend class DockWidget;
friend class DockManagerPrivate;
friend class DockManager;
friend class AutoHideDockContainer;
void onDockWidgetFeaturesChanged();
void onTabCloseRequested(int index);
@@ -48,7 +54,34 @@ private:
*/
void reorderDockWidget(int fromIndex, int toIndex);
/*
* Update the auto hide button checked state based on if it's contained in an auto hide container or not
*/
void updateAutoHideButtonCheckState();
/*
* Update the title bar button tooltips
*/
void updateTitleBarButtonsToolTips();
/**
* Calculate the auto hide side bar location depending on the dock area
* widget position in the container
*/
SideBarLocation calculateSideTabBarArea() const;
protected:
#ifdef Q_OS_WIN
/**
* Reimplements QWidget::event to handle QEvent::PlatformSurface
* This is here to fix issue #294 Tab refresh problem with a QGLWidget
* that exists since Qt version 5.12.7. So this function is here to
* work around a Qt issue.
*/
virtual bool event(QEvent *event) override;
#endif
/**
* Inserts a dock widget into dock area.
* All dockwidgets in the dock area tabified in a stacked layout with tabs.
@@ -110,11 +143,26 @@ protected:
*/
void markTitleBarMenuOutdated();
/*
* Update the title bar button visibility based on if it's top level or not
*/
void updateTitleBarButtonVisibility(bool isTopLevel) const;
void toggleView(bool open);
public:
using Super = QFrame;
/**
* Dock area related flags
*/
enum eDockAreaFlag
{
HideSingleWidgetTitleBar = 0x0001,
DefaultFlags = 0x0000
};
Q_DECLARE_FLAGS(DockAreaFlags, eDockAreaFlag)
/**
* Default Constructor
*/
@@ -135,6 +183,27 @@ public:
* if there is no
*/
DockContainerWidget *dockContainer() const;
/**
* Returns the auto hide dock container widget this dock area widget belongs to or 0
* if there is no
*/
AutoHideDockContainer *autoHideDockContainer() const;
/**
* Returns true if the dock area is in an auto hide container
*/
bool isAutoHide() const;
/**
* Sets the current auto hide dock container
*/
void setAutoHideDockContainer(AutoHideDockContainer *autoHideDockContainer);
/**
* Returns the largest minimumSizeHint() of the dock widgets in this area.
* The minimum size hint is updated if a dock widget is removed or added.
*/
virtual QSize minimumSizeHint() const override;
/**
* Returns the rectangle of the title area
@@ -205,6 +274,12 @@ public:
*/
void saveState(QXmlStreamWriter &stream) const;
/**
* Restores a dock area.
* \see restoreChildNodes() for details
*/
static bool restoreState(DockingStateReader& stream, DockAreaWidget*& createdWidget, bool testing, DockContainerWidget* parentContainer);
/**
* This functions returns the dock widget features of all dock widget in
* this area.
@@ -242,6 +317,41 @@ public:
*/
DockAreaTitleBar *titleBar() const;
/**
* Returns the dock area flags - a combination of flags that configure the
* appearance and features of the dock area.
* \see setDockAreaFlasg()
*/
DockAreaFlags dockAreaFlags() const;
/**
* Sets the dock area flags - a combination of flags that configure the
* appearance and features of the dock area
*/
void setDockAreaFlags(DockAreaFlags flags);
/**
* Sets the dock area flag Flag on this widget if on is true; otherwise
* clears the flag.
*/
void setDockAreaFlag(eDockAreaFlag flag, bool on);
/**
* Returns true if the area has a single dock widget and contains the central widget of it's manager.
*/
bool isCentralWidgetArea() const;
/**
* Returns true if the area contains the central widget of it's manager.
*/
bool containsCentralWidget() const;
/**
* If this dock area is the one and only visible area in a container, then
* this function returns true
*/
bool isTopLevelArea() const;
/**
* This activates the tab for the given tab index.
* If the dock widget for the given tab is not visible, the this function
@@ -254,18 +364,24 @@ public:
*/
void closeArea();
/**
* Sets the dock area into auto hide mode or into normal mode.
* If the dock area is switched to auto hide mode, then all dock widgets
* that are pinable will be added to the sidebar
*/
void setAutoHide(bool enable, SideBarLocation location = SideBarNone);
/**
* Switches the dock area to auto hide mode or vice versa depending on its
* current state.
*/
void toggleAutoHide(SideBarLocation location = SideBarNone);
/**
* This function closes all other areas except of this area
*/
void closeOtherAreas();
/**
* Returns the largest minimumSizeHint() of the dock widgets in this
* area.
* The minimum size hint is updated if a dock widget is removed or added.
*/
QSize minimumSizeHint() const override;
signals:
/**
* This signal is emitted when user clicks on a tab at an index.

View File

@@ -3,46 +3,52 @@
#include "dockcomponentsfactory.h"
#include "dockwidgettab.h"
#include "autohidetab.h"
#include "dockareatabbar.h"
#include "dockareatitlebar.h"
#include "dockwidget.h"
#include "dockareawidget.h"
#include "dockwidget.h"
#include "dockwidgettab.h"
#include <memory>
namespace ADS
namespace ADS {
static std::unique_ptr<DockComponentsFactory> g_defaultFactory(new DockComponentsFactory());
DockWidgetTab *DockComponentsFactory::createDockWidgetTab(DockWidget *dockWidget) const
{
static std::unique_ptr<DockComponentsFactory> g_defaultFactory(new DockComponentsFactory());
return new DockWidgetTab(dockWidget);
}
DockWidgetTab *DockComponentsFactory::createDockWidgetTab(DockWidget *dockWidget) const
{
return new DockWidgetTab(dockWidget);
}
AutoHideTab *DockComponentsFactory::createDockWidgetSideTab(DockWidget *dockWidget) const
{
return new AutoHideTab(dockWidget);
}
DockAreaTabBar *DockComponentsFactory::createDockAreaTabBar(DockAreaWidget *dockArea) const
{
return new DockAreaTabBar(dockArea);
}
DockAreaTabBar *DockComponentsFactory::createDockAreaTabBar(DockAreaWidget *dockArea) const
{
return new DockAreaTabBar(dockArea);
}
DockAreaTitleBar *DockComponentsFactory::createDockAreaTitleBar(DockAreaWidget *dockArea) const
{
return new DockAreaTitleBar(dockArea);
}
DockAreaTitleBar *DockComponentsFactory::createDockAreaTitleBar(DockAreaWidget *dockArea) const
{
return new DockAreaTitleBar(dockArea);
}
const DockComponentsFactory *DockComponentsFactory::factory()
{
return g_defaultFactory.get();
}
const DockComponentsFactory *DockComponentsFactory::factory()
{
return g_defaultFactory.get();
}
void DockComponentsFactory::setFactory(DockComponentsFactory *factory)
{
g_defaultFactory.reset(factory);
}
void DockComponentsFactory::setFactory(DockComponentsFactory *factory)
{
g_defaultFactory.reset(factory);
}
void DockComponentsFactory::resetDefaultFactory()
{
g_defaultFactory.reset(new DockComponentsFactory());
}
void DockComponentsFactory::resetDefaultFactory()
{
g_defaultFactory.reset(new DockComponentsFactory());
}
} // namespace ADS

View File

@@ -12,6 +12,7 @@ class DockAreaTitleBar;
class DockAreaTabBar;
class DockAreaWidget;
class DockWidget;
class AutoHideTab;
/**
* Factory for creation of certain GUI elements for the docking framework.
@@ -37,6 +38,12 @@ public:
*/
virtual DockWidgetTab *createDockWidgetTab(DockWidget *dockWidget) const;
/**
* This default implementation just creates a dock widget side tab with
* new CDockWidgetTab(DockWidget).
*/
virtual AutoHideTab *createDockWidgetSideTab(DockWidget *dockWidget) const;
/**
* This default implementation just creates a dock area tab bar with
* new DockAreaTabBar(dockArea).

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
#pragma once
#include "ads_globals.h"
#include "autohidetab.h"
#include "dockwidget.h"
#include <QFrame>
@@ -24,13 +25,16 @@ class FloatingDockContainerPrivate;
class FloatingDragPreview;
class DockingStateReader;
class FloatingDragPreviewPrivate;
class AutoHideSideBar;
class AutoHideTab;
struct AutoHideTabPrivate;
struct AutoHideDockContainerPrivate;
class AutoHideDockContainer;
/**
* Container that manages a number of dock areas with single dock widgets
* or tabified dock widgets in each area.
* Each window that support docking has a DockContainerWidget. That means
* the main application window and all floating windows contain a
* DockContainerWidget instance.
* Container that manages a number of dock areas with single dock widgets or tabified dock widgets
* in each area. Each window that support docking has a DockContainerWidget. That means the main
* application window and all floating windows contain a DockContainerWidget instance.
*/
class ADS_EXPORT DockContainerWidget : public QFrame
{
@@ -47,6 +51,11 @@ private:
friend class DockWidget;
friend class FloatingDragPreview;
friend class FloatingDragPreviewPrivate;
friend AutoHideDockContainer;
friend AutoHideTab;
friend AutoHideTabPrivate;
friend AutoHideDockContainerPrivate;
friend AutoHideSideBar;
protected:
/**
@@ -59,11 +68,24 @@ protected:
*/
QSplitter *rootSplitter() const;
/**
* Creates and initializes a dockwidget auto hide container into the given area. Initializing
* inserts the tabs into the side tab widget and hides it
* Returns nullptr if you try and insert into an area where the configuration is not enabled
*/
AutoHideDockContainer *createAndSetupAutoHideContainer(SideBarLocation area,
DockWidget *dockWidget);
/**
* Helper function for creation of the root splitter
*/
void createRootSplitter();
/**
* Helper function for creation of the side tab bar widgets
*/
void createSideTabBarWidgets();
/**
* Drop floating widget into the container
*/
@@ -91,7 +113,7 @@ protected:
/**
* This function replaces the goto construct. Still need to write a good description.
*/
void emitAndExit() const; // TODO rename
void emitAndExit() const;
/**
* Saves the state into the given stream
@@ -134,6 +156,28 @@ protected:
*/
QList<DockWidget *> dockWidgets() const;
/**
* This function forces the dock container widget to update handles of splitters
* based on resize modes of dock widgets contained in the container.
*/
void updateSplitterHandles(QSplitter *splitter);
/**
* Registers the given floating widget in the internal list of auto hide widgets
*/
void registerAutoHideWidget(AutoHideDockContainer *autoHideWidget);
/**
* Remove the given auto hide widget from the list of registered auto hide widgets
*/
void removeAutoHideWidget(AutoHideDockContainer *autoHideWidget);
/**
* Handles widget events of auto hide widgets to trigger delayed show
* or hide actions for auto hide container on auto hide tab mouse over
*/
void handleAutoHideWidgetEvent(QEvent *e, QWidget *w);
public:
/**
* Default Constructor
@@ -154,7 +198,8 @@ public:
*/
DockAreaWidget *addDockWidget(DockWidgetArea area,
DockWidget *dockWidget,
DockAreaWidget *dockAreaWidget = nullptr);
DockAreaWidget *dockAreaWidget = nullptr,
int index = -1);
/**
* Removes dockwidget
@@ -190,6 +235,18 @@ public:
*/
QList<DockAreaWidget *> openedDockAreas() const;
/**
* Returns a list for all open dock widgets in all open dock areas
*/
QList<DockWidget *> openedDockWidgets() const;
/**
* This function returns true, if the container has open dock areas.
* This functions is a little bit faster than calling openedDockAreas().isEmpty()
* because it returns as soon as it finds an open dock area
*/
bool hasOpenDockAreas() const;
/**
* This function returns true if this dock area has only one single
* visible dock widget.
@@ -239,6 +296,34 @@ public:
*/
void closeOtherAreas(DockAreaWidget *keepOpenArea);
/**
* Returns the side tab widget for the given area
*/
AutoHideSideBar *sideTabBar(SideBarLocation area) const;
/**
* Access function for auto hide widgets
*/
QList<AutoHideDockContainer *> autoHideWidgets() const;
/**
* Returns the content rectangle without the autohide side bars
*/
QRect contentRect() const;
/**
* Returns the content rectangle mapped to global space.
* The content rectangle is the rectangle of the dock manager widget minus
* the auto hide side bars. So that means, it is the geometry of the
* internal root splitter mapped to global space.
*/
QRect contentRectGlobal() const;
/**
* Returns the dock manager that owns this container
*/
DockManager *dockManager() const;
signals:
/**
* This signal is emitted if one or multiple dock areas has been added to
@@ -247,6 +332,11 @@ signals:
*/
void dockAreasAdded();
/**
* This signal is emitted, if a new auto hide widget has been created.
*/
void autoHideWidgetCreated(AutoHideDockContainer *autoHideWidget);
/**
* This signal is emitted if one or multiple dock areas has been removed
*/

View File

@@ -3,250 +3,332 @@
#include "dockfocuscontroller.h"
#include "dockareawidget.h"
#include "ads_globals_p.h"
#include "dockareatitlebar.h"
#include "dockareawidget.h"
#include "dockcontainerwidget.h"
#include "dockmanager.h"
#include "dockwidget.h"
#include "dockwidgettab.h"
#include "floatingdockcontainer.h"
#ifdef Q_OS_LINUX
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
#include "linux/floatingwidgettitlebar.h"
#endif
#include <QApplication>
#include <QPointer>
#include <QWindow>
#include <algorithm>
#include <iostream>
namespace ADS
namespace ADS {
static const char *const g_focusedDockWidgetProperty = "FocusedDockWidget";
class DockFocusControllerPrivate
{
public:
DockFocusController *q;
QPointer<DockWidget> m_focusedDockWidget = nullptr;
QPointer<DockAreaWidget> m_focusedArea = nullptr;
QPointer<DockWidget> m_oldFocusedDockWidget = nullptr;
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
QPointer<FloatingDockContainer> m_floatingWidget = nullptr;
#endif
DockManager *m_dockManager = nullptr;
bool m_forceFocusChangedSignal = false;
bool m_tabPressed = false;
/**
* Private data class of CDockFocusController class (pimpl)
* Private data constructor
*/
class DockFocusControllerPrivate
{
public:
DockFocusController *q;
QPointer<DockWidget> m_focusedDockWidget = nullptr;
QPointer<DockAreaWidget> m_focusedArea = nullptr;
#ifdef Q_OS_LINUX
QPointer<FloatingDockContainer> m_floatingWidget = nullptr;
#endif
DockManager *m_dockManager = nullptr;
DockFocusControllerPrivate(DockFocusController *parent);
/**
* Private data constructor
*/
DockFocusControllerPrivate(DockFocusController *parent);
/**
* This function updates the focus style of the given dock widget and
* the dock area that it belongs to
*/
void updateDockWidgetFocus(DockWidget *dockWidget);
}; // class DockFocusControllerPrivate
/**
* This function updates the focus style of the given dock widget and
* the dock area that it belongs to
*/
void updateDockWidgetFocus(DockWidget *dockWidget);
}; // class DockFocusControllerPrivate
static void updateDockWidgetFocusStyle(DockWidget *dockWidget, bool focused)
{
dockWidget->setProperty("focused", focused);
dockWidget->tabWidget()->setProperty("focused", focused);
dockWidget->tabWidget()->updateStyle();
internal::repolishStyle(dockWidget);
}
static void updateDockWidgetFocusStyle(DockWidget *dockWidget, bool focused)
{
dockWidget->setProperty("focused", focused);
dockWidget->tabWidget()->setProperty("focused", focused);
dockWidget->tabWidget()->updateStyle();
internal::repolishStyle(dockWidget);
}
static void updateDockAreaFocusStyle(DockAreaWidget *dockArea, bool focused)
{
dockArea->setProperty("focused", focused);
internal::repolishStyle(dockArea);
internal::repolishStyle(dockArea->titleBar());
}
static void updateDockAreaFocusStyle(DockAreaWidget *dockArea, bool focused)
{
dockArea->setProperty("focused", focused);
internal::repolishStyle(dockArea);
internal::repolishStyle(dockArea->titleBar());
}
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
static void updateFloatingWidgetFocusStyle(FloatingDockContainer *floatingWidget, bool focused)
{
if (floatingWidget->hasNativeTitleBar())
return;
#ifdef Q_OS_LINUX
static void updateFloatingWidgetFocusStyle(FloatingDockContainer *floatingWidget, bool focused)
{
auto titleBar = qobject_cast<FloatingWidgetTitleBar *>(floatingWidget->titleBarWidget());
if (!titleBar)
return;
auto titleBar = qobject_cast<FloatingWidgetTitleBar *>(floatingWidget->titleBarWidget());
if (!titleBar)
return;
titleBar->setProperty("focused", focused);
titleBar->updateStyle();
}
titleBar->setProperty("focused", focused);
titleBar->updateStyle();
}
#endif
DockFocusControllerPrivate::DockFocusControllerPrivate(DockFocusController *parent)
: q(parent)
{}
DockFocusControllerPrivate::DockFocusControllerPrivate(DockFocusController *parent)
: q(parent)
{}
void DockFocusControllerPrivate::updateDockWidgetFocus(DockWidget *dockWidget)
{
DockAreaWidget *newFocusedDockArea = nullptr;
if (m_focusedDockWidget)
updateDockWidgetFocusStyle(m_focusedDockWidget, false);
void DockFocusControllerPrivate::updateDockWidgetFocus(DockWidget *dockWidget)
{
if (!dockWidget->features().testFlag(DockWidget::DockWidgetFocusable))
return;
DockWidget *old = m_focusedDockWidget;
m_focusedDockWidget = dockWidget;
updateDockWidgetFocusStyle(m_focusedDockWidget, true);
newFocusedDockArea = m_focusedDockWidget->dockAreaWidget();
if (newFocusedDockArea && (m_focusedArea != newFocusedDockArea))
{
if (m_focusedArea)
{
QObject::disconnect(m_focusedArea, &DockAreaWidget::viewToggled,
q, &DockFocusController::onFocusedDockAreaViewToggled);
updateDockAreaFocusStyle(m_focusedArea, false);
}
QWindow *window = nullptr;
auto dockContainer = dockWidget->dockContainer();
if (dockContainer)
window = dockContainer->window()->windowHandle();
m_focusedArea = newFocusedDockArea;
updateDockAreaFocusStyle(m_focusedArea, true);
QObject::connect(m_focusedArea, &DockAreaWidget::viewToggled,
q, &DockFocusController::onFocusedDockAreaViewToggled);
if (window)
window->setProperty(g_focusedDockWidgetProperty,
QVariant::fromValue(QPointer<DockWidget>(dockWidget)));
DockAreaWidget *newFocusedDockArea = nullptr;
if (m_focusedDockWidget)
updateDockWidgetFocusStyle(m_focusedDockWidget, false);
DockWidget *old = m_focusedDockWidget;
m_focusedDockWidget = dockWidget;
updateDockWidgetFocusStyle(m_focusedDockWidget, true);
newFocusedDockArea = m_focusedDockWidget->dockAreaWidget();
if (newFocusedDockArea && (m_focusedArea != newFocusedDockArea)) {
if (m_focusedArea) {
QObject::disconnect(m_focusedArea,
&DockAreaWidget::viewToggled,
q,
&DockFocusController::onFocusedDockAreaViewToggled);
updateDockAreaFocusStyle(m_focusedArea, false);
}
auto dockContainer = m_focusedDockWidget->dockContainer();
FloatingDockContainer *newFloatingWidget = nullptr;
m_focusedArea = newFocusedDockArea;
updateDockAreaFocusStyle(m_focusedArea, true);
QObject::connect(m_focusedArea,
&DockAreaWidget::viewToggled,
q,
&DockFocusController::onFocusedDockAreaViewToggled);
}
if (dockContainer)
newFloatingWidget = dockContainer->floatingWidget();
FloatingDockContainer *newFloatingWidget = nullptr;
dockContainer = m_focusedDockWidget->dockContainer();
if (dockContainer)
newFloatingWidget = dockContainer->floatingWidget();
if (newFloatingWidget)
newFloatingWidget->setProperty("FocusedDockWidget", QVariant::fromValue(dockWidget));
if (newFloatingWidget)
newFloatingWidget->setProperty(g_focusedDockWidgetProperty,
QVariant::fromValue(QPointer<DockWidget>(dockWidget)));
#ifdef Q_OS_LINUX
// This code is required for styling the floating widget titlebar for linux
// depending on the current focus state
if (m_floatingWidget == newFloatingWidget)
return;
if (m_floatingWidget)
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
// This code is required for styling the floating widget titlebar for linux
// depending on the current focus state
if (m_floatingWidget != newFloatingWidget) {
if (m_floatingWidget) {
updateFloatingWidgetFocusStyle(m_floatingWidget, false);
}
m_floatingWidget = newFloatingWidget;
if (m_floatingWidget)
if (m_floatingWidget) {
updateFloatingWidgetFocusStyle(m_floatingWidget, true);
}
}
#endif
if (old != dockWidget)
emit m_dockManager->focusedDockWidgetChanged(old, dockWidget);
if (old == dockWidget && !m_forceFocusChangedSignal)
return;
m_forceFocusChangedSignal = false;
if (dockWidget->isVisible()) {
emit m_dockManager->focusedDockWidgetChanged(old, dockWidget);
} else {
m_oldFocusedDockWidget = old;
QObject::connect(dockWidget,
&DockWidget::visibilityChanged,
q,
&DockFocusController::onDockWidgetVisibilityChanged);
}
}
DockFocusController::DockFocusController(DockManager *dockManager)
: QObject(dockManager)
, d(new DockFocusControllerPrivate(this))
{
d->m_dockManager = dockManager;
connect(qApp, &QApplication::focusChanged,
this, &DockFocusController::onApplicationFocusChanged);
connect(d->m_dockManager, &DockManager::stateRestored,
this, &DockFocusController::onStateRestored);
}
void DockFocusController::onDockWidgetVisibilityChanged(bool visible)
{
auto dockWidget = qobject_cast<DockWidget *>(sender());
QObject::disconnect(dockWidget,
&DockWidget::visibilityChanged,
this,
&DockFocusController::onDockWidgetVisibilityChanged);
if (dockWidget && visible)
emit d->m_dockManager->focusedDockWidgetChanged(d->m_oldFocusedDockWidget, dockWidget);
}
DockFocusController::~DockFocusController()
{
delete d;
}
DockFocusController::DockFocusController(DockManager *dockManager)
: QObject(dockManager)
, d(new DockFocusControllerPrivate(this))
{
d->m_dockManager = dockManager;
connect(qApp,
&QApplication::focusChanged,
this,
&DockFocusController::onApplicationFocusChanged);
connect(qApp,
&QApplication::focusWindowChanged,
this,
&DockFocusController::onFocusWindowChanged);
connect(d->m_dockManager,
&DockManager::stateRestored,
this,
&DockFocusController::onStateRestored);
}
void DockFocusController::onApplicationFocusChanged(QWidget *focusedOld, QWidget *focusedNow)
{
Q_UNUSED(focusedOld);
DockFocusController::~DockFocusController()
{
delete d;
}
if (d->m_dockManager->isRestoringState())
return;
void DockFocusController::onFocusWindowChanged(QWindow *focusWindow)
{
if (!focusWindow)
return;
if (!focusedNow)
return;
auto dockWidgetVar = focusWindow->property(g_focusedDockWidgetProperty);
if (!dockWidgetVar.isValid())
return;
DockWidget *dockWidget = nullptr;
auto dockWidgetTab = qobject_cast<DockWidgetTab *>(focusedNow);
if (dockWidgetTab)
dockWidget = dockWidgetTab->dockWidget();
auto dockWidget = dockWidgetVar.value<QPointer<DockWidget>>();
if (!dockWidget)
return;
if (!dockWidget)
dockWidget = qobject_cast<DockWidget *>(focusedNow);
d->updateDockWidgetFocus(dockWidget);
}
bool focusActual = dockWidget && dockWidget->widget();
void DockFocusController::onApplicationFocusChanged(QWidget *focusedOld, QWidget *focusedNow)
{
Q_UNUSED(focusedOld);
if (!dockWidget)
dockWidget = internal::findParent<DockWidget *>(focusedNow);
// Ignore focus changes if we are restoring state, or if user clicked a tab which in turn
// caused the focus change.
if (d->m_dockManager->isRestoringState() || d->m_tabPressed)
return;
#ifdef Q_OS_LINUX
if (!dockWidget)
return;
#else
if (!dockWidget || dockWidget->tabWidget()->isHidden())
return;
#endif
qCInfo(adsLog) << Q_FUNC_INFO << "old: " << focusedOld << "new:" << focusedNow;
if (!focusedNow)
return;
DockWidget *dockWidget = qobject_cast<DockWidget *>(focusedNow);
if (!dockWidget)
dockWidget = internal::findParent<DockWidget *>(focusedNow);
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
if (!dockWidget)
return;
#else
if (!dockWidget || dockWidget->tabWidget()->isHidden())
return;
#endif
d->updateDockWidgetFocus(dockWidget);
}
void DockFocusController::setDockWidgetTabFocused(DockWidgetTab *tab)
{
auto dockWidget = tab->dockWidget();
if (dockWidget)
d->updateDockWidgetFocus(dockWidget);
}
if (focusActual) {
// Do this async to avoid issues when changing focus in middle of another focus handling
QMetaObject::invokeMethod(dockWidget->widget(), QOverload<>::of(&QWidget::setFocus),
Qt::QueuedConnection);
}
void DockFocusController::clearDockWidgetFocus(DockWidget *dockWidget)
{
dockWidget->clearFocus();
updateDockWidgetFocusStyle(dockWidget, false);
}
void DockFocusController::setDockWidgetFocused(DockWidget *focusedNow)
{
d->updateDockWidgetFocus(focusedNow);
}
void DockFocusController::onFocusedDockAreaViewToggled(bool open)
{
if (d->m_dockManager->isRestoringState() || !d->m_focusedArea || open)
return;
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(sender());
if (!dockArea || open)
return;
auto container = dockArea->dockContainer();
auto openedDockAreas = container->openedDockAreas();
if (openedDockAreas.isEmpty())
return;
d->updateDockWidgetFocus(openedDockAreas[0]->currentDockWidget());
}
void DockFocusController::notifyWidgetOrAreaRelocation(QWidget *droppedWidget)
{
if (d->m_dockManager->isRestoringState())
return;
DockWidget *dockWidget = qobject_cast<DockWidget *>(droppedWidget);
if (!dockWidget) {
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(droppedWidget);
if (dockArea)
dockWidget = dockArea->currentDockWidget();
}
void DockFocusController::setDockWidgetFocused(DockWidget *focusedNow)
{
d->updateDockWidgetFocus(focusedNow);
}
if (!dockWidget)
return;
void DockFocusController::onFocusedDockAreaViewToggled(bool open)
{
if (d->m_dockManager->isRestoringState() || !d->m_focusedArea || open)
return;
d->m_forceFocusChangedSignal = true;
DockManager::setWidgetFocus(dockWidget);
}
auto container = d->m_focusedArea->dockContainer();
auto openedDockAreas = container->openedDockAreas();
if (openedDockAreas.isEmpty())
return;
void DockFocusController::notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget)
{
if (!floatingWidget || d->m_dockManager->isRestoringState())
return;
DockManager::setWidgetFocus(openedDockAreas[0]->currentDockWidget()->tabWidget());
}
auto dockWidgetVar = floatingWidget->property(g_focusedDockWidgetProperty);
if (!dockWidgetVar.isValid())
return;
void DockFocusController::notifyWidgetOrAreaRelocation(QWidget *droppedWidget)
{
if (d->m_dockManager->isRestoringState())
return;
DockWidget *dockWidget = qobject_cast<DockWidget *>(droppedWidget);
if (dockWidget)
{
DockManager::setWidgetFocus(dockWidget->tabWidget());
return;
}
DockAreaWidget* dockArea = qobject_cast<DockAreaWidget*>(droppedWidget);
if (!dockArea)
return;
dockWidget = dockArea->currentDockWidget();
auto dockWidget = dockWidgetVar.value<DockWidget *>();
if (dockWidget) {
dockWidget->dockAreaWidget()->setCurrentDockWidget(dockWidget);
DockManager::setWidgetFocus(dockWidget->tabWidget());
}
}
void DockFocusController::notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget)
{
if (!floatingWidget || d->m_dockManager->isRestoringState())
return;
void DockFocusController::onStateRestored()
{
if (d->m_focusedDockWidget)
updateDockWidgetFocusStyle(d->m_focusedDockWidget, false);
}
auto vDockWidget = floatingWidget->property("FocusedDockWidget");
if (!vDockWidget.isValid())
return;
DockWidget *DockFocusController::focusedDockWidget() const
{
return d->m_focusedDockWidget.data();
}
auto dockWidget = vDockWidget.value<DockWidget *>();
if (dockWidget) {
dockWidget->dockAreaWidget()->setCurrentDockWidget(dockWidget);
DockManager::setWidgetFocus(dockWidget->tabWidget());
}
}
void DockFocusController::onStateRestored()
{
if (d->m_focusedDockWidget)
updateDockWidgetFocusStyle(d->m_focusedDockWidget, false);
}
void DockFocusController::setDockWidgetTabPressed(bool value)
{
d->m_tabPressed = value;
}
} // namespace ADS

View File

@@ -27,8 +27,10 @@ private:
private:
void onApplicationFocusChanged(QWidget *old, QWidget *now);
void onFocusWindowChanged(QWindow *focusWindow);
void onFocusedDockAreaViewToggled(bool open);
void onStateRestored();
void onDockWidgetVisibilityChanged(bool visible);
public:
/**
@@ -41,19 +43,6 @@ public:
*/
~DockFocusController() override;
/**
* Helper function to set focus depending on the configuration of the
* FocusStyling flag
*/
template <class QWidgetPtr>
static void setWidgetFocus(QWidgetPtr widget)
{
if (!DockManager::testConfigFlag(DockManager::FocusHighlighting))
return;
widget->setFocus(Qt::OtherFocusReason);
}
/**
* A container needs to call this function if a widget has been dropped
* into it
@@ -68,6 +57,28 @@ public:
*/
void notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget);
/**
* Returns the dock widget that has focus style in the ui or a nullptr if
* not dock widget is painted focused.
*/
DockWidget *focusedDockWidget() const;
/**
* Notifies the dock focus controller, that a the mouse is pressed or released.
*/
void setDockWidgetTabPressed(bool value);
/**
* Request focus highlighting for the given dock widget assigned to the tab
* given in Tab parameter
*/
void setDockWidgetTabFocused(DockWidgetTab *tab);
/*
* Request clear focus for a dock widget
*/
void clearDockWidgetFocus(DockWidget *dockWidget);
/**
* Request a focus change to the given dock widget
*/

View File

@@ -4,12 +4,14 @@
#include "dockmanager.h"
#include "ads_globals.h"
#include "advanceddockingsystemtr.h"
#include "ads_globals_p.h"
#include "advanceddockingsystemtr.h"
#include "autohidedockcontainer.h"
#include "dockareawidget.h"
#include "dockfocuscontroller.h"
#include "dockingstatereader.h"
#include "dockoverlay.h"
#include "docksplitter.h"
#include "dockwidget.h"
#include "floatingdockcontainer.h"
#include "iconprovider.h"
@@ -40,8 +42,13 @@
#include <QMessageBox>
#include <QSettings>
#include <QVariant>
#include <QWindow>
#include <QXmlStreamWriter>
#if !(defined(Q_OS_UNIX) && !defined(Q_OS_MACOS))
#include <QWindowStateChangeEvent>
#endif
Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg);
using namespace Utils;
@@ -57,6 +64,9 @@ enum eStateFileVersion {
};
static DockManager::ConfigFlags g_staticConfigFlags = DockManager::DefaultNonOpaqueConfig;
static DockManager::AutoHideFlags g_staticAutoHideConfigFlags; // auto hide is disabled by default
static QString g_floatingContainersTitle;
/**
* Private data class of DockManager class (pimpl)
@@ -66,6 +76,7 @@ class DockManagerPrivate
public:
DockManager *q;
QList<QPointer<FloatingDockContainer>> m_floatingWidgets;
QList<QPointer<FloatingDockContainer>> m_hiddenFloatingWidgets;
QList<DockContainerWidget *> m_containers;
DockOverlay *m_containerOverlay = nullptr;
DockOverlay *m_dockAreaOverlay = nullptr;
@@ -73,6 +84,8 @@ public:
bool m_restoringState = false;
QVector<FloatingDockContainer *> m_uninitializedFloatingWidgets;
DockFocusController *m_focusController = nullptr;
DockWidget *m_centralWidget = nullptr;
bool m_isLeavingMinimized = false;
QString m_workspacePresetsPath;
QList<Workspace> m_workspaces;
@@ -114,7 +127,7 @@ public:
void markDockWidgetsDirty()
{
for (const auto &dockWidget : std::as_const(m_dockWidgetsMap))
dockWidget->setProperty("dirty", true);
dockWidget->setProperty(internal::g_dirtyProperty, true);
}
/**
@@ -180,11 +193,27 @@ bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int versio
return false;
}
qCInfo(adsLog) << stateReader.attributes().value("containers").toInt();
if (m_centralWidget) {
const auto centralWidgetAttribute = stateReader.attributes().value("centralWidget");
// If we have a central widget, but a state without central widget, then something is wrong.
if (centralWidgetAttribute.isEmpty()) {
qWarning()
<< "DockManager has central widget, but saved state does not have central widget.";
return false;
}
// If the object name of the central widget does not match the name of the saved central
// widget, something is wrong.
if (m_centralWidget->objectName() != centralWidgetAttribute.toString()) {
qWarning() << "Object name of central widget does not match name of central widget in "
"saved state.";
return false;
}
}
bool result = true;
#ifdef ADS_DEBUG_PRINT
int dockContainers = stateReader.attributes().value("containers").toInt();
qCInfo(adsLog) << dockContainers;
#endif
int dockContainerCount = 0;
while (stateReader.readNextStartElement()) {
if (stateReader.name() == QLatin1String("container")) {
@@ -199,10 +228,10 @@ bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int versio
if (!testing) {
// Delete remaining empty floating widgets
int floatingWidgetIndex = dockContainerCount - 1;
int deleteCount = m_floatingWidgets.count() - floatingWidgetIndex;
for (int i = 0; i < deleteCount; ++i) {
m_floatingWidgets[floatingWidgetIndex + i]->deleteLater();
q->removeDockContainer(m_floatingWidgets[floatingWidgetIndex + i]->dockContainer());
for (int i = floatingWidgetIndex; i < m_floatingWidgets.count(); ++i) {
QPointer<FloatingDockContainer> floatingWidget = m_floatingWidgets[i];
q->removeDockContainer(floatingWidget->dockContainer());
floatingWidget->deleteLater();
}
}
@@ -215,11 +244,17 @@ void DockManagerPrivate::restoreDockWidgetsOpenState()
// 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 : std::as_const(m_dockWidgetsMap)) {
if (dockWidget->property(internal::dirtyProperty).toBool()) {
if (dockWidget->property(internal::g_dirtyProperty).toBool()) {
// If the DockWidget is an auto hide widget that is not assigned yet,
// then we need to delete the auto hide container now
if (dockWidget->isAutoHide())
dockWidget->autoHideDockContainer()->cleanupAndDelete();
dockWidget->flagAsUnassigned();
emit dockWidget->viewToggled(false);
} else {
dockWidget->toggleViewInternal(!dockWidget->property(internal::closedProperty).toBool());
dockWidget->toggleViewInternal(
!dockWidget->property(internal::g_closedProperty).toBool());
}
}
}
@@ -251,7 +286,7 @@ void DockManagerPrivate::restoreDockAreasIndices()
void DockManagerPrivate::emitTopLevelEvents()
{
// Finally we need to send the topLevelChanged() signals for all dock widgets if top
// Finally we need to send the topLevelChanged() signal for all dock widgets if top
// level changed.
for (auto dockContainer : std::as_const(m_containers)) {
DockWidget *topLevelDockWidget = dockContainer->topLevelDockWidget();
@@ -288,6 +323,7 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version)
restoreDockWidgetsOpenState();
restoreDockAreasIndices();
emitTopLevelEvents();
q->dumpLayout();
return true;
}
@@ -301,6 +337,7 @@ DockManager::DockManager(QWidget *parent)
});
createRootSplitter();
createSideTabBarWidgets();
QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parent);
if (mainWindow)
mainWindow->setCentralWidget(this);
@@ -311,6 +348,17 @@ DockManager::DockManager(QWidget *parent)
if (DockManager::configFlags().testFlag(DockManager::FocusHighlighting))
d->m_focusController = new DockFocusController(this);
window()->installEventFilter(this);
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
connect(qApp, &QApplication::focusWindowChanged, this, [](QWindow *focusWindow) {
// Bring modal dialogs to foreground to ensure that they are in front of any
// floating dock widget.
if (focusWindow && focusWindow->isModal())
focusWindow->raise();
});
#endif
}
DockManager::~DockManager()
@@ -319,6 +367,18 @@ DockManager::~DockManager()
save();
saveStartupWorkspace();
// Fix memory leaks, see https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/issues/307
std::vector<ADS::DockAreaWidget *> areas;
for (int i = 0; i != dockAreaCount(); ++i)
areas.push_back(dockArea(i));
for (auto area : areas) {
for (auto widget : area->dockWidgets())
delete widget;
delete area;
}
// Using a temporary vector since the destructor of FloatingDockWidgetContainer
// alters d->m_floatingWidgets.
const auto copy = d->m_floatingWidgets;
@@ -334,21 +394,41 @@ DockManager::ConfigFlags DockManager::configFlags()
return g_staticConfigFlags;
}
DockManager::AutoHideFlags DockManager::autoHideConfigFlags()
{
return g_staticAutoHideConfigFlags;
}
void DockManager::setConfigFlags(const ConfigFlags flags)
{
g_staticConfigFlags = flags;
}
void DockManager::setAutoHideConfigFlags(const AutoHideFlags flags)
{
g_staticAutoHideConfigFlags = flags;
}
void DockManager::setConfigFlag(eConfigFlag flag, bool on)
{
internal::setFlag(g_staticConfigFlags, flag, on);
}
void DockManager::setAutoHideConfigFlag(eAutoHideFlag flag, bool on)
{
internal::setFlag(g_staticAutoHideConfigFlags, flag, on);
}
bool DockManager::testConfigFlag(eConfigFlag flag)
{
return configFlags().testFlag(flag);
}
bool DockManager::testAutoHideConfigFlag(eAutoHideFlag flag)
{
return autoHideConfigFlags().testFlag(flag);
}
IconProvider &DockManager::iconProvider()
{
static IconProvider instance;
@@ -372,10 +452,9 @@ void DockManager::setWorkspacePresetsPath(const QString &path)
void DockManager::initialize()
{
qCInfo(adsLog) << "Initialize DockManager";
qCInfo(adsLog) << Q_FUNC_INFO;
// Can't continue if settings are not set yet
QTC_ASSERT(d->m_settings, return);
QTC_ASSERT(d->m_settings, return); // Can't continue if settings are not set yet
syncWorkspacePresets();
prepareWorkspaces();
@@ -414,10 +493,40 @@ void DockManager::initialize()
DockAreaWidget *DockManager::addDockWidget(DockWidgetArea area,
DockWidget *dockWidget,
DockAreaWidget *dockAreaWidget)
DockAreaWidget *dockAreaWidget,
int index)
{
d->m_dockWidgetsMap.insert(dockWidget->objectName(), dockWidget);
return DockContainerWidget::addDockWidget(area, dockWidget, dockAreaWidget);
auto container = dockAreaWidget ? dockAreaWidget->dockContainer() : this;
auto dockArea = container->addDockWidget(area, dockWidget, dockAreaWidget, index);
emit dockWidgetAdded(dockWidget);
return dockArea;
}
DockAreaWidget *DockManager::addDockWidgetToContainer(DockWidgetArea area,
DockWidget *dockWidget,
DockContainerWidget *dockContainerWidget)
{
d->m_dockWidgetsMap.insert(dockWidget->objectName(), dockWidget);
auto dockArea = dockContainerWidget->addDockWidget(area, dockWidget);
emit dockWidgetAdded(dockWidget);
return dockArea;
}
AutoHideDockContainer *DockManager::addAutoHideDockWidget(SideBarLocation location,
DockWidget *dockWidget)
{
return addAutoHideDockWidgetToContainer(location, dockWidget, this);
}
AutoHideDockContainer *DockManager::addAutoHideDockWidgetToContainer(
SideBarLocation location, DockWidget *dockWidget, DockContainerWidget *dockContainerWidget)
{
d->m_dockWidgetsMap.insert(dockWidget->objectName(), dockWidget);
auto container = dockContainerWidget->createAndSetupAutoHideContainer(location, dockWidget);
container->collapseView(true);
emit dockWidgetAdded(dockWidget);
return container;
}
DockAreaWidget *DockManager::addDockWidgetTab(DockWidgetArea area, DockWidget *dockWidget)
@@ -426,15 +535,16 @@ DockAreaWidget *DockManager::addDockWidgetTab(DockWidgetArea area, DockWidget *d
if (areaWidget)
return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, areaWidget);
else if (!openedDockAreas().isEmpty())
return addDockWidget(area, dockWidget, openedDockAreas().constLast());
return addDockWidget(area, dockWidget, openedDockAreas().constLast()); // TODO
else
return addDockWidget(area, dockWidget, nullptr);
}
DockAreaWidget *DockManager::addDockWidgetTabToArea(DockWidget *dockWidget,
DockAreaWidget *dockAreaWidget)
DockAreaWidget *dockAreaWidget,
int index)
{
return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, dockAreaWidget);
return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, dockAreaWidget, index);
}
FloatingDockContainer *DockManager::addDockWidgetFloating(DockWidget *dockWidget)
@@ -452,6 +562,7 @@ FloatingDockContainer *DockManager::addDockWidgetFloating(DockWidget *dockWidget
else
d->m_uninitializedFloatingWidgets.append(floatingWidget);
emit dockWidgetAdded(dockWidget);
return floatingWidget;
}
@@ -465,6 +576,7 @@ void DockManager::removeDockWidget(DockWidget *dockWidget)
emit dockWidgetAboutToBeRemoved(dockWidget);
d->m_dockWidgetsMap.remove(dockWidget->objectName());
DockContainerWidget::removeDockWidget(dockWidget);
dockWidget->setDockManager(nullptr);
emit dockWidgetRemoved(dockWidget);
}
@@ -503,6 +615,10 @@ QByteArray DockManager::saveState(const QString &displayName, int version) const
stream.writeAttribute("userVersion", QString::number(version));
stream.writeAttribute("containers", QString::number(d->m_containers.count()));
stream.writeAttribute(workspaceDisplayNameAttribute.toString(), displayName);
if (d->m_centralWidget)
stream.writeAttribute("centralWidget", d->m_centralWidget->objectName());
for (auto container : std::as_const(d->m_containers))
container->saveState(stream);
@@ -544,12 +660,185 @@ bool DockManager::isRestoringState() const
return d->m_restoringState;
}
bool DockManager::isLeavingMinimizedState() const
{
return d->m_isLeavingMinimized;
}
bool DockManager::eventFilter(QObject *obj, QEvent *event)
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
// Emulate Qt:Tool behavior.
/*
// Window always on top of the MainWindow.
if (event->type() == QEvent::WindowActivate) {
for (auto &floatingWidget : floatingWidgets()) {
if (!floatingWidget->isVisible() || window()->isMinimized())
continue;
// setWindowFlags(Qt::WindowStaysOnTopHint) will hide the window and thus requires
// a show call. This then leads to flickering and a nasty endless loop (also buggy
// behavior on Ubuntu). So we just do it ourself.
floatingWidget->setWindowFlag(Qt::WindowStaysOnTopHint, true);
}
} else if (event->type() == QEvent::WindowDeactivate) {
for (auto &floatingWidget : floatingWidgets()) {
if (!floatingWidget->isVisible() || window()->isMinimized())
continue;
floatingWidget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
floatingWidget->raise();
}
}
*/
// Sync minimize with MainWindow
if (event->type() == QEvent::WindowStateChange) {
for (auto &floatingWidget : floatingWidgets()) {
if (!floatingWidget->isVisible())
continue;
if (window()->isMinimized())
floatingWidget->showMinimized();
else
floatingWidget->setWindowState(floatingWidget->windowState()
& (~Qt::WindowMinimized));
}
if (!window()->isMinimized())
QApplication::setActiveWindow(window());
}
return Super::eventFilter(obj, event);
#else
if (event->type() == QEvent::WindowStateChange) {
QWindowStateChangeEvent *ev = static_cast<QWindowStateChangeEvent *>(event);
if (ev->oldState().testFlag(Qt::WindowMinimized)) {
d->m_isLeavingMinimized = true;
QMetaObject::invokeMethod(this, "endLeavingMinimizedState", Qt::QueuedConnection);
}
}
return Super::eventFilter(obj, event);
#endif
}
DockWidget *DockManager::focusedDockWidget() const
{
if (!d->m_focusController)
return nullptr;
else
return d->m_focusController->focusedDockWidget();
}
QList<int> DockManager::splitterSizes(DockAreaWidget *containedArea) const
{
if (containedArea) {
auto splitter = internal::findParent<DockSplitter *>(containedArea);
if (splitter)
return splitter->sizes();
}
return QList<int>();
}
void DockManager::setSplitterSizes(DockAreaWidget *containedArea, const QList<int> &sizes)
{
if (!containedArea)
return;
auto splitter = internal::findParent<DockSplitter *>(containedArea);
if (splitter && splitter->count() == sizes.count())
splitter->setSizes(sizes);
}
void DockManager::setFloatingContainersTitle(const QString &title)
{
g_floatingContainersTitle = title;
}
QString DockManager::floatingContainersTitle()
{
if (g_floatingContainersTitle.isEmpty())
return qApp->applicationDisplayName();
return g_floatingContainersTitle;
}
DockWidget *DockManager::centralWidget() const
{
return d->m_centralWidget;
}
DockAreaWidget *DockManager::setCentralWidget(DockWidget *widget)
{
if (!widget) {
d->m_centralWidget = nullptr;
return nullptr;
}
// Setting a new central widget is now allowed if there is already a central widget or
// if there are already other dock widgets.
if (d->m_centralWidget) {
qWarning(
"Setting a central widget not possible because there is already a central widget.");
return nullptr;
}
// Setting a central widget is now allowed if there are already other dock widgets.
if (!d->m_dockWidgetsMap.isEmpty()) {
qWarning("Setting a central widget not possible - the central widget need to be the first "
"dock widget that is added to the dock manager.");
return nullptr;
}
widget->setFeature(DockWidget::DockWidgetClosable, false);
widget->setFeature(DockWidget::DockWidgetMovable, false);
widget->setFeature(DockWidget::DockWidgetFloatable, false);
widget->setFeature(DockWidget::DockWidgetPinnable, false);
d->m_centralWidget = widget;
DockAreaWidget *centralArea = addDockWidget(CenterDockWidgetArea, widget);
centralArea->setDockAreaFlag(DockAreaWidget::eDockAreaFlag::HideSingleWidgetTitleBar, true);
return centralArea;
}
void DockManager::setDockWidgetFocused(DockWidget *dockWidget)
{
if (d->m_focusController)
d->m_focusController->setDockWidgetFocused(dockWidget);
}
void DockManager::hideManagerAndFloatingWidgets()
{
hide();
d->m_hiddenFloatingWidgets.clear();
// Hide updates of floating widgets from user.
for (auto &floatingWidget : d->m_floatingWidgets) {
if (floatingWidget->isVisible()) {
QList<DockWidget *> visibleWidgets;
for (auto dockWidget : floatingWidget->dockWidgets()) {
if (dockWidget->toggleViewAction()->isChecked())
visibleWidgets.push_back(dockWidget);
}
// Save as floating widget to be shown when DockManager will be shown back.
d->m_hiddenFloatingWidgets.push_back(floatingWidget);
floatingWidget->hide();
// Hidding floating widget automatically marked contained DockWidgets as hidden
// but they must remain marked as visible as we want them to be restored visible
// when DockManager will be shown back.
for (auto dockWidget : visibleWidgets)
dockWidget->toggleViewAction()->setChecked(true);
}
}
}
void DockManager::endLeavingMinimizedState()
{
d->m_isLeavingMinimized = false;
this->activateWindow();
}
void DockManager::registerFloatingWidget(FloatingDockContainer *floatingWidget)
{
d->m_floatingWidgets.append(floatingWidget);
@@ -602,15 +891,53 @@ void DockManager::notifyDockAreaRelocation(DockAreaWidget *, DockContainerWidget
void DockManager::showEvent(QShowEvent *event)
{
Super::showEvent(event);
// Fix issue #380
restoreHiddenFloatingWidgets();
if (d->m_uninitializedFloatingWidgets.empty())
return;
for (auto floatingWidget : std::as_const(d->m_uninitializedFloatingWidgets))
floatingWidget->show();
for (auto floatingWidget : std::as_const(d->m_uninitializedFloatingWidgets)) {
// Check, if someone closed a floating dock widget before the dock manager is shown.
if (floatingWidget->dockContainer()->hasOpenDockAreas())
floatingWidget->show();
}
d->m_uninitializedFloatingWidgets.clear();
}
DockFocusController *DockManager::dockFocusController() const
{
return d->m_focusController;
}
void DockManager::restoreHiddenFloatingWidgets()
{
if (d->m_hiddenFloatingWidgets.isEmpty())
return;
// Restore floating widgets that were hidden upon hideManagerAndFloatingWidgets
for (auto &floatingWidget : d->m_hiddenFloatingWidgets) {
bool hasDockWidgetVisible = false;
// Needed to prevent FloatingDockContainer being shown empty
// Could make sense to move this to FloatingDockContainer::showEvent(QShowEvent *event)
// if experiencing FloatingDockContainer being shown empty in other situations, but let's keep
// it here for now to make sure changes to fix Issue #380 does not impact existing behaviours
for (auto dockWidget : floatingWidget->dockWidgets()) {
if (dockWidget->toggleViewAction()->isChecked()) {
dockWidget->toggleView(true);
hasDockWidgetVisible = true;
}
}
if (hasDockWidgetVisible)
floatingWidget->show();
}
d->m_hiddenFloatingWidgets.clear();
}
Workspace *DockManager::activeWorkspace() const
{
return &d->m_workspace;

View File

@@ -46,6 +46,8 @@ class DockWidgetTab;
class DockWidgetTabPrivate;
struct DockAreaWidgetPrivate;
class IconProvider;
class DockFocusController;
class AutoHideSideBar;
inline constexpr QStringView workspaceFolderName{u"workspaces"};
inline constexpr QStringView workspaceFileExtension{u"wrk"};
@@ -80,6 +82,8 @@ private:
friend class FloatingDragPreview;
friend class FloatingDragPreviewPrivate;
friend class DockAreaTitleBar;
friend class AutoHideDockContainer;
friend AutoHideSideBar;
public:
using Super = DockContainerWidget;
@@ -105,8 +109,6 @@ public:
= 0x0080, //!< if this flag is set, then all tabs that are closable show a close button
RetainTabSizeWhenCloseButtonHidden
= 0x0100, //!< if this flag is set, the space for the close button is reserved even if the close button is not visible
OpaqueUndocking
= 0x0200, ///< If enabled, the widgets are immediately undocked into floating widgets, if disabled, only a draw preview is undocked and the real undocking is deferred until the mouse is released
DragPreviewIsDynamic
= 0x0400, ///< If opaque undocking is disabled, this flag defines the behavior of the drag preview window, if this flag is enabled, the preview will be adjusted dynamically to the drop area
DragPreviewShowsContentPixmap
@@ -117,34 +119,38 @@ public:
= 0x2000, ///< If this option is enabled, the tab of a dock widget is always displayed - even if it is the only visible dock widget in a floating widget.
DockAreaHasUndockButton = 0x4000, //!< If the flag is set each dock area has an undock button
DockAreaHasTabsMenuButton
= 0x8000, //!< If the flag is set each dock area has a tabs menu button
= 0x8000, //!< If the flag is set each dock area has a tabs menu button
DockAreaHideDisabledButtons
= 0x10000, //!< If the flag is set disabled dock area buttons will not appear on the tollbar at all (enabling them will bring them back)
= 0x10000, //!< If the flag is set disabled dock area buttons will not appear on the toolbar at all (enabling them will bring them back)
DockAreaDynamicTabsMenuButtonVisibility
= 0x20000, //!< If the flag is set, the tabs menu button will be shown only when it is required - that means, if the tabs are elided. If the tabs are not elided, it is hidden
FloatingContainerHasWidgetTitle
= 0x40000, //!< If set, the Floating Widget window title reflects the title of the current dock widget otherwise it displays application name as window title
= 0x40000, //!< If set, the Floating Widget window title reflects the title of the current dock widget otherwise it displays the title set with `CDockManager::setFloatingContainersTitle` or application name as window title
FloatingContainerHasWidgetIcon
= 0x80000, //!< If set, the Floating Widget icon reflects the icon of the current dock widget otherwise it displays application icon
HideSingleCentralWidgetTitleBar
= 0x100000, //!< If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden
//!< this only makes sense for non draggable and non floatable widgets and enables the creation of some kind of "central" widget
FocusHighlighting
= 0x200000, //!< enables styling of focused dock widget tabs or floating widget titlebar
EqualSplitOnInsertion
= 0x400000, ///!< if enabled, the space is equally distributed to all widgets in a splitter
= 0x400000, ///!< if enabled, the space is equally distributed to all widgets in a splitter
MiddleMouseButtonClosesTab
= 0x2000000, //! If the flag is set, the user can use the mouse middle button to close the tab under the mouse
DefaultDockAreaButtons
= DockAreaHasCloseButton | DockAreaHasUndockButton
| DockAreaHasTabsMenuButton, ///< default configuration of dock area title bar buttons
DefaultBaseConfig = DefaultDockAreaButtons | ActiveTabHasCloseButton
| XmlAutoFormattingEnabled
| FloatingContainerHasWidgetTitle, ///< default base configuration settings
DefaultBaseConfig
= DefaultDockAreaButtons | ActiveTabHasCloseButton | XmlAutoFormattingEnabled
| FloatingContainerHasWidgetTitle, ///< default base configuration settings
DefaultOpaqueConfig
= DefaultBaseConfig | OpaqueSplitterResize
| OpaqueUndocking, ///< the default configuration with opaque operations - this may cause issues if ActiveX or Qt 3D windows are involved
| DragPreviewShowsContentPixmap, ///< the default configuration for non opaque operations
DefaultNonOpaqueConfig
= DefaultBaseConfig
@@ -156,6 +162,31 @@ public:
};
Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag)
/**
* These global configuration flags configure some dock manager auto hide settings.
* Set the dock manager flags, before you create the dock manager instance.
*/
enum eAutoHideFlag {
AutoHideFeatureEnabled = 0x01, //!< enables / disables auto hide feature
DockAreaHasAutoHideButton
= 0x02, //!< If the flag is set each dock area has a auto hide menu button
AutoHideButtonTogglesArea
= 0x04, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled
AutoHideButtonCheckable
= 0x08, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes.
AutoHideSideBarsIconOnly
= 0x10, ///< show only icons in auto hide side tab - if a tab has no icon, then the text will be shown
AutoHideShowOnMouseOver
= 0x20, ///< show the auto hide window on mouse over tab and hide it if mouse leaves auto hide container
AutoHideCloseButtonCollapsesDock
= 0x40, ///< Close button of an auto hide container collapses the dock instead of hiding it completely
DefaultAutoHideConfig
= AutoHideFeatureEnabled
| DockAreaHasAutoHideButton ///< the default configuration for left and right side bars
};
Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag)
/**
* Default Constructor.
* If the given parent is a QMainWindow, the dock manager sets itself as the central widget.
@@ -174,23 +205,45 @@ public:
*/
static ConfigFlags configFlags();
/**
* This function returns the auto hide configuration flags.
*/
static AutoHideFlags autoHideConfigFlags();
/**
* Sets the global configuration flags for the whole docking system. Call this function before
* you create the dock manager and before your create the first dock widget.
*/
static void setConfigFlags(const ConfigFlags flags);
/**
* Sets the global configuration flags for the whole docking system. Call this function before
* you create the dock manager and before your create the first dock widget.
*/
static void setAutoHideConfigFlags(const AutoHideFlags flags);
/**
* Set a certain config flag.
* \see setConfigFlags()
*/
static void setConfigFlag(eConfigFlag flag, bool on = true);
/**
* Set a certain overlay config flag.
* \see setConfigFlags()
*/
static void setAutoHideConfigFlag(eAutoHideFlag flag, bool on = true);
/**
* Returns true if the given config flag is set.
*/
static bool testConfigFlag(eConfigFlag flag);
/**
* Returns true if the given overlay config flag is set
*/
static bool testAutoHideConfigFlag(eAutoHideFlag flag);
/**
* Returns the global icon provider.
* The icon provider enables the use of custom icons in case using styleheets for icons is not
@@ -242,7 +295,33 @@ public:
*/
DockAreaWidget *addDockWidget(DockWidgetArea area,
DockWidget *dockWidget,
DockAreaWidget *dockAreaWidget = nullptr);
DockAreaWidget *dockAreaWidget = nullptr,
int index = -1);
/**
* Adds dockwidget into the given container.
* This allows you to place the dock widget into a container, even if that
* container does not yet contain a DockAreaWidget.
* \return Returns the dock area widget that contains the new DockWidget
*/
DockAreaWidget *addDockWidgetToContainer(DockWidgetArea area,
DockWidget *dockWidget,
DockContainerWidget *dockContainerWidget);
/**
* Adds an Auto-Hide widget to the dock manager container pinned to
* the given side bar location.
* \return Returns the CAutoHideDockContainer that contains the new DockWidget
*/
AutoHideDockContainer *addAutoHideDockWidget(SideBarLocation location, DockWidget *dockWidget);
/**
* Adds an Auto-Hide widget to the given DockContainerWidget pinned to
* the given side bar location in this container.
* \return Returns the CAutoHideDockContainer that contains the new DockWidget
*/
AutoHideDockContainer *addAutoHideDockWidgetToContainer(
SideBarLocation location, DockWidget *dockWidget, DockContainerWidget *dockContainerWidget);
/**
* This function will add the given Dockwidget to the given dock area as a new tab. If no dock
@@ -253,7 +332,9 @@ public:
/**
* This function will add the given Dockwidget to the given DockAreaWidget as a new tab.
*/
DockAreaWidget *addDockWidgetTabToArea(DockWidget *dockWidget, DockAreaWidget *dockAreaWidget);
DockAreaWidget *addDockWidgetTabToArea(DockWidget *dockWidget,
DockAreaWidget *dockAreaWidget,
int index = -1);
/**
* Adds the given DockWidget floating and returns the created FloatingDockContainer instance.
@@ -322,11 +403,90 @@ public:
bool isRestoringState() const;
/**
* Request a focus change to the given dock widget.
* This function only has an effect, if the flag CDockManager::FocusStyling is enabled.
* This function returns true, if the DockManager window is restoring from minimized state.
* The DockManager is in this state starting from the QWindowStateChangeEvent that signals the
* state change from minimized to normal until endLeavingMinimizedState() function is called.
*/
bool isLeavingMinimizedState() const;
bool eventFilter(QObject *obj, QEvent *e) override;
/**
* Returns the dock widget that has focus style in the ui or a nullptr if not dock widget is
* painted focused. If the flag FocusHighlighting is disabled, this function always returns
* nullptr.
*/
DockWidget *focusedDockWidget() const;
/**
* Returns the sizes of the splitter that contains the dock area. If there is no splitter that
* contains the area, an empty list will be returned.
*/
QList<int> splitterSizes(DockAreaWidget *containedArea) const;
/**
* Update the sizes of a splitter
* Programmatically updates the sizes of a given splitter by calling QSplitter::setSizes(). The
* splitter will be the splitter that contains the supplied dock area widget. If there is not
* splitter that contains the dock area, or the sizes supplied does not match the number of
* children of the splitter, this method will have no effect.
*/
void setSplitterSizes(DockAreaWidget *containedArea, const QList<int> &sizes);
/**
* Set a custom title for all FloatingContainer that does not reflect the title of the current
* dock widget.
*/
static void setFloatingContainersTitle(const QString &title);
/**
* Returns the title used by all FloatingContainer that does not reflect the title of the
* current dock widget. If not title was set with setFloatingContainersTitle(), it returns
* QGuiApplication::applicationDisplayName().
*/
static QString floatingContainersTitle();
/**
* This function returns managers central widget or nullptr if no central widget is set.
*/
DockWidget *centralWidget() const;
/**
* Adds dockwidget widget into the central area and marks it as central widget.
* If central widget is set, it will be the only dock widget
* that will resize with the dock container. A central widget if not
* movable, floatable or closable and the titlebar of the central
* dock area is not visible.
* If the given widget could be set as central widget, the function returns
* the created dock area. If the widget could not be set, because there
* is already a central widget, this function returns a nullptr.
* To clear the central widget, pass a nullptr to the function.
* \note Setting a central widget is only possible if no other dock widgets
* have been registered before. That means, this function should be the
* first function that you call before you add other dock widgets.
* \retval != 0 The dock area that contains the central widget
* \retval nullptr Indicates that the given widget can not be set as central
* widget because there is already a central widget.
*/
DockAreaWidget *setCentralWidget(DockWidget *widget);
/**
* Request a focus change to the given dock widget. This function only has an effect, if the
* flag DockManager::FocusStyling is enabled.
*/
void setDockWidgetFocused(DockWidget *dockWidget);
/**
* Hide CDockManager and all floating widgets (See Issue #380). Calling regular QWidget::hide()
* hides the DockManager but not the floating widgets.
*/
void hideManagerAndFloatingWidgets();
/**
* Ends the isRestoringFromMinimizedState
*/
void endLeavingMinimizedState();
signals:
/**
* This signal is emitted if the list of workspaces changed.
@@ -376,6 +536,12 @@ signals:
*/
void dockAreaCreated(ADS::DockAreaWidget *dockArea);
/**
* This signal is emitted if a dock widget has been added to this
* dock manager instance.
*/
void dockWidgetAdded(ADS::DockWidget *dockWidget);
/**
* This signal is emitted just before removal of the given DockWidget.
*/
@@ -454,6 +620,17 @@ protected:
*/
void showEvent(QShowEvent *event) override;
/**
* Access for the internal dock focus controller.
* This function only returns a valid object, if the FocusHighlighting flag is set.
*/
DockFocusController *dockFocusController() const;
/**
* Restore floating widgets hidden by an earlier call to hideManagerAndFloatingWidgets.
*/
void restoreHiddenFloatingWidgets();
public:
// Workspace state
Workspace *activeWorkspace() const;

File diff suppressed because it is too large Load Diff

View File

@@ -12,61 +12,70 @@
#include <QLoggingCategory>
#include <QVariant>
namespace ADS
namespace ADS {
/**
* Private dock splitter data
*/
struct DockSplitterPrivate
{
/**
* Private dock splitter data
*/
struct DockSplitterPrivate
{
DockSplitter *q;
int m_visibleContentCount = 0;
DockSplitter *q;
int m_visibleContentCount = 0;
DockSplitterPrivate(DockSplitter *parent)
: q(parent)
{}
};
DockSplitter::DockSplitter(QWidget *parent)
: QSplitter(parent)
, d(new DockSplitterPrivate(this))
{
//setProperty("ads-splitter", true); // TODO
setProperty(Utils::StyleHelper::C_MINI_SPLITTER, true);
setChildrenCollapsible(false);
}
DockSplitter::DockSplitter(Qt::Orientation orientation, QWidget *parent)
: QSplitter(orientation, parent)
, d(new DockSplitterPrivate(this))
DockSplitterPrivate(DockSplitter *parent)
: q(parent)
{}
};
DockSplitter::~DockSplitter()
{
qCInfo(adsLog) << Q_FUNC_INFO;
delete d;
}
DockSplitter::DockSplitter(QWidget *parent)
: QSplitter(parent)
, d(new DockSplitterPrivate(this))
{
//setProperty("ads-splitter", true); // TODO
setProperty(Utils::StyleHelper::C_MINI_SPLITTER, true);
setChildrenCollapsible(false);
}
bool DockSplitter::hasVisibleContent() const
{
// TODO Cache or precalculate this to speed up
for (int i = 0; i < count(); ++i) {
if (!widget(i)->isHidden()) {
return true;
}
DockSplitter::DockSplitter(Qt::Orientation orientation, QWidget *parent)
: QSplitter(orientation, parent)
, d(new DockSplitterPrivate(this))
{}
DockSplitter::~DockSplitter()
{
qCInfo(adsLog) << Q_FUNC_INFO;
delete d;
}
bool DockSplitter::hasVisibleContent() const
{
// TODO Cache or precalculate this to speed up
for (int i = 0; i < count(); ++i) {
if (!widget(i)->isHidden()) {
return true;
}
return false;
}
QWidget *DockSplitter::firstWidget() const
{
return (count() > 0) ? widget(0) : nullptr;
return false;
}
QWidget *DockSplitter::firstWidget() const
{
return (count() > 0) ? widget(0) : nullptr;
}
QWidget *DockSplitter::lastWidget() const
{
return (count() > 0) ? widget(count() - 1) : nullptr;
}
bool DockSplitter::isResizingWithContainer() const
{
for (auto area : findChildren<DockAreaWidget *>()) {
if (area->isCentralWidgetArea())
return true;
}
QWidget *DockSplitter::lastWidget() const
{
return (count() > 0) ? widget(count() - 1) : nullptr;
}
return false;
}
} // namespace ADS

View File

@@ -45,6 +45,11 @@ public:
* Returns last widget of nullptr is splitter is empty
*/
QWidget *lastWidget() const;
/**
* Returns true if the splitter contains central widget of dock manager.
*/
bool isResizingWithContainer() const;
}; // class DockSplitter
} // namespace ADS

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,9 @@ class DockContainerWidget;
class DockAreaWidget;
class DockContainerWidgetPrivate;
class FloatingDockContainer;
class AutoHideTab;
class AutoHideDockContainer;
class AutoHideSideBar;
/**
* The QDockWidget class provides a widget that can be docked inside a
@@ -49,6 +52,8 @@ protected:
friend class DockWidgetTab;
friend class DockWidgetTabPrivate;
friend class DockAreaTitleBarPrivate;
friend class AutoHideDockContainer;
friend AutoHideSideBar;
/**
* Assigns the dock manager that manages this dock widget
@@ -120,14 +125,28 @@ public:
using Super = QFrame;
enum DockWidgetFeature {
DockWidgetClosable = 0x01,///< dock widget has a close button
DockWidgetMovable = 0x02,///< dock widget is movable and can be moved to a new position in the current dock container
DockWidgetFloatable = 0x04,
DockWidgetDeleteOnClose = 0x08, ///< deletes the dock widget when it is closed
CustomCloseHandling = 0x10,
DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable,
AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose | CustomCloseHandling,
NoDockWidgetFeatures = 0x00
DockWidgetClosable = 0x001, ///< dock widget has a close button
DockWidgetMovable
= 0x002, ///< dock widget is movable and can be moved to a new position in the current dock container
DockWidgetFloatable = 0x004, ///< dock widget can be dragged into a floating window
DockWidgetDeleteOnClose = 0x008, ///< deletes the dock widget when it is closed
CustomCloseHandling
= 0x010, ///< clicking the close button will not close the dock widget but emits the closeRequested() signal instead
DockWidgetFocusable = 0x020, ///< if this is enabled, a dock widget can get focus highlighting
DockWidgetForceCloseWithArea
= 0x040, ///< dock widget will be closed when the dock area hosting it is closed
NoTab = 0x080, ///< dock widget tab will never be shown if this flag is set
DeleteContentOnClose
= 0x100, ///< deletes only the contained widget on close, keeping the dock widget intact
///< and in place. Attempts to rebuild the contents widget on show if there is a widget factory set.
DockWidgetPinnable
= 0x200, ///< dock widget can be pinned and added to an auto hide dock container
DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable
| DockWidgetFocusable | DockWidgetPinnable,
AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose
| CustomCloseHandling,
DockWidgetAlwaysCloseAndDelete = DockWidgetForceCloseWithArea | DockWidgetDeleteOnClose,
NoDockWidgetFeatures = 0x000
};
Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
@@ -158,10 +177,18 @@ public:
* To ensure, that a dock widget does not block resizing, the dock widget
* reimplements minimumSizeHint() function to return a very small minimum
* size hint. If you would like to adhere the minimumSizeHint() from the
* content widget, the set the minimumSizeHintMode() to
* MinimumSizeHintFromContent.
* content widget, then set the minimumSizeHintMode() to
* MinimumSizeHintFromContent. If you would like to use the minimumSize()
* value of the content widget or the dock widget, then you can use the
* MinimumSizeHintFromDockWidgetMinimumSize or
* MinimumSizeHintFromContentMinimumSize modes.
*/
enum eMinimumSizeHintMode { MinimumSizeHintFromDockWidget, MinimumSizeHintFromContent };
enum eMinimumSizeHintMode {
MinimumSizeHintFromDockWidget,
MinimumSizeHintFromContent,
MinimumSizeHintFromDockWidgetMinimumSize,
MinimumSizeHintFromContentMinimumSize,
};
/**
* This mode configures the behavior of the toggle view action.
@@ -205,7 +232,7 @@ public:
/**
* 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
* The content of a dock widget should be resizable to a very small size to
* prevent the dock widget from blocking the resizing. To ensure, that a
* 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
@@ -221,6 +248,18 @@ public:
*/
void setWidget(QWidget *widget, eInsertMode insertMode = AutoScrollArea);
/**
* Only used when the feature flag DeleteContentOnClose is set.
* Using the flag and setting a widget factory allows to free the resources
* of the widget of your application while retaining the position the next
* time you want to show your widget, unlike the flag DockWidgetDeleteOnClose
* which deletes the dock widget itself. Since we keep the dock widget, all
* regular features of ADS should work as normal, including saving and
* restoring the state of the docking system and using perspectives.
*/
using FactoryFunc = std::function<QWidget *(QWidget *)>;
void setWidgetFactory(FactoryFunc createWidget, eInsertMode insertMode = AutoScrollArea);
/**
* Remove the widget from the dock and give ownership back to the caller
*/
@@ -269,12 +308,41 @@ public:
*/
DockContainerWidget *dockContainer() const;
/**
* This function return the floating DockContainer if is isFloating() is true
* and a nullptr if this dock widget is not floating.
*/
FloatingDockContainer *floatingDockContainer() const;
/**
* Returns the dock area widget this dock widget belongs to or 0
* if this dock widget has not been docked yet
*/
DockAreaWidget *dockAreaWidget() const;
/**
* Returns the side tab widget for this dock, if this dock widget is in
* a auto hide container. If it is not in a auto hide container, then this
* function returns a nullptr,
*/
AutoHideTab *sideTabWidget() const;
/**
* Assign a side tab widget if this dock widget is an auto hide container
*/
void setSideTabWidget(AutoHideTab *sideTab) const;
/**
* Returns true, if this dock widget is in an auto hide container
*/
bool isAutoHide() const;
/**
* Returns the auto hide dock container of this dock widget
* or 0 if there is none
*/
AutoHideDockContainer *autoHideDockContainer() const;
/**
* This property holds whether the dock widget is floating.
* A dock widget is only floating, if it is the one and only widget inside
@@ -314,6 +382,16 @@ public:
*/
void setMinimumSizeHintMode(eMinimumSizeHintMode mode);
/**
* Get the minimum size hint mode configured by setMinimumSizeHintMode
*/
eMinimumSizeHintMode minimumSizeHintMode() const;
/**
* Returns true if the dock widget is set as central widget of it's dock manager
*/
bool isCentralWidget() const;
/**
* Sets the dock widget icon that is shown in tabs and in toggle view
* actions
@@ -431,7 +509,7 @@ public: // reimplements QFrame
/**
* This property controls whether the dock widget is open or closed.
* The toogleViewAction triggers this slot
* The toggleViewAction triggers this slot
*/
void toggleView(bool open = true);
@@ -488,6 +566,18 @@ public: // reimplements QFrame
*/
void showNormal();
/**
* Sets the dock widget into auto hide mode if this feature is enabled
* via CDockManager::setAutoHideFlags(CDockManager::AutoHideFeatureEnabled)
*/
void setAutoHide(bool enable, SideBarLocation location = SideBarNone);
/**
* Switches the dock widget to auto hide mode or vice versa depending on its
* current state.
*/
void toggleAutoHide(SideBarLocation location = SideBarNone);
signals:
/**
* This signal is emitted if the dock widget is opened or closed

File diff suppressed because it is too large Load Diff

View File

@@ -35,24 +35,27 @@ private:
bool m_focus;
};
/**
* 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
* The dock widget tab is shown in the dock area title bar to switch between tabbed dock widgets.
*/
class ADS_EXPORT DockWidgetTab : public QFrame
{
Q_OBJECT
Q_PROPERTY(bool activeTab READ isActiveTab WRITE setActiveTab NOTIFY activeTabChanged)
Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
private:
DockWidgetTabPrivate *d; ///< private data (pimpl)
friend class DockWidgetTabPrivate;
friend class DockWidget;
friend class DockManager;
friend class AutoHideDockContainer;
void onDockWidgetFeaturesChanged();
void detachDockWidget();
void autoHideDockWidget();
void onAutoHideToActionClicked();
protected:
void mousePressEvent(QMouseEvent *event) override;
@@ -95,8 +98,7 @@ public:
DockWidget *dockWidget() const;
/**
* Sets the dock area widget the dockWidget returned by dockWidget()
* function belongs to.
* Sets the dock area widget the dockWidget returned by dockWidget() function belongs to.
*/
void setDockAreaWidget(DockAreaWidget *dockArea);
@@ -152,6 +154,24 @@ public:
*/
void updateStyle();
/**
* Returns the icon size.
* If no explicit icon size has been set, the function returns an invalid QSize.
*/
QSize iconSize() const;
/**
* Set an explicit icon size.
* If no icon size has been set explicitly, than the tab sets the icon size depending
* on the style.
*/
void setIconSize(const QSize &size);
/**
* Returns true, if the tab has been clicked and the mouse is currently pressed.
*/
bool mousePressed() const;
void setVisible(bool visible) override;
signals:
@@ -161,6 +181,7 @@ signals:
void closeOtherTabsRequested();
void moved(const QPoint &globalPosition);
void elidedChanged(bool elided);
void iconSizeChanged();
}; // class DockWidgetTab
} // namespace ADS

View File

@@ -6,143 +6,145 @@
#include <QMouseEvent>
namespace ADS {
/**
* Private data of public ElidingLabel
*/
struct ElidingLabelPrivate
{
ElidingLabel *q;
Qt::TextElideMode m_elideMode = Qt::ElideNone;
QString m_text;
bool m_isElided = false;
ElidingLabelPrivate(ElidingLabel *parent)
: q(parent)
{}
/**
* Private data of public ElidingLabel
*/
class ElidingLabelPrivate
{
public:
ElidingLabel *q;
Qt::TextElideMode m_elideMode = Qt::ElideNone;
QString m_text;
bool m_isElided = false;
void elideText(int width);
/**
* Convenience function to check if the
*/
bool isModeElideNone() const { return Qt::ElideNone == m_elideMode; }
};
void ElidingLabelPrivate::elideText(int width)
{
if (isModeElideNone())
return;
QFontMetrics fm = q->fontMetrics();
QString str = fm.elidedText(m_text, m_elideMode, width - q->margin() * 2 - q->indent());
if (str == u'\u2026')
str = m_text.at(0);
bool wasElided = m_isElided;
m_isElided = str != m_text;
if (m_isElided != wasElided)
emit q->elidedChanged(m_isElided);
q->QLabel::setText(str);
}
ElidingLabel::ElidingLabel(QWidget *parent, Qt::WindowFlags flags)
: QLabel(parent, flags)
, d(new ElidingLabelPrivate(this))
ElidingLabelPrivate(ElidingLabel *parent)
: q(parent)
{}
ElidingLabel::ElidingLabel(const QString &text, QWidget *parent, Qt::WindowFlags flags)
: QLabel(text, parent, flags)
, d(new ElidingLabelPrivate(this))
{
d->m_text = text;
void elideText(int width);
/**
* Convenience function to check if the
*/
bool isModeElideNone() const { return Qt::ElideNone == m_elideMode; }
};
void ElidingLabelPrivate::elideText(int width)
{
if (isModeElideNone())
return;
QFontMetrics fm = q->fontMetrics();
QString str = fm.elidedText(m_text, m_elideMode, width - q->margin() * 2 - q->indent());
if (str == u'\u2026')
str = m_text.at(0);
bool wasElided = m_isElided;
m_isElided = (str != m_text);
if (m_isElided != wasElided)
emit q->elidedChanged(m_isElided);
q->QLabel::setText(str);
}
ElidingLabel::ElidingLabel(QWidget *parent, Qt::WindowFlags flags)
: QLabel(parent, flags)
, d(new ElidingLabelPrivate(this))
{}
ElidingLabel::ElidingLabel(const QString &text, QWidget *parent, Qt::WindowFlags flags)
: QLabel(text, parent, flags)
, d(new ElidingLabelPrivate(this))
{
d->m_text = text;
internal::setToolTip(this, text);
}
ElidingLabel::~ElidingLabel()
{
delete d;
}
Qt::TextElideMode ElidingLabel::elideMode() const
{
return d->m_elideMode;
}
void ElidingLabel::setElideMode(Qt::TextElideMode mode)
{
d->m_elideMode = mode;
d->elideText(size().width());
}
bool ElidingLabel::isElided() const
{
return d->m_isElided;
}
void ElidingLabel::mouseReleaseEvent(QMouseEvent *event)
{
Super::mouseReleaseEvent(event);
if (event->button() != Qt::LeftButton)
return;
emit clicked();
}
void ElidingLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_UNUSED(event)
emit doubleClicked();
Super::mouseDoubleClickEvent(event);
}
void ElidingLabel::resizeEvent(QResizeEvent *event)
{
if (!d->isModeElideNone())
d->elideText(event->size().width());
Super::resizeEvent(event);
}
QSize ElidingLabel::minimumSizeHint() const
{
if (hasPixmap() || d->isModeElideNone())
return QLabel::minimumSizeHint();
const QFontMetrics &fm = fontMetrics();
QSize size(fm.horizontalAdvance(d->m_text.left(2) + ""), fm.height());
return size;
}
QSize ElidingLabel::sizeHint() const
{
if (hasPixmap() || d->isModeElideNone())
return QLabel::sizeHint();
const QFontMetrics &fm = fontMetrics();
QSize size(fm.horizontalAdvance(d->m_text), QLabel::sizeHint().height());
return size;
}
void ElidingLabel::setText(const QString &text)
{
d->m_text = text;
if (d->isModeElideNone()) {
Super::setText(text);
} else {
internal::setToolTip(this, text);
}
ElidingLabel::~ElidingLabel()
{
delete d;
}
Qt::TextElideMode ElidingLabel::elideMode() const
{
return d->m_elideMode;
}
void ElidingLabel::setElideMode(Qt::TextElideMode mode)
{
d->m_elideMode = mode;
d->elideText(size().width());
}
}
bool ElidingLabel::isElided() const
{
return d->m_isElided;
}
QString ElidingLabel::text() const
{
return d->m_text;
}
void ElidingLabel::mouseReleaseEvent(QMouseEvent *event)
{
Super::mouseReleaseEvent(event);
if (event->button() != Qt::LeftButton)
return;
emit clicked();
}
void ElidingLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_UNUSED(event)
emit doubleClicked();
Super::mouseDoubleClickEvent(event);
}
void ElidingLabel::resizeEvent(QResizeEvent *event)
{
if (!d->isModeElideNone())
d->elideText(event->size().width());
Super::resizeEvent(event);
}
bool ElidingLabel::hasPixmap() const
{
return !pixmap().isNull();
}
QSize ElidingLabel::minimumSizeHint() const
{
if (hasPixmap() || d->isModeElideNone())
return QLabel::minimumSizeHint();
const QFontMetrics &fm = fontMetrics();
QSize size(fm.horizontalAdvance(d->m_text.left(2) + ""), fm.height());
return size;
}
QSize ElidingLabel::sizeHint() const
{
if (hasPixmap() || d->isModeElideNone())
return QLabel::sizeHint();
const QFontMetrics &fm = fontMetrics();
QSize size(fm.horizontalAdvance(d->m_text), QLabel::sizeHint().height());
return size;
}
void ElidingLabel::setText(const QString &text)
{
d->m_text = text;
if (d->isModeElideNone()) {
Super::setText(text);
} else {
internal::setToolTip(this, text);
d->elideText(this->size().width());
}
}
QString ElidingLabel::text() const
{
return d->m_text;
}
bool ElidingLabel::hasPixmap() const
{
return !pixmap().isNull();
}
} // namespace ADS

View File

@@ -9,20 +9,19 @@
namespace ADS {
struct ElidingLabelPrivate;
class 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
* 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 ADS_EXPORT ElidingLabel : public QLabel
{
Q_OBJECT
private:
ElidingLabelPrivate *d;
friend struct ElidingLabelPrivate;
friend class ElidingLabelPrivate;
protected:
void mouseReleaseEvent(QMouseEvent *event) override;
@@ -32,8 +31,10 @@ protected:
public:
using Super = QLabel;
ElidingLabel(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::Widget);
ElidingLabel(const QString &text, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::Widget);
ElidingLabel(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
ElidingLabel(const QString &text,
QWidget *parent = nullptr,
Qt::WindowFlags flags = Qt::WindowFlags());
~ElidingLabel() override;
/**

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
#include <QDockWidget>
#include <QRubberBand>
#ifdef Q_OS_LINUX
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
using FloatingWidgetBaseType = QDockWidget;
#else
using FloatingWidgetBaseType = QWidget;
@@ -33,8 +33,8 @@ class DockingStateReader;
/**
* Pure virtual interface for floating widgets.
* This interface is used for opaque and non-opaque undocking. If opaque
* undocking is used, the a real FloatingDockContainer widget will be created
* This interface is used for opaque and non-opaque undocking. If opaque undocking is used,
* the a real FloatingDockContainer widget will be created.
*/
class AbstractFloatingWidget
{
@@ -42,8 +42,7 @@ public:
virtual ~AbstractFloatingWidget() = 0;
/**
* Starts floating.
* This function should get called typically from a mouse press event
* handler
* This function should get called typically from a mouse press event handler.
*/
virtual void startFloating(const QPoint &dragStartMousePos,
const QSize &size,
@@ -52,26 +51,23 @@ public:
= 0;
/**
* Moves the widget to a new position relative to the position given when
* startFloating() was called.
* This function should be called from a mouse mouve event handler to
* move the floating widget on mouse move events.
* Moves the widget to a new position relative to the position given when startFloating()
* was called. This function should be called from a mouse mouve event handler to move the
* floating widget on mouse move events.
*/
virtual void moveFloating() = 0;
/**
* Tells the widget that to finish dragging if the mouse is released.
* This function should be called from a mouse release event handler
* to finish the dragging
* Tells the widget that to finish dragging if the mouse is released. This function should be
* called from a mouse release event handler to finish the dragging.
*/
virtual void finishDragging() = 0;
};
/**
* This implements a floating widget that is a dock container that accepts
* docking of dock widgets like the main window and that can be docked into
* another dock container.
* Every floating window of the docking system is a FloatingDockContainer.
* This implements a floating widget that is a dock container that accepts docking of dock widgets
* like the main window and that can be docked into another dock container. Every floating window
* of the docking system is a FloatingDockContainer.
*/
class ADS_EXPORT FloatingDockContainer : public FloatingWidgetBaseType,
public AbstractFloatingWidget
@@ -96,9 +92,8 @@ private:
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
* 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 &dragStartMousePos,
const QSize &size,
@@ -106,7 +101,7 @@ protected:
QWidget *mouseEventHandler) override;
/**
* Call this function to start dragging the floating widget
* Call this function to start dragging the floating widget.
*/
void startDragging(const QPoint &dragStartMousePos,
const QSize &size,
@@ -116,14 +111,13 @@ protected:
}
/**
* Call this function if you explicitly want to signal that dragging has
* finished
* Call this function if you explicitly want to signal that dragging has finished.
*/
void finishDragging() override;
/**
* Call this function if you just want to initialize the position
* and size of the floating widget
* Call this function if you just want to initialize the position and size of the
* floating widget.
*/
void initFloatingGeometry(const QPoint &dragStartMousePos, const QSize &size)
{
@@ -131,21 +125,20 @@ protected:
}
/**
* Moves the widget to a new position relative to the position given when
* startFloating() was called
* Moves the widget to a new position relative to the position given when startFloating()
* was called.
*/
void moveFloating() override;
/**
* 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
* 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(DockingStateReader &stream, bool testing);
/**
* Call this function to update the window title
* Call this function to update the window title.
*/
void updateWindowTitle();
@@ -158,6 +151,10 @@ protected: // reimplements QWidget
#ifdef Q_OS_MACOS
virtual bool event(QEvent *event) override;
virtual void moveEvent(QMoveEvent *event) override;
#elif defined(Q_OS_UNIX)
virtual bool event(QEvent *e) override;
virtual void moveEvent(QMoveEvent *event) override;
virtual void resizeEvent(QResizeEvent *event) override;
#endif
#ifdef Q_OS_WIN
@@ -202,26 +199,61 @@ public:
bool isClosable() const;
/**
* This function returns true, if this floating widget has only one single
* visible dock widget in a single visible dock area.
* The single dock widget is a real top level floating widget because no
* other widgets are docked.
* This function returns true, if this floating widget has only one single visible dock widget
* in a single visible dock area. The single dock widget is a real top level floating widget
* because no other widgets are docked.
*/
bool hasTopLevelDockWidget() const;
/**
* This function returns the first dock widget in the first dock area.
* If the function hasSingleDockWidget() returns true, then this function
* returns this single dock widget.
* This function returns the first dock widget in the first dock area. If the function
* hasSingleDockWidget() returns true, then this function returns this single dock widget.
*/
DockWidget *topLevelDockWidget() const;
/**
* 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.
* 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<DockWidget *> dockWidgets() const;
/**
* This function hides the floating bar instantely and delete it later.
*/
void hideAndDeleteLater();
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
/**
* This is a function that responds to FloatingWidgetTitleBar::maximizeRequest()
* Maximize or normalize the container size.
*/
void onMaximizeRequest();
/**
* Normalize (Unmaximize) the window.
* fixGeometry parameter fixes a "bug" in QT where immediately after calling showNormal
* geometry is not set properly.
* Set this true when moving the window immediately after normalizing.
*/
void showNormal(bool fixGeometry = false);
/**
* Maximizes the window.
*/
void showMaximized();
/**
* Returns if the window is currently maximized or not.
*/
bool isMaximized() const;
/**
* Returns true if the floating widget has a native titlebar or false if
* the floating widget has a QWidget based title bar
*/
bool hasNativeTitleBar();
#endif
}; // class FloatingDockContainer
} // namespace ADS

View File

@@ -4,6 +4,7 @@
#include "floatingdragpreview.h"
#include "ads_globals_p.h"
#include "autohidedockcontainer.h"
#include "dockareawidget.h"
#include "dockcontainerwidget.h"
#include "dockmanager.h"
@@ -20,311 +21,359 @@
#include <iostream>
namespace ADS
namespace ADS {
/**
* Private data class (pimpl)
*/
class FloatingDragPreviewPrivate
{
public:
FloatingDragPreview *q;
QWidget *m_content = nullptr;
DockAreaWidget *m_contentSourceArea = nullptr;
QPoint m_dragStartMousePosition;
DockManager *m_dockManager = nullptr;
DockContainerWidget *m_dropContainer = nullptr;
bool m_hidden = false;
QPixmap m_contentPreviewPixmap;
bool m_canceled = false;
/**
* Private data class (pimpl)
* Private data constructor
*/
class FloatingDragPreviewPrivate
FloatingDragPreviewPrivate(FloatingDragPreview *parent);
void updateDropOverlays(const QPoint &globalPosition);
void setHidden(bool value)
{
public:
FloatingDragPreview *q;
QWidget *m_content = nullptr;
DockAreaWidget *m_contentSourceArea = nullptr;
QPoint m_dragStartMousePosition;
DockManager *m_dockManager = nullptr;
DockContainerWidget *m_dropContainer = nullptr;
bool m_hidden = false;
QPixmap m_contentPreviewPixmap;
bool m_canceled = false;
/**
* Private data constructor
*/
FloatingDragPreviewPrivate(FloatingDragPreview *parent);
void updateDropOverlays(const QPoint &globalPosition);
void setHidden(bool value)
{
m_hidden = value;
q->update();
}
/**
* Cancel dragging and emit the draggingCanceled event
*/
void cancelDragging()
{
m_canceled = true;
emit q->draggingCanceled();
m_dockManager->containerOverlay()->hideOverlay();
m_dockManager->dockAreaOverlay()->hideOverlay();
q->close();
}
/**
* Creates the real floating widget in case the mouse is released outside
* outside of any drop area
*/
void createFloatingWidget();
}; // class FloatingDragPreviewPrivate
void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &globalPosition)
{
if (!q->isVisible() || !m_dockManager)
return;
auto containers = m_dockManager->dockContainers();
DockContainerWidget *topContainer = nullptr;
for (auto containerWidget : containers) {
if (!containerWidget->isVisible())
continue;
const QPoint mappedPosition = containerWidget->mapFromGlobal(globalPosition);
if (containerWidget->rect().contains(mappedPosition)) {
if (!topContainer || containerWidget->isInFrontOf(topContainer))
topContainer = containerWidget;
}
}
m_dropContainer = topContainer;
auto containerOverlay = m_dockManager->containerOverlay();
auto dockAreaOverlay = m_dockManager->dockAreaOverlay();
auto dockDropArea = dockAreaOverlay->dropAreaUnderCursor();
auto containerDropArea = containerOverlay->dropAreaUnderCursor();
if (!topContainer) {
containerOverlay->hideOverlay();
dockAreaOverlay->hideOverlay();
if (DockManager::testConfigFlag(DockManager::DragPreviewIsDynamic))
setHidden(false);
return;
}
const int visibleDockAreas = topContainer->visibleDockAreaCount();
containerOverlay->setAllowedAreas(visibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
auto dockArea = topContainer->dockAreaAt(globalPosition);
if (dockArea && dockArea->isVisible() && visibleDockAreas >= 0
&& dockArea != m_contentSourceArea) {
dockAreaOverlay->enableDropPreview(true);
dockAreaOverlay->setAllowedAreas((visibleDockAreas == 1) ? NoDockWidgetArea
: dockArea->allowedAreas());
DockWidgetArea area = dockAreaOverlay->showOverlay(dockArea);
// 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) && (containerDropArea != InvalidDockWidgetArea)) {
dockAreaOverlay->enableDropPreview(false);
containerOverlay->enableDropPreview(true);
} else {
containerOverlay->enableDropPreview(InvalidDockWidgetArea == area);
}
containerOverlay->showOverlay(topContainer);
} else {
dockAreaOverlay->hideOverlay();
// If there is only one single visible dock area in a container, then
// it does not make sense to show a dock overlay because the dock area
// would be removed and inserted at the same position
if (visibleDockAreas <= 1)
containerOverlay->hideOverlay();
else
containerOverlay->showOverlay(topContainer);
if (dockArea == m_contentSourceArea && InvalidDockWidgetArea == containerDropArea)
m_dropContainer = nullptr;
}
if (DockManager::testConfigFlag(DockManager::DragPreviewIsDynamic)) {
setHidden(dockDropArea != InvalidDockWidgetArea
|| containerDropArea != InvalidDockWidgetArea);
}
m_hidden = value;
q->update();
}
FloatingDragPreviewPrivate::FloatingDragPreviewPrivate(FloatingDragPreview *parent)
: q(parent)
{}
/**
* Cancel dragging and emit the draggingCanceled event.
*/
void cancelDragging()
{
m_canceled = true;
emit q->draggingCanceled();
m_dockManager->containerOverlay()->hideOverlay();
m_dockManager->dockAreaOverlay()->hideOverlay();
q->close();
}
void FloatingDragPreviewPrivate::createFloatingWidget()
/**
* Creates the real floating widget in case the mouse is released outside outside of any
* drop area.
*/
void createFloatingWidget();
/**
* Returns true, if the content is floatable.
*/
bool isContentFloatable() const
{
DockWidget *dockWidget = qobject_cast<DockWidget *>(m_content);
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(m_content);
FloatingDockContainer *floatingWidget = nullptr;
if (dockWidget && dockWidget->features().testFlag(DockWidget::DockWidgetFloatable))
floatingWidget = new FloatingDockContainer(dockWidget);
else if (dockArea && dockArea->features().testFlag(DockWidget::DockWidgetFloatable))
floatingWidget = new FloatingDockContainer(dockArea);
return true;
if (floatingWidget) {
floatingWidget->setGeometry(q->geometry());
floatingWidget->show();
if (!DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
QApplication::processEvents();
int frameHeight = floatingWidget->frameGeometry().height() - floatingWidget->geometry().height();
QRect fixedGeometry = q->geometry();
fixedGeometry.adjust(0, frameHeight, 0, 0);
floatingWidget->setGeometry(fixedGeometry);
}
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(m_content);
if (dockArea && dockArea->features().testFlag(DockWidget::DockWidgetFloatable))
return true;
return false;
}
}; // class FloatingDragPreviewPrivate
void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &globalPosition)
{
if (!q->isVisible() || !m_dockManager)
return;
auto containers = m_dockManager->dockContainers();
DockContainerWidget *topContainer = nullptr;
for (auto containerWidget : containers) {
if (!containerWidget->isVisible())
continue;
const QPoint mappedPosition = containerWidget->mapFromGlobal(globalPosition);
if (containerWidget->rect().contains(mappedPosition)) {
if (!topContainer || containerWidget->isInFrontOf(topContainer))
topContainer = containerWidget;
}
}
FloatingDragPreview::FloatingDragPreview(QWidget *content, QWidget *parent)
: QWidget(parent)
, d(new FloatingDragPreviewPrivate(this))
{
d->m_content = content;
setAttribute(Qt::WA_DeleteOnClose);
if (DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
m_dropContainer = topContainer;
auto containerOverlay = m_dockManager->containerOverlay();
auto dockAreaOverlay = m_dockManager->dockAreaOverlay();
auto dockDropArea = dockAreaOverlay->dropAreaUnderCursor();
auto containerDropArea = containerOverlay->dropAreaUnderCursor();
if (!topContainer) {
containerOverlay->hideOverlay();
dockAreaOverlay->hideOverlay();
if (DockManager::testConfigFlag(DockManager::DragPreviewIsDynamic))
setHidden(false);
return;
}
int visibleDockAreas = topContainer->visibleDockAreaCount();
// Include the overlay widget we're dragging as a visible widget
auto dockAreaWidget = qobject_cast<DockAreaWidget *>(m_content);
if (dockAreaWidget && dockAreaWidget->isAutoHide())
visibleDockAreas++;
containerOverlay->setAllowedAreas(visibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
auto dockArea = topContainer->dockAreaAt(globalPosition);
if (dockArea && dockArea->isVisible() && visibleDockAreas >= 0
&& dockArea != m_contentSourceArea) {
dockAreaOverlay->enableDropPreview(true);
dockAreaOverlay->setAllowedAreas((visibleDockAreas == 1) ? NoDockWidgetArea
: dockArea->allowedAreas());
DockWidgetArea area = dockAreaOverlay->showOverlay(dockArea);
// 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) && (containerDropArea != InvalidDockWidgetArea)) {
dockAreaOverlay->enableDropPreview(false);
containerOverlay->enableDropPreview(true);
} else {
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
containerOverlay->enableDropPreview(InvalidDockWidgetArea == area);
}
containerOverlay->showOverlay(topContainer);
} else {
dockAreaOverlay->hideOverlay();
// If there is only one single visible dock area in a container, then it does not make
// sense to show a dock overlay because the dock area would be removed and inserted at
// the same position.
if (visibleDockAreas == 1)
containerOverlay->hideOverlay();
else
containerOverlay->showOverlay(topContainer);
if (Utils::HostOsInfo::isLinuxHost()) {
auto flags = windowFlags();
flags |= Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint;
setWindowFlags(flags);
}
setWindowOpacity(0.6);
// Create a static image of the widget that should get undocked
// This is like some kind preview image like it is uses in drag and drop operations
if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap)) {
d->m_contentPreviewPixmap = QPixmap(content->size());
content->render(&d->m_contentPreviewPixmap);
}
connect(qApp,
&QApplication::applicationStateChanged,
this,
&FloatingDragPreview::onApplicationStateChanged);
// The only safe way to receive escape key presses is to install an event
// filter for the application object
QApplication::instance()->installEventFilter(this);
if (dockArea == m_contentSourceArea && InvalidDockWidgetArea == containerDropArea)
m_dropContainer = nullptr;
}
FloatingDragPreview::FloatingDragPreview(DockWidget *content)
: FloatingDragPreview(static_cast<QWidget *>(content),
content->dockManager()) // TODO static_cast?
{
d->m_dockManager = content->dockManager();
if (content->dockAreaWidget()->openDockWidgetsCount() == 1)
d->m_contentSourceArea = content->dockAreaWidget();
if (DockManager::testConfigFlag(DockManager::DragPreviewIsDynamic))
setHidden(dockDropArea != InvalidDockWidgetArea
|| containerDropArea != InvalidDockWidgetArea);
}
setWindowTitle(content->windowTitle());
}
FloatingDragPreviewPrivate::FloatingDragPreviewPrivate(FloatingDragPreview *parent)
: q(parent)
{}
FloatingDragPreview::FloatingDragPreview(DockAreaWidget *content)
: FloatingDragPreview(static_cast<QWidget *>(content),
content->dockManager()) // TODO static_cast?
{
d->m_dockManager = content->dockManager();
d->m_contentSourceArea = content;
setWindowTitle(content->currentDockWidget()->windowTitle());
}
void FloatingDragPreviewPrivate::createFloatingWidget()
{
DockWidget *dockWidget = qobject_cast<DockWidget *>(m_content);
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(m_content);
FloatingDragPreview::~FloatingDragPreview() { delete d; }
FloatingDockContainer *floatingWidget = nullptr;
void FloatingDragPreview::moveFloating()
{
const int borderSize = (frameSize().width() - size().width()) / 2;
const QPoint moveToPos = QCursor::pos() - d->m_dragStartMousePosition
- QPoint(borderSize, 0);
move(moveToPos);
d->updateDropOverlays(QCursor::pos());
}
if (dockWidget && dockWidget->features().testFlag(DockWidget::DockWidgetFloatable))
floatingWidget = new FloatingDockContainer(dockWidget);
else if (dockArea && dockArea->features().testFlag(DockWidget::DockWidgetFloatable))
floatingWidget = new FloatingDockContainer(dockArea);
void FloatingDragPreview::startFloating(const QPoint &dragStartMousePos,
const QSize &size,
eDragState dragState,
QWidget *mouseEventHandler)
{
Q_UNUSED(mouseEventHandler)
Q_UNUSED(dragState)
resize(size);
d->m_dragStartMousePosition = dragStartMousePos;
moveFloating();
show();
}
void FloatingDragPreview::finishDragging()
{
qCInfo(adsLog) << Q_FUNC_INFO;
auto dockDropArea = d->m_dockManager->dockAreaOverlay()->visibleDropAreaUnderCursor();
auto containerDropArea = d->m_dockManager->containerOverlay()->visibleDropAreaUnderCursor();
if (!d->m_dropContainer) {
d->createFloatingWidget();
} else if (dockDropArea != InvalidDockWidgetArea) {
d->m_dropContainer->dropWidget(d->m_content, dockDropArea, d->m_dropContainer->dockAreaAt(QCursor::pos()));
} else if (containerDropArea != InvalidDockWidgetArea) {
// If there is only one single dock area, and we drop into the center
// then we tabify the dropped widget into the only visible dock area
if (d->m_dropContainer->visibleDockAreaCount() <= 1 && CenterDockWidgetArea == containerDropArea)
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, d->m_dropContainer->dockAreaAt(QCursor::pos()));
else
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, nullptr);
} else {
d->createFloatingWidget();
}
this->close();
d->m_dockManager->containerOverlay()->hideOverlay();
d->m_dockManager->dockAreaOverlay()->hideOverlay();
}
void FloatingDragPreview::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
if (d->m_hidden)
return;
QPainter painter(this);
if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap))
painter.drawPixmap(QPoint(0, 0), d->m_contentPreviewPixmap);
// If we do not have a window frame then we paint a QRubberBand like frameless window
if (floatingWidget) {
floatingWidget->setGeometry(q->geometry());
floatingWidget->show();
if (!DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
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);
painter.setBrush(color);
painter.drawRect(rect().adjusted(0, 0, -1, -1));
QApplication::processEvents();
int frameHeight = floatingWidget->frameGeometry().height()
- floatingWidget->geometry().height();
QRect fixedGeometry = q->geometry();
fixedGeometry.adjust(0, frameHeight, 0, 0);
floatingWidget->setGeometry(fixedGeometry);
}
}
}
void FloatingDragPreview::onApplicationStateChanged(Qt::ApplicationState state)
{
if (state != Qt::ApplicationActive) {
disconnect(qApp,
&QApplication::applicationStateChanged,
this,
&FloatingDragPreview::onApplicationStateChanged);
FloatingDragPreview::FloatingDragPreview(QWidget *content, QWidget *parent)
: QWidget(parent)
, d(new FloatingDragPreviewPrivate(this))
{
d->m_content = content;
setAttribute(Qt::WA_DeleteOnClose);
if (DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
} else {
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
}
if (Utils::HostOsInfo::isAnyUnixHost() && !Utils::HostOsInfo::isMacHost()) {
auto flags = windowFlags();
flags |= Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint;
setWindowFlags(flags);
}
setWindowOpacity(0.6);
// Create a static image of the widget that should get undocked. This is like some kind preview
// image like it is uses in drag and drop operations.
if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap)) {
d->m_contentPreviewPixmap = QPixmap(content->size());
content->render(&d->m_contentPreviewPixmap);
}
connect(qApp,
&QApplication::applicationStateChanged,
this,
&FloatingDragPreview::onApplicationStateChanged);
// The only safe way to receive escape key presses is to install an event filter for the
// application object.
QApplication::instance()->installEventFilter(this);
}
FloatingDragPreview::FloatingDragPreview(DockWidget *content)
: FloatingDragPreview(static_cast<QWidget *>(content),
content->dockManager()) // TODO static_cast?
{
d->m_dockManager = content->dockManager();
if (content->dockAreaWidget()->openDockWidgetsCount() == 1)
d->m_contentSourceArea = content->dockAreaWidget();
setWindowTitle(content->windowTitle());
}
FloatingDragPreview::FloatingDragPreview(DockAreaWidget *content)
: FloatingDragPreview(static_cast<QWidget *>(content),
content->dockManager()) // TODO static_cast?
{
d->m_dockManager = content->dockManager();
d->m_contentSourceArea = content;
setWindowTitle(content->currentDockWidget()->windowTitle());
}
FloatingDragPreview::~FloatingDragPreview()
{
delete d;
}
void FloatingDragPreview::moveFloating()
{
const int borderSize = (frameSize().width() - size().width()) / 2;
const QPoint moveToPos = QCursor::pos() - d->m_dragStartMousePosition - QPoint(borderSize, 0);
move(moveToPos);
d->updateDropOverlays(QCursor::pos());
}
void FloatingDragPreview::startFloating(const QPoint &dragStartMousePos,
const QSize &size,
eDragState dragState,
QWidget *mouseEventHandler)
{
Q_UNUSED(mouseEventHandler)
Q_UNUSED(dragState)
resize(size);
d->m_dragStartMousePosition = dragStartMousePos;
moveFloating();
show();
}
void FloatingDragPreview::finishDragging()
{
qCInfo(adsLog) << Q_FUNC_INFO;
auto dockDropArea = d->m_dockManager->dockAreaOverlay()->visibleDropAreaUnderCursor();
auto containerDropArea = d->m_dockManager->containerOverlay()->visibleDropAreaUnderCursor();
bool validDropArea = (dockDropArea != InvalidDockWidgetArea)
|| (containerDropArea != InvalidDockWidgetArea);
// Non floatable auto hide widgets should stay in its current auto hide state if they are
// dragged into a floating window.
if (validDropArea || d->isContentFloatable())
cleanupAutoHideContainerWidget();
if (!d->m_dropContainer) {
d->createFloatingWidget();
} else if (dockDropArea != InvalidDockWidgetArea) {
d->m_dropContainer->dropWidget(d->m_content,
dockDropArea,
d->m_dropContainer->dockAreaAt(QCursor::pos()));
} else if (containerDropArea != InvalidDockWidgetArea) {
// If there is only one single dock area, and we drop into the center then we tabify the
// dropped widget into the only visible dock area.
if (d->m_dropContainer->visibleDockAreaCount() <= 1
&& CenterDockWidgetArea == containerDropArea)
d->m_dropContainer->dropWidget(d->m_content,
containerDropArea,
d->m_dropContainer->dockAreaAt(QCursor::pos()));
else
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, nullptr);
} else {
d->createFloatingWidget();
}
close();
d->m_dockManager->containerOverlay()->hideOverlay();
d->m_dockManager->dockAreaOverlay()->hideOverlay();
}
void FloatingDragPreview::cleanupAutoHideContainerWidget()
{
auto droppedDockWidget = qobject_cast<DockWidget *>(d->m_content);
if (droppedDockWidget && droppedDockWidget->autoHideDockContainer())
droppedDockWidget->autoHideDockContainer()->cleanupAndDelete();
auto droppedArea = qobject_cast<DockAreaWidget *>(d->m_content);
if (droppedArea && droppedArea->autoHideDockContainer())
droppedArea->autoHideDockContainer()->cleanupAndDelete();
}
void FloatingDragPreview::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
if (d->m_hidden)
return;
QPainter painter(this);
if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap))
painter.drawPixmap(QPoint(0, 0), d->m_contentPreviewPixmap);
// If we do not have a window frame then we paint a QRubberBand like frameless window
if (!DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
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);
painter.setBrush(color);
painter.drawRect(rect().adjusted(0, 0, -1, -1));
}
}
void FloatingDragPreview::onApplicationStateChanged(Qt::ApplicationState state)
{
if (state != Qt::ApplicationActive) {
disconnect(qApp,
&QApplication::applicationStateChanged,
this,
&FloatingDragPreview::onApplicationStateChanged);
d->cancelDragging();
}
}
bool FloatingDragPreview::eventFilter(QObject *watched, QEvent *event)
{
if (!d->m_canceled && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Escape) {
watched->removeEventFilter(this);
d->cancelDragging();
}
}
bool FloatingDragPreview::eventFilter(QObject *watched, QEvent *event)
{
if (!d->m_canceled && event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Escape) {
watched->removeEventFilter(this);
d->cancelDragging();
}
}
return false;
}
return false;
}
} // namespace ADS

View File

@@ -86,6 +86,11 @@ public: // implements AbstractFloatingWidget
*/
void finishDragging() override;
/**
* Cleanup auto hide container if the dragged widget has one.
*/
void cleanupAutoHideContainerWidget();
signals:
/**
* This signal is emitted, if dragging has been canceled by escape key

View File

@@ -6,44 +6,45 @@
#include <QVector>
namespace ADS {
/**
* Private data class (pimpl)
*/
struct IconProviderPrivate
{
IconProvider *q;
QVector<QIcon> m_userIcons{IconCount, QIcon()};
/**
* Private data class (pimpl)
* Private data constructor
*/
struct IconProviderPrivate
{
IconProvider *q;
QVector<QIcon> m_userIcons{IconCount, QIcon()};
IconProviderPrivate(IconProvider *parent);
};
// struct IconProviderPrivate
/**
* Private data constructor
*/
IconProviderPrivate(IconProvider *parent);
};
// struct IconProviderPrivate
IconProviderPrivate::IconProviderPrivate(IconProvider *parent)
: q(parent)
{}
IconProviderPrivate::IconProviderPrivate(IconProvider *parent)
: q(parent)
{}
IconProvider::IconProvider()
: d(new IconProviderPrivate(this))
{}
IconProvider::IconProvider()
: d(new IconProviderPrivate(this))
{}
IconProvider::~IconProvider()
{
delete d;
}
IconProvider::~IconProvider()
{
delete d;
}
QIcon IconProvider::customIcon(eIcon iconId) const
{
Q_ASSERT(iconId < d->m_userIcons.size());
return d->m_userIcons[iconId];
}
QIcon IconProvider::customIcon(eIcon iconId) const
{
Q_ASSERT(iconId < d->m_userIcons.size());
return d->m_userIcons[iconId];
}
void IconProvider::registerCustomIcon(eIcon iconId, const QIcon &icon)
{
Q_ASSERT(iconId < d->m_userIcons.size());
d->m_userIcons[iconId] = icon;
}
void IconProvider::registerCustomIcon(eIcon iconId, const QIcon &icon)
{
Q_ASSERT(iconId < d->m_userIcons.size());
d->m_userIcons[iconId] = icon;
}
} // namespace ADS

View File

@@ -12,8 +12,7 @@ namespace ADS {
struct IconProviderPrivate;
/**
* This object provides all icons that are required by the advanced docking
* system.
* This object provides all icons that are required by the advanced docking system.
* The IconProvider enables the user to register custom icons in case using
* stylesheets is not an option.
*/

View File

@@ -4,8 +4,10 @@
#include "floatingwidgettitlebar.h"
#include "ads_globals.h"
#include "dockmanager.h"
#include "elidinglabel.h"
#include "floatingdockcontainer.h"
#include "iconprovider.h"
#include <QHBoxLayout>
#include <QMouseEvent>
@@ -20,6 +22,7 @@ namespace ADS {
using TabLabelType = ElidingLabel;
using CloseButtonType = QToolButton;
using MaximizeButtonType = QToolButton;
/**
* @brief Private data class of public interface CFloatingWidgetTitleBar
@@ -31,8 +34,12 @@ public:
QLabel *m_iconLabel = nullptr;
TabLabelType *m_titleLabel = nullptr;
CloseButtonType *m_closeButton = nullptr;
MaximizeButtonType *m_maximizeButton = nullptr;
FloatingDockContainer *m_floatingWidget = nullptr;
eDragState m_dragState = DraggingInactive;
QIcon m_maximizeIcon;
QIcon m_normalIcon;
bool m_maximized = false;
FloatingWidgetTitleBarPrivate(FloatingWidgetTitleBar *parent)
: q(parent)
@@ -46,15 +53,18 @@ public:
void FloatingWidgetTitleBarPrivate::createLayout()
{
// Title label
m_titleLabel = new TabLabelType();
m_titleLabel->setElideMode(Qt::ElideRight);
m_titleLabel->setText("DockWidget->windowTitle()");
m_titleLabel->setObjectName("floatingTitleLabel");
m_titleLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
// Close button
m_closeButton = new CloseButtonType();
m_closeButton->setObjectName("floatingTitleCloseButton");
m_closeButton->setAutoRaise(true);
internal::setButtonIcon(m_closeButton,
QStyle::SP_TitleBarCloseButton,
ADS::FloatingWidgetCloseIcon);
@@ -68,6 +78,21 @@ void FloatingWidgetTitleBarPrivate::createLayout()
q,
&FloatingWidgetTitleBar::closeRequested);
// Maximize button
m_maximizeButton = new MaximizeButtonType();
m_maximizeButton->setObjectName("floatingTitleMaxButton");
m_maximizeButton->setAutoRaise(true);
m_maximizeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_maximizeButton->setIconSize(QSize(11, 11));
m_maximizeButton->setFixedSize(QSize(17, 17));
m_maximizeButton->setVisible(true);
m_maximizeButton->setFocusPolicy(Qt::NoFocus);
QObject::connect(m_maximizeButton,
&QPushButton::clicked,
q,
&FloatingWidgetTitleBar::maximizeRequested);
QFontMetrics fontMetrics(m_titleLabel->font());
int spacing = qRound(fontMetrics.height() / 4.0);
@@ -78,6 +103,7 @@ void FloatingWidgetTitleBarPrivate::createLayout()
q->setLayout(layout);
layout->addWidget(m_titleLabel, 1);
layout->addSpacing(spacing);
layout->addWidget(m_maximizeButton);
layout->addWidget(m_closeButton);
layout->addSpacing(1);
layout->setAlignment(Qt::AlignCenter);
@@ -91,6 +117,26 @@ FloatingWidgetTitleBar::FloatingWidgetTitleBar(FloatingDockContainer *parent)
{
d->m_floatingWidget = parent;
d->createLayout();
d->m_normalIcon = DockManager::iconProvider().customIcon(ADS::FloatingWidgetNormalIcon);
if (d->m_normalIcon.isNull()) {
auto normalPixmap = style()->standardPixmap(QStyle::SP_TitleBarNormalButton,
0,
d->m_maximizeButton);
d->m_normalIcon.addPixmap(normalPixmap, QIcon::Normal);
d->m_normalIcon.addPixmap(internal::createTransparentPixmap(normalPixmap, 0.25),
QIcon::Disabled);
}
d->m_maximizeIcon = DockManager::iconProvider().customIcon(ADS::FloatingWidgetMaximizeIcon);
if (d->m_maximizeIcon.isNull()) {
auto maxPixmap = this->style()->standardPixmap(QStyle::SP_TitleBarMaxButton,
0,
d->m_maximizeButton);
d->m_maximizeIcon.addPixmap(maxPixmap, QIcon::Normal);
d->m_maximizeIcon.addPixmap(internal::createTransparentPixmap(maxPixmap, 0.25),
QIcon::Disabled);
}
}
FloatingWidgetTitleBar::~FloatingWidgetTitleBar()
@@ -125,8 +171,11 @@ void FloatingWidgetTitleBar::mouseMoveEvent(QMouseEvent *event)
return;
}
// move floating window
// Move floating window
if (DraggingFloatingWidget == d->m_dragState) {
if (d->m_floatingWidget->isMaximized())
d->m_floatingWidget->showNormal(true);
d->m_floatingWidget->moveFloating();
Super::mouseMoveEvent(event);
return;
@@ -134,6 +183,16 @@ void FloatingWidgetTitleBar::mouseMoveEvent(QMouseEvent *event)
Super::mouseMoveEvent(event);
}
void FloatingWidgetTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
emit maximizeRequested();
event->accept();
} else {
QWidget::mouseDoubleClickEvent(event);
}
}
void FloatingWidgetTitleBar::enableCloseButton(bool enable)
{
d->m_closeButton->setEnabled(enable);
@@ -149,4 +208,13 @@ void FloatingWidgetTitleBar::updateStyle()
internal::repolishStyle(this, internal::RepolishDirectChildren);
}
void FloatingWidgetTitleBar::setMaximizedIcon(bool maximized)
{
d->m_maximized = maximized;
if (maximized)
d->m_maximizeButton->setIcon(d->m_normalIcon);
else
d->m_maximizeButton->setIcon(d->m_maximizeIcon);
}
} // namespace ADS

View File

@@ -4,6 +4,7 @@
#pragma once
#include <QFrame>
#include <QIcon>
namespace ADS {
@@ -11,11 +12,10 @@ class FloatingDockContainer;
class FloatingWidgetTitleBarPrivate;
/**
* Titlebar for floating widgets to capture non client are mouse events.
* Title bar for floating widgets to capture non client area mouse events.
* Linux does not support NonClientArea mouse events like
* QEvent::NonClientAreaMouseButtonPress. Because these events are required
* for the docking system to work properly, we use our own titlebar here to
* capture the required mouse events.
* QEvent::NonClientAreaMouseButtonPress. Because these events are required for the docking system
* to work properly, we use our own titlebar here to capture the required mouse events.
*/
class FloatingWidgetTitleBar : public QFrame
{
@@ -27,6 +27,7 @@ protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
public:
using Super = QWidget;
@@ -52,11 +53,21 @@ public:
*/
void updateStyle();
/**
* Change the maximize button icon according to current windows state
*/
void setMaximizedIcon(bool maximized);
signals:
/**
* This signal is emitted, if the close button is clicked.
*/
void closeRequested();
/**
* This signal is emitted, if the maximize button is clicked.
*/
void maximizeRequested();
};
} // namespace ADS

View File

@@ -0,0 +1,55 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#include "pushbutton.h"
#include <QPainter>
#include <QStyleOptionButton>
#include <QDebug>
#include <QStylePainter>
namespace ADS {
QSize PushButton::sizeHint() const
{
QSize sh = QPushButton::sizeHint();
if (m_orientation != PushButton::Horizontal)
sh.transpose();
return sh;
}
PushButton::Orientation PushButton::buttonOrientation() const
{
return m_orientation;
}
void PushButton::setButtonOrientation(Orientation orientation)
{
m_orientation = orientation;
updateGeometry();
}
void PushButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QStylePainter painter(this);
QStyleOptionButton option;
initStyleOption(&option);
if (m_orientation == PushButton::VerticalTopToBottom) {
painter.rotate(90);
painter.translate(0, -1 * width());
option.rect = option.rect.transposed();
} else if (m_orientation == PushButton::VerticalBottomToTop) {
painter.rotate(-90);
painter.translate(-1 * height(), 0);
option.rect = option.rect.transposed();
}
painter.drawControl(QStyle::CE_PushButton, option);
}
} // namespace ADS

View File

@@ -0,0 +1,47 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#pragma once
#include "ads_globals.h"
#include <QPushButton>
namespace ADS {
/**
* ADS specific push button class with orientation support
*/
class ADS_EXPORT PushButton : public QPushButton
{
Q_OBJECT
public:
enum Orientation {
Horizontal,
VerticalTopToBottom,
VerticalBottomToTop
};
using QPushButton::QPushButton;
virtual QSize sizeHint() const override;
/**
* Returns the current orientation
*/
Orientation buttonOrientation() const;
/**
* Set the orientation of this button
*/
void setButtonOrientation(Orientation orientation);
protected:
virtual void paintEvent(QPaintEvent *event) override;
private:
Orientation m_orientation = Horizontal;
}; // class PushButton
} // namespace ADS

View File

@@ -0,0 +1,269 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#include "resizehandle.h"
#include <QDebug>
#include <QStyle>
#include <QStyleOption>
#include <QMouseEvent>
#include <QRubberBand>
#include <QPointer>
namespace ADS {
/**
* Private data class of CResizeHandle class (pimpl)
*/
class ResizeHandlePrivate
{
public:
ResizeHandle *q = nullptr;
Qt::Edge m_handlePosition = Qt::LeftEdge;
QWidget *m_target = nullptr;
int m_mouseOffset = 0;
bool m_pressed = false;
int m_minSize = 0;
int m_maxSize = 1;
QPointer<QRubberBand> m_rubberBand;
bool m_opaqueResize = false;
int m_handleWidth = 4;
/**
* Private data constructor
*/
ResizeHandlePrivate(ResizeHandle *parent);
/**
* Pick position component from pos depending on orientation
*/
int pick(const QPoint &pos) const
{
return q->orientation() == Qt::Horizontal ? pos.x() : pos.y();
}
/**
* Returns true, if orientation is horizontal
*/
bool isHorizontal() const { return q->orientation() == Qt::Horizontal; }
/**
* Set rubberband position
*/
void setRubberBand(int pos);
/**
* Calculates the resize position and geometry
*/
void doResizing(QMouseEvent *event, bool forceResize = false);
};
// class ResizeHandlePrivate
ResizeHandlePrivate::ResizeHandlePrivate(ResizeHandle *parent)
: q(parent)
{}
void ResizeHandlePrivate::setRubberBand(int pos)
{
if (!m_rubberBand)
m_rubberBand = new QRubberBand(QRubberBand::Line, m_target->parentWidget());
auto geometry = q->geometry();
auto topLeft = m_target->mapTo(m_target->parentWidget(), geometry.topLeft());
switch (m_handlePosition) {
case Qt::LeftEdge:
case Qt::RightEdge:
topLeft.rx() += pos;
break;
case Qt::TopEdge:
case Qt::BottomEdge:
topLeft.ry() += pos;
break;
}
geometry.moveTopLeft(topLeft);
m_rubberBand->setGeometry(geometry);
m_rubberBand->show();
}
void ResizeHandlePrivate::doResizing(QMouseEvent *event, bool forceResize)
{
int pos = pick(event->pos()) - m_mouseOffset;
auto oldGeometry = m_target->geometry();
auto newGeometry = oldGeometry;
switch (m_handlePosition) {
case Qt::LeftEdge: {
newGeometry.adjust(pos, 0, 0, 0);
int size = qBound(m_minSize, newGeometry.width(), m_maxSize);
pos += (newGeometry.width() - size);
newGeometry.setWidth(size);
newGeometry.moveTopRight(oldGeometry.topRight());
} break;
case Qt::RightEdge: {
newGeometry.adjust(0, 0, pos, 0);
int size = qBound(m_minSize, newGeometry.width(), m_maxSize);
pos -= (newGeometry.width() - size);
newGeometry.setWidth(size);
} break;
case Qt::TopEdge: {
newGeometry.adjust(0, pos, 0, 0);
int size = qBound(m_minSize, newGeometry.height(), m_maxSize);
pos += (newGeometry.height() - size);
newGeometry.setHeight(size);
newGeometry.moveBottomLeft(oldGeometry.bottomLeft());
} break;
case Qt::BottomEdge: {
newGeometry.adjust(0, 0, 0, pos);
int size = qBound(m_minSize, newGeometry.height(), m_maxSize);
pos -= (newGeometry.height() - size);
newGeometry.setHeight(size);
} break;
}
if (q->opaqueResize() || forceResize) {
m_target->setGeometry(newGeometry);
} else {
setRubberBand(pos);
}
}
ResizeHandle::ResizeHandle(Qt::Edge handlePosition, QWidget *parent)
: Super(parent)
, d(new ResizeHandlePrivate(this))
{
d->m_target = parent;
setMinResizeSize(48);
setHandlePosition(handlePosition);
}
ResizeHandle::~ResizeHandle()
{
delete d;
}
void ResizeHandle::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
return;
d->doResizing(event);
}
void ResizeHandle::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
d->m_mouseOffset = d->pick(event->pos());
d->m_pressed = true;
update();
}
}
void ResizeHandle::mouseReleaseEvent(QMouseEvent *event)
{
if (!opaqueResize() && event->button() == Qt::LeftButton) {
if (d->m_rubberBand)
d->m_rubberBand->deleteLater();
d->doResizing(event, true);
}
if (event->button() == Qt::LeftButton) {
d->m_pressed = false;
update();
}
}
void ResizeHandle::setHandlePosition(Qt::Edge handlePosition)
{
d->m_handlePosition = handlePosition;
switch (d->m_handlePosition) {
case Qt::LeftEdge: // fall through
case Qt::RightEdge:
setCursor(Qt::SizeHorCursor);
break;
case Qt::TopEdge: // fall through
case Qt::BottomEdge:
setCursor(Qt::SizeVerCursor);
break;
}
setMaxResizeSize(d->isHorizontal() ? parentWidget()->height() : parentWidget()->width());
if (!d->isHorizontal()) {
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
} else {
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
}
}
Qt::Edge ResizeHandle::handlePostion() const
{
return d->m_handlePosition;
}
Qt::Orientation ResizeHandle::orientation() const
{
switch (d->m_handlePosition) {
case Qt::LeftEdge: // fall through
case Qt::RightEdge:
return Qt::Horizontal;
case Qt::TopEdge: // fall through
case Qt::BottomEdge:
return Qt::Vertical;
}
return Qt::Horizontal;
}
QSize ResizeHandle::sizeHint() const
{
QSize result;
switch (d->m_handlePosition) {
case Qt::LeftEdge: // fall through
case Qt::RightEdge:
result = QSize(d->m_handleWidth, d->m_target->height());
break;
case Qt::TopEdge: // fall through
case Qt::BottomEdge:
result = QSize(d->m_target->width(), d->m_handleWidth);
break;
}
return result;
}
bool ResizeHandle::isResizing() const
{
return d->m_pressed;
}
void ResizeHandle::setMinResizeSize(int minSize)
{
d->m_minSize = minSize;
}
void ResizeHandle::setMaxResizeSize(int maxSize)
{
d->m_maxSize = maxSize;
}
void ResizeHandle::setOpaqueResize(bool opaque)
{
if (d->m_opaqueResize == opaque)
return;
d->m_opaqueResize = opaque;
emit opaqueResizeChanged();
}
bool ResizeHandle::opaqueResize() const
{
return d->m_opaqueResize;
}
} // namespace ADS

View File

@@ -0,0 +1,99 @@
// Copyright (C) 2020 Uwe Kindler
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#pragma once
#include "ads_globals.h"
#include <QFrame>
namespace ADS {
class ResizeHandlePrivate;
/**
* Resize handle for resizing its parent widget
*/
class ADS_EXPORT ResizeHandle : public QFrame
{
Q_OBJECT
Q_DISABLE_COPY(ResizeHandle)
Q_PROPERTY(bool opaqueResize READ opaqueResize WRITE setOpaqueResize NOTIFY opaqueResizeChanged)
private:
ResizeHandlePrivate *d; ///< private data (pimpl)
friend class ResizeHandlePrivate;
protected:
void mouseMoveEvent(QMouseEvent *) override;
void mousePressEvent(QMouseEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
public:
using Super = QFrame;
/**
* Default Constructor
*/
ResizeHandle(Qt::Edge handlePosition, QWidget *parent);
/**
* Virtual Destructor
*/
virtual ~ResizeHandle();
/**
* Sets the handle position
*/
void setHandlePosition(Qt::Edge handlePosition);
/**
* Returns the handle position
*/
Qt::Edge handlePostion() const;
/**
* Returns the orientation of this resize handle
*/
Qt::Orientation orientation() const;
/**
* Returns the size hint
*/
QSize sizeHint() const override;
/**
* Returns true, if resizing is active
*/
bool isResizing() const;
/**
* Sets the minimum size for the widget that is going to be resized.
* The resize handle will not resize the target widget to a size smaller
* than this value
*/
void setMinResizeSize(int minSize);
/**
* Sets the maximum size for the widget that is going to be resized
* The resize handle will not resize the target widget to a size bigger
* than this value
*/
void setMaxResizeSize(int maxSize);
/**
* Enable / disable opaque resizing
*/
void setOpaqueResize(bool opaque = true);
/**
* Returns true if widgets are resized dynamically (opaquely) while
* interactively moving the resize handle. Otherwise returns false.
*/
bool opaqueResize() const;
signals:
void opaqueResizeChanged();
}; // class ResizeHandle
} // namespace ADS

View File

@@ -93,6 +93,20 @@ ADS--TitleBarButton:press {
background: creatorTheme.DStitleBarButtonPress;
}
#floatingTitleMaxButton {
margin: 1px;
background: none;
border: none;
}
#floatingTitleMaxButton:hover {
background: creatorTheme.DStitleBarButtonHover;
}
#floatingTitleMaxButton:pressed {
background: creatorTheme.DStitleBarButtonPress;
}
QScrollArea#dockWidgetScrollArea {
background-color: creatorTheme.DSpanelBackground;
padding: 0px;
@@ -139,3 +153,180 @@ ADS--DockAreaTitleBar {
ADS--DockAreaWidget[focused="true"] ADS--DockAreaTitleBar {
border-bottom-color: creatorTheme.DStabFocusBackground;
}
ADS--AutoHideTab {
qproperty-iconSize: 16px 16px; /* this is optional in case you would like to change icon size */
background: none;
border: none;
padding-left: 2px;
padding-right: 0px;
text-align: center;
min-height: 20px;
padding-bottom: 2px;
}
ADS--AutoHideTab:hover {
color: creatorTheme.DSinteraction;
}
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="0"],
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="2"] {
border-top: 6px solid rgba(0, 0, 0, 48);
}
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="1"],
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="3"] {
border-bottom: 6px solid rgba(0, 0, 0, 48);
}
ADS--AutoHideTab:hover[iconOnly="false"][sideBarLocation="0"],
ADS--AutoHideTab:hover[iconOnly="false"][sideBarLocation="2"],
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="0"][activeTab="true"],
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="2"][activeTab="true"] {
border-top: 6px solid creatorTheme.DSinteraction;
}
ADS--AutoHideTab:hover[iconOnly="false"][sideBarLocation="1"],
ADS--AutoHideTab:hover[iconOnly="false"][sideBarLocation="3"],
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="1"][activeTab="true"],
ADS--AutoHideTab[iconOnly="false"][sideBarLocation="3"][activeTab="true"] {
border-bottom: 6px solid creatorTheme.DSinteraction;
}
/* Auto hide tabs with icon only */
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="0"] {
border-top: 6px solid rgba(0, 0, 0, 48);
}
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="1"] {
border-left: 6px solid rgba(0, 0, 0, 48);
}
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="2"] {
border-right: 6px solid rgba(0, 0, 0, 48);
}
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="3"] {
border-bottom: 6px solid rgba(0, 0, 0, 48);
}
/* Auto hide tabs with icon only hover */
ADS--AutoHideTab:hover[iconOnly="true"][sideBarLocation="0"],
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="0"][activeTab="true"] {
border-top: 6px solid creatorTheme.DSinteraction;
}
ADS--AutoHideTab:hover[iconOnly="true"][sideBarLocation="1"],
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="1"][activeTab="true"] {
border-left: 6px solid creatorTheme.DSinteraction;
}
ADS--AutoHideTab:hover[iconOnly="true"][sideBarLocation="2"],
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="2"][activeTab="true"] {
border-right: 6px solid creatorTheme.DSinteraction;
}
ADS--AutoHideTab:hover[iconOnly="true"][sideBarLocation="3"],
ADS--AutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] {
border-bottom: 6px solid creatorTheme.DSinteraction;
}
/* AutoHideSideBar */
ADS--AutoHideSideBar {
background: palette(window);
border: none;
qproperty-spacing: 12;
}
#sideTabsContainerWidget {
background: transparent;
}
ADS--AutoHideSideBar[sideBarLocation="0"] {
border-bottom: 1px solid palette(dark);
}
ADS--AutoHideSideBar[sideBarLocation="1"] {
border-right: 1px solid palette(dark);
}
ADS--AutoHideSideBar[sideBarLocation="2"] {
border-left: 1px solid palette(dark);
}
ADS--AutoHideSideBar[sideBarLocation="3"] {
border-top: 1px solid palette(dark);
}
/* AutoHideDockContainer */
ADS--AutoHideDockContainer {
background: palette(window);
}
ADS--AutoHideDockContainer ADS--DockAreaTitleBar {
background: creatorTheme.DSinteraction;
padding: 0px;
border: none;
}
/*
* This is required because the ADS--DockAreaWidget[focused="true"] will
* overwrite the ADS--AutoHideDockContainer ADS--DockAreaTitleBar rule
*/
ADS--AutoHideDockContainer ADS--DockAreaWidget[focused="true"] ADS--DockAreaTitleBar {
background: creatorTheme.DSinteraction;
padding: 0px;
border: none;
}
#autoHideTitleLabel {
padding-left: 4px;
color: palette(light);
}
/* AutoHideDockContainer titlebar buttons */
#dockAreaAutoHideButton {
/*qproperty-icon: url(:/ads/images/vs-pin-button.svg);*/
qproperty-iconSize: 16px;
}
ADS--AutoHideDockContainer #dockAreaAutoHideButton {
/*qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg);*/
qproperty-iconSize: 16px;
}
ADS--AutoHideDockContainer #dockAreaCloseButton{
/*qproperty-icon: url(:/ads/images/close-button-focused.svg)*/
}
ADS--AutoHideDockContainer ADS--TitleBarButton:hover {
background: rgba(255, 255, 255, 48);
}
ads--CAutoHideDockContainer ADS--TitleBarButton:pressed {
background: rgba(255, 255, 255, 96);
}
/* AutoHideDockContainer Titlebar and Buttons */
/* ResizeHandle */
ADS--ResizeHandle {
background: palette(window);
}
ADS--AutoHideDockContainer[sideBarLocation="0"] ADS--ResizeHandle {
border-top: 1px solid palette(dark);
}
ADS--AutoHideDockContainer[sideBarLocation="1"] ADS--ResizeHandle {
border-left: 1px solid palette(dark);
}
ADS--AutoHideDockContainer[sideBarLocation="2"] ADS--ResizeHandle {
border-right: 1px solid palette(dark);
}
ADS--AutoHideDockContainer[sideBarLocation="3"] ADS--ResizeHandle {
border-top: 1px solid palette(dark);
}

View File

@@ -179,7 +179,11 @@ void DesignModeWidget::setup()
ADS::DockManager::setConfigFlag(ADS::DockManager::DockAreaHasUndockButton, false);
ADS::DockManager::setConfigFlag(ADS::DockManager::DockAreaHasTabsMenuButton, false);
ADS::DockManager::setConfigFlag(ADS::DockManager::OpaqueSplitterResize, true);
ADS::DockManager::setConfigFlag(ADS::DockManager::AllTabsHaveCloseButton, true);
ADS::DockManager::setConfigFlag(ADS::DockManager::AllTabsHaveCloseButton, false);
ADS::DockManager::setConfigFlag(ADS::DockManager::RetainTabSizeWhenCloseButtonHidden, true);
//ADS::DockManager::setAutoHideConfigFlags(ADS::DockManager::DefaultAutoHideConfig);
m_dockManager = new ADS::DockManager(this);
m_dockManager->setSettings(settings);
m_dockManager->setWorkspacePresetsPath(
@@ -190,7 +194,9 @@ void DesignModeWidget::setup()
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
// Setup icons
const QString closeUnicode = Theme::getIconUnicode(Theme::Icon::adsClose);
const QString closeUnicode = Theme::getIconUnicode(Theme::Icon::close_small);
const QString maximizeUnicode = Theme::getIconUnicode(Theme::Icon::maxBar_small);
const QString normalUnicode = Theme::getIconUnicode(Theme::Icon::normalBar_small);
const QString fontName = "qtds_propertyIconFont.ttf";
const QSize size = QSize(28, 28);
@@ -202,13 +208,41 @@ void DesignModeWidget::setup()
auto tabCloseIconFocus = Utils::StyleHelper::IconFontHelper(
closeUnicode, Theme::getColor(Theme::DSdockWidgetTitleBar), size, QIcon::Selected, QIcon::Off);
const QIcon tabsCloseIcon = Utils::StyleHelper::getIconFromIconFont(
fontName, {tabCloseIconNormal,
tabCloseIconActive,
tabCloseIconFocus});
const QIcon tabsCloseIcon = Utils::StyleHelper::getIconFromIconFont(fontName,
{tabCloseIconNormal,
tabCloseIconActive,
tabCloseIconFocus});
ADS::DockManager::iconProvider().registerCustomIcon(ADS::TabCloseIcon, tabsCloseIcon);
auto floatingWidgetCloseIconNormal = Utils::StyleHelper::IconFontHelper(
closeUnicode, Theme::getColor(Theme::DStitleBarText), QSize(17, 17), QIcon::Normal, QIcon::Off);
const QIcon floatingWidgetCloseIcon = Utils::StyleHelper::getIconFromIconFont(
fontName, {floatingWidgetCloseIconNormal});
ADS::DockManager::iconProvider().registerCustomIcon(ADS::FloatingWidgetCloseIcon,
floatingWidgetCloseIcon);
auto floatingWidgetMaxIconNormal = Utils::StyleHelper::IconFontHelper(maximizeUnicode,
Theme::getColor(
Theme::DStitleBarText),
QSize(17, 17),
QIcon::Normal,
QIcon::Off);
const QIcon floatingWidgetMaxIcon = Utils::StyleHelper::getIconFromIconFont(
fontName, {floatingWidgetMaxIconNormal});
ADS::DockManager::iconProvider().registerCustomIcon(ADS::FloatingWidgetMaximizeIcon,
floatingWidgetMaxIcon);
auto floatingWidgetNormalIconNormal = Utils::StyleHelper::IconFontHelper(
normalUnicode, Theme::getColor(Theme::DStitleBarText), QSize(17, 17), QIcon::Normal, QIcon::Off);
const QIcon floatingWidgetNormalIcon = Utils::StyleHelper::getIconFromIconFont(
fontName, {floatingWidgetNormalIconNormal});
ADS::DockManager::iconProvider().registerCustomIcon(ADS::FloatingWidgetNormalIcon,
floatingWidgetNormalIcon);
// Setup Actions and Menus
Core::ActionContainer *mview = Core::ActionManager::actionContainer(Core::Constants::M_VIEW);
// View > Views