Add initial functionality for Auto hide

- Add left and right side tab widgets
- Add overlay dock and overlay dock widget behavior
This commit is contained in:
Syarif Fakhri 2022-09-05 17:29:42 +08:00
parent da8f17cce2
commit 3e9dc7f4d6
28 changed files with 1530 additions and 28 deletions

View File

@ -27,6 +27,9 @@ set(ads_SRCS
FloatingDragPreview.cpp
IconProvider.cpp
DockComponentsFactory.cpp
SideTabBar.cpp
DockWidgetSideTab.cpp
OverlayDockContainer.cpp
ads.qrc
)
set(ads_HEADERS
@ -48,6 +51,9 @@ set(ads_HEADERS
FloatingDragPreview.h
IconProvider.h
DockComponentsFactory.h
SideTabBar.h
DockWidgetSideTab.h
OverlayDockContainer.h
)
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
if (UNIX AND NOT APPLE)

View File

@ -52,6 +52,7 @@
#include "IconProvider.h"
#include "DockComponentsFactory.h"
#include "DockFocusController.h"
#include "OverlayDockContainer.h"
#include <iostream>
@ -65,6 +66,7 @@ struct DockAreaTitleBarPrivate
{
CDockAreaTitleBar* _this;
QPointer<tTitleBarButton> TabsMenuButton;
QPointer<tTitleBarButton> AutoHideButton;
QPointer<tTitleBarButton> UndockButton;
QPointer<tTitleBarButton> CloseButton;
QBoxLayout* Layout;
@ -162,6 +164,19 @@ void DockAreaTitleBarPrivate::createButtons()
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
SLOT(onTabsMenuActionTriggered(QAction*)));
// AutoHide Button
const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar);
AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled);
AutoHideButton->setObjectName("autoHideButton");
AutoHideButton->setAutoRaise(true);
AutoHideButton->setCheckable(true);
AutoHideButton->setChecked(false);
internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide Group"));
internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::DockAreaUndockIcon);
AutoHideButton->setSizePolicy(ButtonSizePolicy);
Layout->addWidget(AutoHideButton, 0);
_this->connect(AutoHideButton, SIGNAL(toggled(bool)), SLOT(onAutoHideButtonClicked(bool)));
// Undock button
UndockButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasUndockButton));
UndockButton->setObjectName("detachGroupButton");
@ -249,6 +264,10 @@ IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset,
//============================================================================
void DockAreaTitleBarPrivate::startFloating(const QPoint& Offset)
{
if (DockArea->overlayDockContainer() != nullptr)
{
DockArea->overlayDockContainer()->hide();
}
FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget);
}
@ -438,6 +457,14 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index)
updateDockWidgetActionsButtons();
}
void CDockAreaTitleBar::onAutoHideButtonClicked(bool Checked)
{
if (Checked != d->DockArea->isOverlayed())
{
d->DockArea->toggleAutoHideArea();
}
}
//============================================================================
QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const
@ -447,6 +474,7 @@ QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const
case TitleBarButtonTabsMenu: return d->TabsMenuButton;
case TitleBarButtonUndock: return d->UndockButton;
case TitleBarButtonClose: return d->CloseButton;
case TitleBarButtonAutoHide: return d->AutoHideButton;
default:
return nullptr;
}
@ -523,7 +551,8 @@ void CDockAreaTitleBar::mouseMoveEvent(QMouseEvent* ev)
// sense to move it to a new floating widget and leave this one
// empty
if (d->DockArea->dockContainer()->isFloating()
&& d->DockArea->dockContainer()->visibleDockAreaCount() == 1)
&& d->DockArea->dockContainer()->visibleDockAreaCount() == 1
&& !d->DockArea->isOverlayed())
{
return;
}

View File

@ -60,9 +60,10 @@ private Q_SLOTS:
void onUndockButtonClicked();
void onTabsMenuActionTriggered(QAction* Action);
void onCurrentTabChanged(int Index);
void onAutoHideButtonClicked(bool Checked);
protected:
/**
/**
* Stores mouse position to detect dragging
*/
virtual void mousePressEvent(QMouseEvent* ev) override;

View File

@ -54,6 +54,9 @@
#include "DockAreaTitleBar.h"
#include "DockComponentsFactory.h"
#include "DockWidgetTab.h"
#include "SideTabBar.h"
#include "DockWidgetSideTab.h"
#include "OverlayDockContainer.h"
namespace ads
@ -249,6 +252,7 @@ struct DockAreaWidgetPrivate
DockAreaLayout* ContentsLayout = nullptr;
CDockAreaTitleBar* TitleBar = nullptr;
CDockManager* DockManager = nullptr;
COverlayDockContainer* OverlayDockContainer = nullptr;
bool UpdateTitleBarButtons = false;
DockWidgetAreas AllowedAreas = DefaultAllowedAreas;
QSize MinSizeHint;
@ -358,6 +362,7 @@ void DockAreaWidgetPrivate::updateTitleBarButtonStates()
_this->features().testFlag(CDockWidget::DockWidgetClosable));
TitleBar->button(TitleBarButtonUndock)->setEnabled(
_this->features().testFlag(CDockWidget::DockWidgetFloatable));
TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isOverlayed());
TitleBar->updateDockWidgetActionsButtons();
UpdateTitleBarButtons = false;
}
@ -404,6 +409,24 @@ CDockContainerWidget* CDockAreaWidget::dockContainer() const
return internal::findParent<CDockContainerWidget*>(this);
}
//============================================================================
COverlayDockContainer* CDockAreaWidget::overlayDockContainer() const
{
return d->OverlayDockContainer;
}
//============================================================================
bool CDockAreaWidget::isOverlayed() const
{
return d->OverlayDockContainer != nullptr;
}
//============================================================================
void CDockAreaWidget::setOverlayDockContainer(COverlayDockContainer* OverlayDockContainer)
{
d->OverlayDockContainer = OverlayDockContainer;
}
//============================================================================
void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget)
@ -530,6 +553,10 @@ void CDockAreaWidget::hideAreaWithNoVisibleContent()
{
FloatingWidget->hide();
}
if (isOverlayed())
{
overlayDockContainer()->hide();
}
}
@ -757,7 +784,8 @@ void CDockAreaWidget::updateTitleBarVisibility()
bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating()
|| CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar));
Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1);
d->TitleBar->setVisible(!Hidden);
d->TitleBar->setVisible(isOverlayed() ? true : !Hidden); // Titlebar must always be visible when overlayed so it can be dragged
d->TitleBar->tabBar()->setVisible(isOverlayed() ? false : !Hidden); // Never show tab bar when overlayed
}
}
@ -783,6 +811,11 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
s.writeAttribute("Current", Name);
// To keep the saved XML data small, we only save the allowed areas and the
// dock area flags if the values are different from the default values
if (isOverlayed())
{
overlayDockContainer()->saveState(s);
}
if (d->AllowedAreas != DefaultAllowedAreas)
{
s.writeAttribute("AllowedAreas", QString::number(d->AllowedAreas, 16));
@ -957,8 +990,9 @@ void CDockAreaWidget::closeArea()
{
// If there is only one single dock widget and this widget has the
// DeleteOnClose feature, then we delete the dock widget now
// Note: Auto hide and overlays do not support dock widget delete on close
auto OpenDockWidgets = openedDockWidgets();
if (OpenDockWidgets.count() == 1 && OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
if (OpenDockWidgets.count() == 1 && OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && !isOverlayed())
{
OpenDockWidgets[0]->closeDockWidgetInternal();
}
@ -966,7 +1000,7 @@ void CDockAreaWidget::closeArea()
{
for (auto DockWidget : openedDockWidgets())
{
if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && DockWidget->features().testFlag(CDockWidget::DockWidgetForceCloseWithArea))
if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && DockWidget->features().testFlag(CDockWidget::DockWidgetForceCloseWithArea) && !isOverlayed())
DockWidget->closeDockWidgetInternal();
else
DockWidget->toggleView(false);
@ -974,6 +1008,31 @@ void CDockAreaWidget::closeArea()
}
}
//============================================================================
void CDockAreaWidget::toggleAutoHideArea()
{
const auto area = dockContainer()->getDockAreaPosition(this);
for (const auto DockWidget : openedDockWidgets())
{
onAutoHideToggleRequested(DockWidget, !isOverlayed(), area);
}
}
//============================================================================
void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, SideTabBarArea area)
{
if (Enable)
{
dockContainer()->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget());
DockWidget->sideTabWidget()->show();
dockContainer()->createDockWidgetOverlayContainer(area, DockWidget);
toggleView(false);
}
else
{
overlayDockContainer()->moveContentsToParent();
}
}
//============================================================================
void CDockAreaWidget::closeOtherAreas()

