mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2025-01-24 05:22:06 +08:00
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:
parent
da8f17cce2
commit
3e9dc7f4d6
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
151
src/DockWidgetSideTab.cpp
Normal 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
96
src/DockWidgetSideTab.h
Normal 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
|
@ -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)
|
||||
{
|
||||
|
@ -58,6 +58,7 @@ private:
|
||||
friend struct DockWidgetTabPrivate;
|
||||
friend class CDockWidget;
|
||||
friend class CDockManager;
|
||||
friend class COverlayDockContainer;
|
||||
void onDockWidgetFeaturesChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
@ -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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
309
src/OverlayDockContainer.cpp
Normal file
309
src/OverlayDockContainer.cpp
Normal 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
129
src/OverlayDockContainer.h
Normal 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
101
src/SideTabBar.cpp
Normal 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
81
src/SideTabBar.h
Normal 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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user