View File

@ -65,6 +65,7 @@ private:
friend class CDockWidget;
friend struct DockManagerPrivate;
friend class CDockManager;
friend class COverlayDockContainer;
void onDockWidgetFeaturesChanged();
private Q_SLOTS:
@ -186,6 +187,23 @@ public:
*/
CDockContainerWidget* dockContainer() const;
/**
* Returns the overlay dock container widget this dock area widget belongs to or 0
* if there is no
*/
COverlayDockContainer* overlayDockContainer() const;
/**
* Returns true if the dock area exists in an overlay dock container
*/
bool isOverlayed() const;
/**
* Sets the current overlay dock container
*/
void setOverlayDockContainer(COverlayDockContainer* OverlayDockContainer);
/**
* Returns the largest minimumSizeHint() of the dock widgets in this
* area.
@ -337,6 +355,16 @@ public Q_SLOTS:
void closeArea();
/**
* Toggles the Auto hides behaviour of the dock area and all dock widgets in this area
*/
void toggleAutoHideArea();
/**
* Auto hides the dock area and all dock widgets in this area
*/
void onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, SideTabBarArea area);
/**
* This function closes all other areas except of this area
*/
void closeOtherAreas();

View File

@ -17,6 +17,7 @@
#include "DockAreaTitleBar.h"
#include "DockWidget.h"
#include "DockAreaWidget.h"
#include "DockWidgetSideTab.h"
namespace ads
{
@ -29,6 +30,12 @@ CDockWidgetTab* CDockComponentsFactory::createDockWidgetTab(CDockWidget* DockWid
return new CDockWidgetTab(DockWidget);
}
//============================================================================
CDockWidgetSideTab* CDockComponentsFactory::createDockWidgetSideTab(CDockWidget *DockWidget) const
{
return new CDockWidgetSideTab(DockWidget);
}
//============================================================================
CDockAreaTabBar* CDockComponentsFactory::createDockAreaTabBar(CDockAreaWidget* DockArea) const

View File

@ -19,6 +19,7 @@ class CDockAreaTitleBar;
class CDockAreaTabBar;
class CDockAreaWidget;
class CDockWidget;
class CDockWidgetSideTab;
@ -46,6 +47,12 @@ public:
*/
virtual CDockWidgetTab* createDockWidgetTab(CDockWidget* DockWidget) const;
/**
* This default implementation just creates a dock widget side tab with
* new CDockWidgetTab(DockWidget).
*/
virtual CDockWidgetSideTab* createDockWidgetSideTab(CDockWidget* DockWidget) const;
/**
* This default implementation just creates a dock area tab bar with
* new CDockAreaTabBar(DockArea).

View File

@ -38,6 +38,7 @@
#include <QDebug>
#include <QXmlStreamWriter>
#include <QAbstractButton>
#include <QLabel>
#include "DockManager.h"
#include "DockAreaWidget.h"
@ -47,6 +48,11 @@
#include "DockOverlay.h"
#include "ads_globals.h"
#include "DockSplitter.h"
#include "SideTabBar.h"
#include "OverlayDockContainer.h"
#include "DockWidgetTab.h"
#include "DockWidgetSideTab.h"
#include "DockAreaTitleBar.h"
#include <functional>
#include <iostream>
@ -131,6 +137,7 @@ public:
QPointer<CDockManager> DockManager;
unsigned int zOrderIndex = 0;
QList<CDockAreaWidget*> DockAreas;
QMap<SideTabBarArea, CSideTabBar*> SideTabBarWidgets;
QGridLayout* Layout = nullptr;
QSplitter* RootSplitter = nullptr;
bool isFloating = false;
@ -212,6 +219,11 @@ public:
void saveChildNodesState(QXmlStreamWriter& Stream, QWidget* Widget);
/**
* Save state of overlay widgets
*/
void saveOverlayWidgetsState(QXmlStreamWriter& Stream);
/**
* Restore state of child nodes.
* \param[in] Stream The data stream that contains the serialized state
* \param[out] CreatedWidget The widget created from parsed data or 0 if
@ -236,6 +248,19 @@ public:
bool restoreDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget,
bool Testing);
/**
* Restores the overlay dock area.
* Assumes that there are no overlay dock areas, and then restores all the dock areas that
* exist in the XML
*/
bool restoreOverlayDockArea(CDockingStateReader& s, SideTabBarArea area, bool Testing);
/**
* Restores either a dock area or an overlay dock area depending on the value in the XML
*/
bool restoreDockOrOverlayDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget,
bool Testing);
/**
* Helper function for recursive dumping of layout
*/
@ -404,11 +429,13 @@ void DockContainerWidgetPrivate::onVisibleDockAreaCountChanged()
this->TopLevelDockArea = TopLevelDockArea;
TopLevelDockArea->titleBarButton(TitleBarButtonUndock)->setVisible(false || !_this->isFloating());
TopLevelDockArea->titleBarButton(TitleBarButtonClose)->setVisible(false || !_this->isFloating());
TopLevelDockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(false || !_this->isFloating());
}
else if (this->TopLevelDockArea)
{
this->TopLevelDockArea->titleBarButton(TitleBarButtonUndock)->setVisible(true);
this->TopLevelDockArea->titleBarButton(TitleBarButtonClose)->setVisible(true);
this->TopLevelDockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(true);
this->TopLevelDockArea = nullptr;
}
}
@ -807,6 +834,7 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QList<CDockAreaWidget*
{
DockArea->titleBarButton(TitleBarButtonUndock)->setVisible(true);
DockArea->titleBarButton(TitleBarButtonClose)->setVisible(true);
DockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(true);
}
// We need to ensure, that the dock area title bar is visible. The title bar
@ -873,6 +901,19 @@ void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidge
}
}
void DockContainerWidgetPrivate::saveOverlayWidgetsState(QXmlStreamWriter& Stream)
{
for (const auto dockAreaWidget : _this->findChildren<CDockAreaWidget*>())
{
if (!dockAreaWidget->isOverlayed())
{
continue;
}
dockAreaWidget->saveState(Stream);
}
}
//============================================================================
bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s,
@ -989,6 +1030,126 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s,
return true;
}
//============================================================================
bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, SideTabBarArea area, bool Testing)
{
bool Ok;
#ifdef ADS_DEBUG_PRINT
int Tabs = s.attributes().value("Tabs").toInt(&Ok);
if (!Ok)
{
return false;
}
#endif
QString CurrentDockWidget = s.attributes().value("Current").toString();
ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: "
<< CurrentDockWidget);
if (area == Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar))
{
return false;
}
if (area == Right && !CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar))
{
return false;
}
CDockAreaWidget* DockArea = nullptr;
if (!Testing)
{
const auto dockContainer = new COverlayDockContainer(DockManager, area, _this);
if (!dockContainer->restoreState(s, Testing))
{
return false;
}
dockContainer->hide();
DockArea = dockContainer->dockAreaWidget();
const auto titleBar = DockArea->titleBar();
QSignalBlocker blocker(titleBar);
titleBar->button(TitleBarButtonAutoHide)->setChecked(true);
}
while (s.readNextStartElement())
{
if (s.name() != QLatin1String("Widget"))
{
continue;
}
auto ObjectName = s.attributes().value("Name");
if (ObjectName.isEmpty())
{
return false;
}
s.skipCurrentElement();
CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName.toString());
if (!DockWidget || Testing)
{
continue;
}
ADS_PRINT("Dock Widget found - parent " << DockWidget->parent());
// We hide the DockArea here to prevent the short display (the flashing)
// of the dock areas during application startup
DockArea->hide();
DockWidget->setToggleViewActionChecked(false);
DockWidget->setClosedState(true);
DockWidget->setProperty(internal::ClosedProperty, true);
DockWidget->setProperty(internal::DirtyProperty, false);
_this->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget());
DockWidget->sideTabWidget()->show();
DockWidget->toggleView(false);
DockArea->overlayDockContainer()->addDockWidget(DockWidget);
}
if (Testing)
{
return true;
}
if (!DockArea->dockWidgetsCount())
{
delete DockArea;
DockArea = nullptr;
}
else
{
DockArea->setProperty("currentDockWidget", CurrentDockWidget);
appendDockAreas({DockArea});
}
return true;
}
//============================================================================
bool DockContainerWidgetPrivate::restoreDockOrOverlayDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget,
bool Testing)
{
bool Ok;
const auto sideTabAreaValue = Stream.attributes().value("SideTabBarArea");
if (!sideTabAreaValue.isNull())
{
auto sideTabBarArea = static_cast<SideTabBarArea>(sideTabAreaValue.toInt(&Ok));
if (!Ok)
{
return false;
}
if (sideTabBarArea != SideTabBarArea::None)
{
return restoreOverlayDockArea(Stream, sideTabBarArea, Testing);
}
}
// If there's no SideTabBarArea value in the XML, or the value of SideTabBarArea is none, restore the dock area
return restoreDockArea(Stream, CreatedWidget, Testing);
}
//============================================================================
bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s,
@ -1054,7 +1215,7 @@ bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s,
// We hide the DockArea here to prevent the short display (the flashing)
// of the dock areas during application startup
DockArea->hide();
DockArea->addDockWidget(DockWidget);
DockArea->addDockWidget(DockWidget);
DockWidget->setToggleViewActionChecked(!Closed);
DockWidget->setClosedState(Closed);
DockWidget->setProperty(internal::ClosedProperty, Closed);
@ -1096,7 +1257,7 @@ bool DockContainerWidgetPrivate::restoreChildNodes(CDockingStateReader& s,
}
else if (s.name() == QLatin1String("Area"))
{
Result = restoreDockArea(s, CreatedWidget, Testing);
Result = restoreDockOrOverlayDockArea(s, CreatedWidget, Testing);
ADS_PRINT("DockAreaWidget");
}
else
@ -1288,6 +1449,7 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p
d->Layout = new QGridLayout();
d->Layout->setContentsMargins(0, 0, 0, 0);
d->Layout->setSpacing(0);
d->Layout->setColumnStretch(1, 1);
setLayout(d->Layout);
// The function d->newSplitter() accesses the config flags from dock
@ -1299,6 +1461,7 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p
{
d->DockManager->registerDockContainer(this);
createRootSplitter();
createSideTabBarWidgets();
}
}
@ -1334,6 +1497,45 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW
}
}
void CDockContainerWidget::createDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget)
{
if (d->DockManager != DockWidget->dockManager())
{
DockWidget->setDockManager(d->DockManager); // Overlay Dock Container needs a valid dock manager
}
const auto dockContainer = new COverlayDockContainer(DockWidget, area);
dockContainer->hide();
}
//============================================================================
SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDockAreaWidget* DockAreaWidget)
{
const auto dockWidgetCenter = DockAreaWidget->mapToGlobal(DockAreaWidget->frameGeometry().center());
const auto splitterCenter = rootSplitter()->mapToGlobal(rootSplitter()->frameGeometry().center());
const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? Left : Right;
if (calculatedPosition == Right)
{
if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar))
{
return Right;
}
return Left;
}
if (calculatedPosition == Left)
{
if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar))
{
return Left;
}
return Right;
}
return Left;
}
//============================================================================
void CDockContainerWidget::removeDockWidget(CDockWidget* Dockwidget)
{
@ -1408,6 +1610,22 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
*p = nullptr;
}
if (area->isOverlayed())
{
// Removing an area from an overlay widget implies deleting the whole overlay widget
// So cleanup will be done when the overlay widget is deleted
// Note: there is no parent splitter
CDockWidget* TopLevelWidget = topLevelDockWidget();
// Updated the title bar visibility of the dock widget if there is only
// one single visible dock widget
CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
dumpLayout();
d->emitDockAreasRemoved();
area->setOverlayDockContainer(nullptr);
return;
}
// If splitter has more than 1 widgets, we are finished and can leave
if (Splitter->count() > 1)
{
@ -1675,6 +1893,7 @@ void CDockContainerWidget::saveState(QXmlStreamWriter& s) const
#endif
}
d->saveChildNodesState(s, d->RootSplitter);
d->saveOverlayWidgetsState(s);
s.writeEndElement();
}
@ -1759,7 +1978,24 @@ void CDockContainerWidget::createRootSplitter()
return;
}
d->RootSplitter = d->newSplitter(Qt::Horizontal);
d->Layout->addWidget(d->RootSplitter);
d->Layout->addWidget(d->RootSplitter, 0, 1); // Add it to the center - the 0 and 2 indexes are used for the SideTabBar widgets
}
//============================================================================
void CDockContainerWidget::createSideTabBarWidgets()
{
if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar))
{
d->SideTabBarWidgets[SideTabBarArea::Left] = new CSideTabBar(this);
d->Layout->addWidget(d->SideTabBarWidgets[SideTabBarArea::Left], 0, 0);
}
if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar))
{
d->SideTabBarWidgets[SideTabBarArea::Right] = new CSideTabBar(this);
d->Layout->addWidget(d->SideTabBarWidgets[SideTabBarArea::Right], 0, 2);
}
}
@ -1894,7 +2130,11 @@ void CDockContainerWidget::closeOtherAreas(CDockAreaWidget* KeepOpenArea)
}
}
//============================================================================
CSideTabBar* CDockContainerWidget::sideTabBar(SideTabBarArea area) const
{
return d->SideTabBarWidgets[area];
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -50,6 +50,7 @@ struct FloatingDockContainerPrivate;
class CFloatingDragPreview;
struct FloatingDragPreviewPrivate;
class CDockingStateReader;
class CSideTabBar;
/**
@ -74,6 +75,7 @@ private:
friend class CDockWidget;
friend class CFloatingDragPreview;
friend struct FloatingDragPreviewPrivate;
friend class COverlayDockContainer;
protected:
/**
@ -91,6 +93,11 @@ protected:
*/
void createRootSplitter();
/**
* Helper function for creation of the side tab bar widgets
*/
void createSideTabBarWidgets();
/**
* Drop floating widget into the container
*/
@ -163,6 +170,7 @@ protected:
void updateSplitterHandles(QSplitter* splitter);
public:
/**
* Default Constructor
*/
@ -183,6 +191,16 @@ public:
CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget,
CDockAreaWidget* DockAreaWidget = nullptr);
/**
* Creates and adds a dockwidget overlay container into the given area.
*/
void createDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget);
/**
* Get's the overlay dock side tab bar area based on the dock area widget position
*/
SideTabBarArea getDockAreaPosition(CDockAreaWidget* DockAreaWidget);
/**
* Removes dockwidget
*/
@ -278,6 +296,11 @@ public:
*/
void closeOtherAreas(CDockAreaWidget* KeepOpenArea);
/**
* Returns the side tab widget for the given area
*/
CSideTabBar* sideTabBar(SideTabBarArea area) const;
Q_SIGNALS:
/**
* This signal is emitted if one or multiple dock areas has been added to

View File

@ -25,6 +25,8 @@
#include "FloatingDockContainer.h"
#include "DockManager.h"
#include "DockAreaTitleBar.h"
#include "DockWidgetSideTab.h"
#include "OverlayDockContainer.h"
#ifdef Q_OS_LINUX
#include "linux/FloatingWidgetTitleBar.h"
@ -69,6 +71,8 @@ static void updateDockWidgetFocusStyle(CDockWidget* DockWidget, bool Focused)
DockWidget->setProperty("focused", Focused);
DockWidget->tabWidget()->setProperty("focused", Focused);
DockWidget->tabWidget()->updateStyle();
DockWidget->sideTabWidget()->setProperty("focused", Focused);
DockWidget->sideTabWidget()->updateStyle();
internal::repolishStyle(DockWidget);
}
@ -185,6 +189,11 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget)
}
#endif
if (old && old->overlayDockContainer() && old != DockWidget)
{
old->overlayDockContainer()->hide();
}
if (old == DockWidget && !ForceFocusChangedSignal)
{
return;

View File

@ -56,6 +56,7 @@
#include "DockAreaTitleBar.h"
#include "DockFocusController.h"
#include "DockSplitter.h"
#include "OverlayDockContainer.h"
#ifdef Q_OS_LINUX
#include "linux/FloatingWidgetTitleBar.h"
@ -99,6 +100,7 @@ struct DockManagerPrivate
CDockManager* _this;
QList<CFloatingDockContainer*> FloatingWidgets;
QList<CFloatingDockContainer*> HiddenFloatingWidgets;
QList<COverlayDockContainer*> OverlayWidgets;
QList<CDockContainerWidget*> Containers;
CDockOverlay* ContainerOverlay;
CDockOverlay* DockAreaOverlay;
@ -146,6 +148,15 @@ struct DockManagerPrivate
}
}
void deleteOverlayWidgets()
{
for (auto OverlayWidget : OverlayWidgets)
{
OverlayWidget->cleanupAndDelete();
}
OverlayWidgets.clear();
}
void markDockWidgetsDirty()
{
for (auto DockWidget : DockWidgetsMap)
@ -430,6 +441,7 @@ bool DockManagerPrivate::restoreState(const QByteArray& State, int version)
// Hide updates of floating widgets from use
hideFloatingWidgets();
deleteOverlayWidgets();
markDockWidgetsDirty();
if (!restoreStateFromXml(state, version))
@ -481,6 +493,7 @@ CDockManager::CDockManager(QWidget *parent) :
d(new DockManagerPrivate(this))
{
createRootSplitter();
createSideTabBarWidgets();
QMainWindow* MainWindow = qobject_cast<QMainWindow*>(parent);
if (MainWindow)
{
@ -525,6 +538,13 @@ CDockManager::~CDockManager()
{
delete FloatingWidget;
}
auto OverlayWidgets = d->OverlayWidgets;
for (auto OverlayWidget : OverlayWidgets)
{
delete OverlayWidget;
}
delete d;
}
@ -616,6 +636,14 @@ void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget
ADS_PRINT("d->FloatingWidgets.count() " << d->FloatingWidgets.count());
}
//============================================================================
void CDockManager::registerOverlayWidget(COverlayDockContainer* OverlayWidget)
{
d->OverlayWidgets.append(OverlayWidget);
Q_EMIT overlayWidgetCreated(OverlayWidget);
ADS_PRINT("d->OverlayWidgets.count() " << d->OverlayWidgets.count());
}
//============================================================================
void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget)
@ -623,6 +651,11 @@ void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget)
d->FloatingWidgets.removeAll(FloatingWidget);
}
//============================================================================
void CDockManager::removeOverlayWidget(COverlayDockContainer* OverlayWidget)
{
d->OverlayWidgets.removeAll(OverlayWidget);
}
//============================================================================
void CDockManager::registerDockContainer(CDockContainerWidget* DockContainer)

View File

@ -84,6 +84,7 @@ private:
friend class CFloatingDragPreview;
friend struct FloatingDragPreviewPrivate;
friend class CDockAreaTitleBar;
friend class COverlayDockContainer;
protected:
@ -93,12 +94,24 @@ protected:
*/
void registerFloatingWidget(CFloatingDockContainer* FloatingWidget);
/**
* Registers the given floating widget in the internal list of
* overlay widgets
*/
void registerOverlayWidget(COverlayDockContainer* OverlayWidget);
/**
* Remove the given floating widget from the list of registered floating
* widgets
*/
void removeFloatingWidget(CFloatingDockContainer* FloatingWidget);
/**
* Remove the given overlay widget from the list of registered overlay
* widgets
*/
void removeOverlayWidget(COverlayDockContainer* OverlayWidget);
/**
* Registers the given dock container widget
*/
@ -202,14 +215,24 @@ public:
//! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0".
MiddleMouseButtonClosesTab = 0x2000000, //! If the flag is set, the user can use the mouse middle button to close the tab under the mouse
DockAreaHasAutoHideButton = 0x4000000, //!< If the flag is set each dock area has a auto hide menu button
DockContainerHasLeftSideBar = 0x8000000, //!< If the flag is set each container will have a left side bar
DockContainerHasRightSideBar = 0x10000000, //!< If the flag is set each container will have a right side bar
DefaultDockAreaButtons = DockAreaHasCloseButton
| DockAreaHasUndockButton
| DockAreaHasTabsMenuButton,///< default configuration of dock area title bar buttons
| DockAreaHasTabsMenuButton
| DockAreaHasAutoHideButton,///< default configuration of dock area title bar buttons
DefaultDockContainerSideBars = DockContainerHasLeftSideBar
| DockContainerHasRightSideBar, ///< the default configuration for left and right side bars
DefaultBaseConfig = DefaultDockAreaButtons
| ActiveTabHasCloseButton
| XmlCompressionEnabled
| FloatingContainerHasWidgetTitle,///< default base configuration settings
| FloatingContainerHasWidgetTitle
| DefaultDockContainerSideBars, ///< default base configuration settings
DefaultOpaqueConfig = DefaultBaseConfig
| OpaqueSplitterResize
@ -602,6 +625,11 @@ Q_SIGNALS:
*/
void floatingWidgetCreated(ads::CFloatingDockContainer* FloatingWidget);
/**
* This signal is emitted, if a new overlay widget has been created.
*/
void overlayWidgetCreated(ads::COverlayDockContainer* OverlayWidget);
/**
* This signal is emitted, if a new DockArea has been created.
* An application can use this signal to set custom icons or custom

View File

@ -50,6 +50,8 @@
#include <QScreen>
#include <QWindow>
#include "SideTabBar.h"
#include "DockWidgetSideTab.h"
#include "DockContainerWidget.h"
#include "DockAreaWidget.h"
#include "DockManager.h"
@ -57,6 +59,7 @@
#include "DockSplitter.h"
#include "DockComponentsFactory.h"
#include "ads_globals.h"
#include "OverlayDockContainer.h"
namespace ads
@ -76,6 +79,7 @@ struct DockWidgetPrivate
QBoxLayout* Layout = nullptr;
QWidget* Widget = nullptr;
CDockWidgetTab* TabWidget = nullptr;
CDockWidgetSideTab* SideTabWidget = nullptr;
CDockWidget::DockWidgetFeatures Features = CDockWidget::DefaultDockWidgetFeatures;
CDockManager* DockManager = nullptr;
CDockAreaWidget* DockArea = nullptr;
@ -182,6 +186,11 @@ void DockWidgetPrivate::showDockWidget()
CFloatingDockContainer*>(Container);
FloatingWidget->show();
}
if (DockArea->isOverlayed())
{
DockArea->overlayDockContainer()->show();
}
}
}
@ -197,6 +206,11 @@ void DockWidgetPrivate::hideDockWidget()
Widget->deleteLater();
Widget = nullptr;
}
if (DockArea->isOverlayed())
{
DockArea->overlayDockContainer()->hide();
}
}
@ -287,7 +301,11 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
setObjectName(title);
d->TabWidget = componentsFactory()->createDockWidgetTab(this);
d->ToggleViewAction = new QAction(title, this);
d->SideTabWidget = componentsFactory()->createDockWidgetSideTab(this);
connect(d->SideTabWidget, &CDockWidgetSideTab::clicked, this, &CDockWidget::onDockWidgetSideTabClicked);
d->ToggleViewAction = new QAction(title, this);
d->ToggleViewAction->setCheckable(true);
connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this,
SLOT(toggleView(bool)));
@ -302,7 +320,7 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
//============================================================================
CDockWidget::~CDockWidget()
{
ADS_PRINT("~CDockWidget()");
ADS_PRINT("~CDockWidget()");
delete d;
}
@ -379,7 +397,7 @@ QWidget* CDockWidget::takeWidget()
{
w->setParent(nullptr);
}
return w;
return w;
}
@ -396,6 +414,16 @@ CDockWidgetTab* CDockWidget::tabWidget() const
return d->TabWidget;
}
COverlayDockContainer* CDockWidget::overlayDockContainer() const
{
if (!d->DockArea)
{
return nullptr;
}
return d->DockArea->overlayDockContainer();
}
//============================================================================
void CDockWidget::setFeatures(DockWidgetFeatures features)
@ -416,8 +444,8 @@ void CDockWidget::setFeatures(DockWidgetFeatures features)
void CDockWidget::setFeature(DockWidgetFeature flag, bool on)
{
auto Features = features();
internal::setFlag(Features, flag, on);
setFeatures(Features);
internal::setFlag(Features, flag, on);
setFeatures(Features);
}
@ -470,6 +498,12 @@ CDockAreaWidget* CDockWidget::dockAreaWidget() const
return d->DockArea;
}
//============================================================================
CDockWidgetSideTab* CDockWidget::sideTabWidget() const
{
return d->SideTabWidget;
}
//============================================================================
bool CDockWidget::isFloating() const
@ -541,7 +575,7 @@ void CDockWidget::setMinimumSizeHintMode(eMinimumSizeHintMode Mode)
//============================================================================
bool CDockWidget::isCentralWidget() const
{
return dockManager()->centralWidget() == this;
return dockManager()->centralWidget() == this;
}
@ -662,7 +696,7 @@ bool CDockWidget::event(QEvent *e)
case QEvent::Show:
Q_EMIT visibilityChanged(geometry().right() >= 0 && geometry().bottom() >= 0);
break;
break;
case QEvent::WindowTitleChange :
{
@ -938,7 +972,7 @@ bool CDockWidget::closeDockWidgetInternal(bool ForceClose)
}
if (features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
{
{
// If the dock widget is floating, then we check if we also need to
// delete the floating widget
if (isFloating())
@ -956,11 +990,11 @@ bool CDockWidget::closeDockWidgetInternal(bool ForceClose)
}
deleteDockWidget();
Q_EMIT closed();
}
else
{
toggleView(false);
}
}
else
{
toggleView(false);
}
return true;
}
@ -1007,6 +1041,27 @@ void CDockWidget::showNormal()
}
}
//============================================================================
void CDockWidget::onDockWidgetSideTabClicked()
{
const auto overlayContainer = overlayDockContainer();
if (!overlayContainer)
{
return;
}
overlayContainer->raise();
const auto show = !overlayContainer->isVisible();
overlayContainer->setVisible(show);
toggleView(show);
if (overlayContainer->isVisible())
{
// d->DockManager->setDockWidgetFocused(this) does not
// de focus the old widget, leading to the overlay still being visible
// even after clicking outside the overlay.
setFocus(Qt::ActiveWindowFocusReason);
}
}
//============================================================================
bool CDockWidget::isFullScreen() const

View File

@ -46,6 +46,8 @@ class CDockContainerWidget;
class CDockAreaWidget;
class DockContainerWidgetPrivate;
class CFloatingDockContainer;
class CDockWidgetSideTab;
class COverlayDockContainer;
/**
* The QDockWidget class provides a widget that can be docked inside a
@ -75,6 +77,7 @@ protected:
friend class CDockWidgetTab;
friend struct DockWidgetTabPrivate;
friend struct DockAreaTitleBarPrivate;
friend class COverlayDockContainer;
/**
* Assigns the dock manager that manages this dock widget
@ -300,6 +303,12 @@ public:
*/
CDockWidgetTab* tabWidget() const;
/**
* Returns the overlay dock container of this dock widget
* or 0 if there is none
*/
COverlayDockContainer* overlayDockContainer() const;
/**
* Sets, whether the dock widget is movable, closable, and floatable.
*/
@ -343,6 +352,11 @@ public:
*/
CDockAreaWidget* dockAreaWidget() const;
/**
* Returns the side tab widget for this dock
*/
CDockWidgetSideTab* sideTabWidget() 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
@ -563,6 +577,10 @@ public Q_SLOTS:
*/
void showNormal();
/**
* Shows the dock overlay container when the side tab is clicked
*/
void onDockWidgetSideTabClicked();
Q_SIGNALS:
/**

151
src/DockWidgetSideTab.cpp Normal file
View File

@ -0,0 +1,151 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockWidgetTab.h
/// \author Syarif Fakhri
/// \date 05.09.2022
/// \brief Implementation of CDockWidgetSideTab class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "DockWidgetSideTab.h"
#include "SideTabBar.h"
#include <QBoxLayout>
#include "ElidingLabel.h"
#include "DockWidget.h"
namespace ads
{
using tTabLabel = CVerticalElidingLabel;
/**
* Private data class of CDockWidgetTab class (pimpl)
*/
struct DockWidgetSideTabPrivate
{
CDockWidgetSideTab* _this;
CDockWidget* DockWidget;
tTabLabel* TitleLabel;
QBoxLayout* Layout;
CSideTabBar* SideTabBar;
/**
* Private data constructor
*/
DockWidgetSideTabPrivate(CDockWidgetSideTab* _public);
/**
* Creates the complete layout
*/
void createLayout();
};
// struct DockWidgetTabPrivate
//============================================================================
DockWidgetSideTabPrivate::DockWidgetSideTabPrivate(CDockWidgetSideTab* _public) :
_this(_public)
{
}
//============================================================================
void DockWidgetSideTabPrivate::createLayout()
{
TitleLabel = new tTabLabel();
TitleLabel->setElideMode(Qt::ElideRight);
TitleLabel->setText(DockWidget->windowTitle());
TitleLabel->setObjectName("dockWidgetTabLabel");
TitleLabel->setAlignment(Qt::AlignCenter);
_this->connect(TitleLabel, SIGNAL(elidedChanged(bool)), SIGNAL(elidedChanged(bool)));
QFontMetrics fm(TitleLabel->font());
int Spacing = qRound(fm.height() / 2.0);
// Fill the layout
Layout = new QBoxLayout(QBoxLayout::LeftToRight);
Layout->setContentsMargins(Spacing,Spacing,0,Spacing);
Layout->setSpacing(0);
_this->setLayout(Layout);
Layout->addWidget(TitleLabel, 1);
Layout->setAlignment(Qt::AlignCenter);
TitleLabel->setVisible(true);
}
//============================================================================
void CDockWidgetSideTab::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
emit clicked();
}
QFrame::mousePressEvent(event);
}
//============================================================================
void CDockWidgetSideTab::setSideTabBar(CSideTabBar* SideTabBar)
{
d->SideTabBar = SideTabBar;
}
//============================================================================
void CDockWidgetSideTab::removeFromSideTabBar()
{
if (d->SideTabBar == nullptr)
{
return;
}
d->SideTabBar->removeSideTab(this);
setSideTabBar(nullptr);
}
//============================================================================
CDockWidgetSideTab::CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent) :
QFrame(parent),
d(new DockWidgetSideTabPrivate(this))
{
setAttribute(Qt::WA_NoMousePropagation);
d->DockWidget = DockWidget;
d->createLayout();
setFocusPolicy(Qt::NoFocus);
}
//============================================================================
CDockWidgetSideTab::~CDockWidgetSideTab()
{
delete d;
}
//============================================================================
void CDockWidgetSideTab::updateStyle()
{
internal::repolishStyle(this, internal::RepolishDirectChildren);
}
}

96
src/DockWidgetSideTab.h Normal file
View File

@ -0,0 +1,96 @@
#ifndef DockWidgetSideTabH
#define DockWidgetSideTabH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockWidgetTab.h
/// \author Syarif Fakhri
/// \date 05.09.2022
/// \brief Declaration of CDockWidgetSideTab class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include <QFrame>
#include "ads_globals.h"
namespace ads
{
struct DockWidgetSideTabPrivate;
class CDockWidget;
class CSideTabBar;
class CDockWidgetTab;
/**
* 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 CDockWidgetSideTab : public QFrame
{
Q_OBJECT
private:
DockWidgetSideTabPrivate* d; ///< private data (pimpl)
friend struct DockWidgetSideTabPrivate;
friend class CDockWidget;
friend class COverlayDockContainer;
protected:
friend class CSideTabBar;
friend class CDockAreaWidget;
friend class CDockContainerWidget;
void mousePressEvent(QMouseEvent* event) override;
void setSideTabBar(CSideTabBar *SideTabBar);
void removeFromSideTabBar();
public:
using Super = QFrame;
/**
* Default Constructor
* param[in] DockWidget The dock widget this title bar belongs to
* param[in] Orientation Horizontal or vertical orientation
* param[in] parent The parent widget of this title bar
*/
CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent = nullptr);
/**
* Virtual Destructor
*/
virtual ~CDockWidgetSideTab();
/**
* Update stylesheet style if a property changes
*/
void updateStyle();
Q_SIGNALS:
void elidedChanged(bool elided);
void clicked();
}; // class DockWidgetSideTab
}
// namespace ads
//-----------------------------------------------------------------------------
#endif

View File

@ -51,6 +51,7 @@
#include "DockManager.h"
#include "IconProvider.h"
#include "DockFocusController.h"
#include "OverlayDockContainer.h"
namespace ads
@ -752,7 +753,6 @@ QSize CDockWidgetTab::iconSize() const
return d->IconSize;
}
//============================================================================
void CDockWidgetTab::setIconSize(const QSize& Size)
{

View File

@ -58,6 +58,7 @@ private:
friend struct DockWidgetTabPrivate;
friend class CDockWidget;
friend class CDockManager;
friend class COverlayDockContainer;
void onDockWidgetFeaturesChanged();
private Q_SLOTS:

View File

@ -29,6 +29,7 @@
//============================================================================
#include "ElidingLabel.h"
#include <QMouseEvent>
#include <QPainter>
namespace ads
@ -225,6 +226,34 @@ QString CElidingLabel::text() const
{
return d->Text;
}
//============================================================================
CVerticalElidingLabel::CVerticalElidingLabel(QWidget* parent, Qt::WindowFlags f) :
CElidingLabel(parent, f)
{
}
//============================================================================
void CVerticalElidingLabel::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.rotate(90);
painter.drawText(0,0, text());
}
//============================================================================
QSize CVerticalElidingLabel::sizeHint() const
{
QSize s = CElidingLabel::minimumSizeHint();
return QSize(s.height(), s.width());
}
//============================================================================
QSize CVerticalElidingLabel::minimumSizeHint() const
{
QSize s = CElidingLabel::sizeHint();
return QSize(s.height(), s.width());
}
} // namespace QtLabb
//---------------------------------------------------------------------------

View File

@ -102,6 +102,18 @@ Q_SIGNALS:
void elidedChanged(bool elided);
}; //class CElidingLabel
class CVerticalElidingLabel : public CElidingLabel
{
protected:
void paintEvent(QPaintEvent* event) override;
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
public:
CVerticalElidingLabel(QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowFlags ());
}; // class CVerticalElidingLabel
} // namespace QtLabb
//---------------------------------------------------------------------------

View File

@ -21,6 +21,7 @@
#include "DockManager.h"
#include "DockContainerWidget.h"
#include "DockOverlay.h"
#include "OverlayDockContainer.h"
namespace ads
{
@ -319,6 +320,9 @@ void CFloatingDragPreview::startFloating(const QPoint &DragStartMousePos,
void CFloatingDragPreview::finishDragging()
{
ADS_PRINT("CFloatingDragPreview::finishDragging");
cleanupOverlayContainerWidget();
auto DockDropArea = d->DockManager->dockAreaOverlay()->visibleDropAreaUnderCursor();
auto ContainerDropArea = d->DockManager->containerOverlay()->visibleDropAreaUnderCursor();
if (!d->DropContainer)
@ -353,6 +357,22 @@ void CFloatingDragPreview::finishDragging()
}
//============================================================================
void CFloatingDragPreview::cleanupOverlayContainerWidget()
{
auto DroppedDockWidget = qobject_cast<CDockWidget*>(d->Content);
auto DroppedArea = qobject_cast<CDockAreaWidget*>(d->Content);
if (DroppedDockWidget && DroppedDockWidget->overlayDockContainer())
{
DroppedDockWidget->overlayDockContainer()->cleanupAndDelete();
}
if (DroppedArea && DroppedArea->overlayDockContainer())
{
DroppedArea->overlayDockContainer()->cleanupAndDelete();
}
}
//============================================================================
void CFloatingDragPreview::paintEvent(QPaintEvent* event)
{

View File

@ -92,6 +92,11 @@ public: // implements IFloatingWidget -----------------------------------------
*/
virtual void finishDragging() override;
/**
* Cleanup overlay container if the dragged widget has one
*/
void cleanupOverlayContainerWidget();
Q_SIGNALS:
/**
* This signal is emitted, if dragging has been canceled by escape key

View File

@ -0,0 +1,309 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockWidgetTab.h
/// \author Syarif Fakhri
/// \date 05.09.2022
/// \brief Implementation of COverlayDockContainer class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "OverlayDockContainer.h"
#include "DockManager.h"
#include "DockWidgetSideTab.h"
#include "DockWidgetTab.h"
#include "SideTabBar.h"
#include "DockAreaTitleBar.h"
#include "DockAreaWidget.h"
#include "DockingStateReader.h"
#include <QXmlStreamWriter>
#include <QAbstractButton>
#include <QBoxLayout>
#include <QPainter>
#include <QSplitter>
namespace ads
{
struct OverlayDockContainerPrivate
{
COverlayDockContainer* _this;
CDockAreaWidget* DockArea{nullptr};
CDockWidget* DockWidget{nullptr};
QPointer<CDockManager> DockManager{nullptr};
QSplitter* Splitter;
SideTabBarArea Area;
/**
* Private data constructor
*/
OverlayDockContainerPrivate(COverlayDockContainer *_public);
}; // struct OverlayDockContainerPrivate
//============================================================================
OverlayDockContainerPrivate::OverlayDockContainerPrivate(
COverlayDockContainer *_public) :
_this(_public)
{
}
CDockContainerWidget* COverlayDockContainer::parentContainer() const
{
return qobject_cast<CDockContainerWidget*>(parent());
}
//============================================================================
COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, SideTabBarArea area, CDockContainerWidget* parent) :
QFrame(parent),
d(new OverlayDockContainerPrivate(this))
{
d->DockManager = DockManager;
d->Area = area;
d->DockArea = new CDockAreaWidget(DockManager, parent);
d->DockArea->setObjectName("OverlayDockArea");
d->DockArea->setOverlayDockContainer(this);
auto autoHideButton = d->DockArea->titleBar()->button(TitleBarButtonAutoHide);
autoHideButton->blockSignals(true);
autoHideButton->setChecked(true);
autoHideButton->blockSignals(false);
QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight);
d->Splitter = new QSplitter(Qt::Orientation::Horizontal);
d->Splitter->setChildrenCollapsible(false);
const auto emptyWidget = new QWidget();
emptyWidget->setMinimumWidth(50);
if (area == SideTabBarArea::Left)
{
d->Splitter->addWidget(d->DockArea);
d->Splitter->addWidget(emptyWidget);
}
else
{
d->Splitter->addWidget(emptyWidget);
d->Splitter->addWidget(d->DockArea);
}
// Allows an equal distribution between the empty widget and the splitter
const auto frameGeometry = d->DockManager->frameGeometry();
const auto leftSize = area == SideTabBarArea::Left ? frameGeometry.width() / 3 : frameGeometry.width();
const auto rightSize = area == SideTabBarArea::Left ? frameGeometry.width() : frameGeometry.width() / 3;
d->Splitter->setSizes(QList<int>({ leftSize, rightSize }));
l->setContentsMargins(QMargins());
l->setSpacing(0);
l->addWidget(d->Splitter);
setLayout(l);
updateMask();
updateSize();
DockManager->registerOverlayWidget(this);
d->DockArea->installEventFilter(this);
parent->installEventFilter(this);
}
//============================================================================
void COverlayDockContainer::updateMask()
{
const auto rect = d->DockArea->frameGeometry();
const auto topLeft = rect.topLeft();
const auto handleSize = d->Splitter->handleWidth();
const auto offset = d->Area == SideTabBarArea::Left ? 0 : handleSize;
setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height())));
}
//============================================================================
void COverlayDockContainer::updateSize()
{
const auto dockContainerParent = parentContainer();
const auto rootSplitter = dockContainerParent->rootSplitter();
const auto rect = rootSplitter->frameGeometry();
move(rect.topLeft());
resize(rect.width(), rect.height());
}
//============================================================================
COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area) :
COverlayDockContainer(DockWidget->dockManager(), area, DockWidget->dockContainer() != nullptr ? DockWidget->dockContainer() : DockWidget->dockManager())
{
addDockWidget(DockWidget);
}
//============================================================================
COverlayDockContainer::~COverlayDockContainer()
{
ADS_PRINT("~COverlayDockContainer");
// Remove event filter in case there are any queued messages
parent()->removeEventFilter(this);
if (d->DockManager)
{
d->DockManager->removeOverlayWidget(this);
}
delete d;
}
//============================================================================
CSideTabBar* COverlayDockContainer::sideTabBar() const
{
return parentContainer()->sideTabBar(d->Area);
}
//============================================================================
CDockWidget* COverlayDockContainer::dockWidget() const
{
return d->DockWidget;
}
//============================================================================
void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget)
{
if (d->DockWidget)
{
// Remove the old dock widget at this area
d->DockArea->removeDockWidget(d->DockWidget);
}
d->DockWidget = DockWidget;
CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget();
if (OldDockArea)
{
OldDockArea->removeDockWidget(DockWidget);
}
d->DockArea->addDockWidget(DockWidget);
updateSize();
updateMask();
}
//============================================================================
SideTabBarArea COverlayDockContainer::sideTabBarArea() const
{
return d->Area;
}
//============================================================================
CDockAreaWidget* COverlayDockContainer::dockAreaWidget() const
{
return d->DockArea;
}
//============================================================================
void COverlayDockContainer::moveContentsToParent()
{
const auto position = mapToGlobal(d->Area == Left ? QPoint(1,height() / 2) : QPoint(width() - 1, height() / 2));
const auto dockAreaWidget = parentContainer()->dockAreaAt(position);
if (dockAreaWidget != nullptr && !dockAreaWidget->isCentralWidgetArea())
{
parentContainer()->addDockWidget(CenterDockWidgetArea, d->DockWidget, dockAreaWidget);
}
else
{
parentContainer()->addDockWidget(d->Area == Left ? LeftDockWidgetArea : RightDockWidgetArea, d->DockWidget);
}
cleanupAndDelete();
}
//============================================================================
void COverlayDockContainer::cleanupAndDelete()
{
const auto dockWidget = d->DockWidget;
if (dockWidget)
{
dockWidget->sideTabWidget()->removeFromSideTabBar();
dockWidget->sideTabWidget()->setParent(dockWidget);
dockWidget->sideTabWidget()->hide();
}
hide();
deleteLater();
}
void COverlayDockContainer::saveState(QXmlStreamWriter& s)
{
s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea()));
QStringList Sizes;
for (auto Size : d->Splitter->sizes())
{
Sizes << QString::number(Size);
}
s.writeAttribute("Sizes", Sizes.join(" "));
}
bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing)
{
auto sSizes = s.attributes().value("Sizes").trimmed().toString();
ADS_PRINT("Sizes: " << sSizes);
QTextStream TextStream(&sSizes);
QList<int> Sizes;
while (!TextStream.atEnd())
{
int value;
TextStream >> value;
Sizes.append(value);
}
if (Sizes.count() != d->Splitter->count())
{
return false;
}
if (!Testing)
{
d->Splitter->setSizes(Sizes);
}
return true;
}
//============================================================================
bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event)
{
if (event->type() == QEvent::Resize)
{
updateSize();
updateMask();
}
return QWidget::eventFilter(watched, event);
}
//============================================================================
void COverlayDockContainer::mousePressEvent(QMouseEvent* event)
{
QWidget::mousePressEvent(event);
}
//============================================================================
void COverlayDockContainer::resizeEvent(QResizeEvent* event)
{
updateMask();
QWidget::resizeEvent(event);
}
}

129
src/OverlayDockContainer.h Normal file
View File

@ -0,0 +1,129 @@
#ifndef OverlayDockContainerH
#define OverlayDockContainerH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockWidgetTab.h
/// \author Syarif Fakhri
/// \date 05.09.2022
/// \brief Declaration of COverlayDockContainer class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "ads_globals.h"
#include <QFrame>
class QXmlStreamWriter;
namespace ads
{
struct OverlayDockContainerPrivate;
class CDockManager;
class CDockWidget;
class CDockContainerWidget;
class CSideTabBar;
class CDockAreaWidget;
class CDockingStateReader;
class ADS_EXPORT COverlayDockContainer : public QFrame
{
Q_OBJECT
private:
OverlayDockContainerPrivate* d; ///< private data (pimpl)
friend struct OverlayDockContainerPrivate;
CDockContainerWidget* parentContainer() const;
protected:
bool eventFilter(QObject* watched, QEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
void updateMask();
void updateSize();
public:
/**
* Create overlay widget with a dock manager
*/
COverlayDockContainer(CDockManager* DockManager, SideTabBarArea area, CDockContainerWidget* parent);
/**
* Create overlay widget with the given dock widget
*/
COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area);
/**
* Virtual Destructor
*/
virtual ~COverlayDockContainer();
/**
* Get's the side tab bar
*/
CSideTabBar* sideTabBar() const;
/**
* Get's the dock widget in this dock container
*/
CDockWidget* dockWidget() const;
/**
* Adds a dock widget and removes the previous dock widget
*/
void addDockWidget(CDockWidget* DockWidget);
/**
* Returns the side tab bar area of this overlay dock container
*/
SideTabBarArea sideTabBarArea() const;
/**
* Returns the dock area widget of this overlay dock container
*/
CDockAreaWidget* dockAreaWidget() const;
/**
* Moves the contents to the parent container widget
* Used before removing this overlay dock container
*/
void moveContentsToParent();
/**
* Cleanups up the side tab widget and then deletes itself
*/
void cleanupAndDelete();
/*
* Saves the state and size
*/
void saveState(QXmlStreamWriter& Stream);
/*
* Restores the size of the splitter
*/
bool restoreState(CDockingStateReader& Stream, bool Testing);
};
}
#endif

101
src/SideTabBar.cpp Normal file
View File

@ -0,0 +1,101 @@
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockWidgetTab.h
/// \author Syarif Fakhri
/// \date 05.09.2022
/// \brief Implementation of CSideTabBar class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "SideTabBar.h"
#include "DockContainerWidget.h"
#include "DockWidgetSideTab.h"
#include "DockWidgetTab.h"
#include <QBoxLayout>
namespace ads
{
/**
* Private data class of CSideTabBar class (pimpl)
*/
struct SideTabBarPrivate
{
/**
* Private data constructor
*/
SideTabBarPrivate(CSideTabBar* _public);
CSideTabBar* _this;
CDockContainerWidget* ContainerWidget;
QBoxLayout* TabsLayout;
}; // struct SideTabBarPrivate
//============================================================================
SideTabBarPrivate::SideTabBarPrivate(CSideTabBar* _public) :
_this(_public)
{
}
//============================================================================
CSideTabBar::CSideTabBar(CDockContainerWidget* parent) :
QWidget(parent),
d(new SideTabBarPrivate(this))
{
d->ContainerWidget = parent;
d->TabsLayout = new QBoxLayout(QBoxLayout::TopToBottom);
d->TabsLayout->setContentsMargins(0, 0, 0, 0);
d->TabsLayout->setSpacing(0);
d->TabsLayout->addStretch(1);
setLayout(d->TabsLayout);
setFocusPolicy(Qt::NoFocus);
}
//============================================================================
CSideTabBar::~CSideTabBar()
{
delete d;
}
//============================================================================
void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab)
{
d->TabsLayout->insertWidget(Index, SideTab);
SideTab->setSideTabBar(this);
}
//============================================================================
void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab)
{
const auto index = d->TabsLayout->indexOf(SideTab);
d->TabsLayout->removeWidget(SideTab);
}
}

81
src/SideTabBar.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef SideTabBarH
#define SideTabBarH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
/// \file DockWidgetTab.h
/// \author Syarif Fakhri
/// \date 05.09.2022
/// \brief Declaration of CSideTabBar class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include <QWidget>
#include "ads_globals.h"
namespace ads
{
struct SideTabBarPrivate;
class CDockContainerWidget;
class CDockWidgetSideTab;
class CDockWidgetTab;
/**
* Side tab widget that is shown at the edges of a dock container.
*/
class ADS_EXPORT CSideTabBar : public QWidget
{
Q_OBJECT
private:
SideTabBarPrivate* d; ///< private data (pimpl)
friend struct SideTabBarPrivate;
friend class DockWidgetSideTab;
public:
using Super = QWidget;
/**
* Default Constructor
*/
CSideTabBar(CDockContainerWidget* parent);
/**
* Virtual Destructor
*/
virtual ~CSideTabBar();
/**
* Inserts the given dock widget tab at the given position.
*/
void insertSideTab(int Index, CDockWidgetSideTab* SideTab);
/**
* Removes the given DockWidgetSideTab from the tabbar
*/
void removeSideTab(CDockWidgetSideTab* SideTab);
Q_SIGNALS:
void sideTabAutoHideToggleRequested();
};
}
#endif

View File

@ -91,7 +91,8 @@ enum TitleBarButton
{
TitleBarButtonTabsMenu,
TitleBarButtonUndock,
TitleBarButtonClose
TitleBarButtonClose,
TitleBarButtonAutoHide
};
/**
@ -105,12 +106,24 @@ enum eDragState
DraggingFloatingWidget//!< DraggingFloatingWidget
};
/**
* Dock widget side tab bar locations
*/
enum SideTabBarArea
{
None,
Left,
Right,
Bottom
};
/**
* The different icons used in the UI
*/
enum eIcon
{
TabCloseIcon, //!< TabCloseIcon
AutoHideIcon, //!< AutoHideIcon
DockAreaMenuIcon, //!< DockAreaMenuIcon
DockAreaUndockIcon,//!< DockAreaUndockIcon
DockAreaCloseIcon, //!< DockAreaCloseIcon

View File

@ -2,7 +2,7 @@
* Default style sheet on Windows Platforms with focus highlighting flag enabled
*/
ads--CDockContainerWidget {
background: palette(dark);
background: palette(window);
}
ads--CDockContainerWidget > QSplitter{
padding: 1 0 1 0;
@ -22,6 +22,14 @@ ads--CDockWidgetTab {
qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/
}
ads--CDockWidgetSideTab {
background: palette(window);
border-color: palette(light);
border-style: solid;
border-width: 1px 1px 1px 1px;
padding: 0 0px;
}
ads--CDockWidgetTab[activeTab="true"] {
background: qlineargradient(spread : pad, x1 : 0, y1 : 0, x2 : 0, y2 : 0.5, stop : 0
palette(window), stop:1 palette(light));
@ -100,6 +108,10 @@ ads--CDockWidgetTab[focused="true"] {
border-color: palette(highlight);
}
ads--CDockWidgetSideTab[focused="true"] {
border-color: palette(highlight);
}
ads--CDockWidgetTab[focused="true"]>#tabCloseButton {
qproperty-icon: url(:/ads/images/close-button-focused.svg)
}
@ -126,4 +138,4 @@ ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar {
background: transparent;
border-bottom: 2px solid palette(highlight);
padding-bottom: 0px;
}
}