Merge remote-tracking branch 'remotes/origin/autohide_drag'

This commit is contained in:
Uwe Kindler 2023-07-13 13:58:08 +02:00
commit f00ef60fb3
30 changed files with 1367 additions and 216 deletions

View File

@ -22,6 +22,70 @@ integrated development environments (IDEs) such as Visual Studio.
## New and Noteworthy
Release [4.1](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest) significantly improves the Auto-Hide functionality and also brings improvements
for Drag and Drop of dock widgets into dock area tabs. These are the highlights of the new version:
#### Drag & Drop to Auto-Hide
Now you can easily drag any dock widget or any floating widget to the
borders of a window to pin it as a auto-hide tab in one of the 4 sidebars.
If you drag a dock widget close the one of the four window borders, special
drop overlays will be shown to indicate the drop area for auto-hide widgets:
![Auo-Hide drag to Sidebar](doc/AutoHide_Drag_to_Sidebar.gif)
Of course, this also works with dock areas:
![Auo-Hide drag Dock Area](doc/AutoHide_Drag_DockArea.gif)
If you drag a dock widget or dock area into a sidebar, then you even have
control over where tabs are inserted. Simply drag your mouse over a specific
auto-hide tab, and your dragged dock widget will be inserted before this tab.
Drag to the sidebar area behind the last tab, and the dragged widget will be
appended as last tab. In the following screen capture, the **Image Viewer 1** will
be inserted before the **Table 0** Auto-Hide tab and the **Image Viewer 2**
is appende behind the last tab:
![Auo-Hide tab insert order](doc/AutoHide_Tab_Insert_Order.gif)
#### Auto-Hide Tab Insertion Order
It is also possible to drag Auto-Hide tabs to a new auto-hide position.
That means, you can drag them to a different border or sidebar:
![Auto-Hide change sidebar](doc/AutoHide_Change_Sidebar.gif)
#### Auto-Hide Tab Sorting
You can drag Auto-Hide tabs to a new position in the current sidebar
to sort them:
![Auo-Hide sort tabs](doc/AutoHide_Sort_Tabs.gif)
#### Auto-Hide Drag to Float / Dock
But that is not all. You can also simply move Auto-Hide tabs to another
floating widget or dock them via drag and drop:
![Auo-Hide drag to float or dock](doc/AutoHide_Drag_to_Float_or_Dock.gif)
#### Auto-Hide Context Menu
All Auto-Hide tabs now have a context menu, that provides all the functionality
that you know from Dock widget tabs. With the **Pin To...** item from the
context menu it is very easy to move an Auto-Hide tab to a different Auto-Hide
sidebar:
![Auo-Hide context menu](doc/AutoHide_Context_Menu.png)
#### Dock Area Tab Insert Order
And last but not least the new version also improves the docking of widgets
into the tabs of a Dock area. Just as with Auto-Hide tabs, you can now determine the position at which a tab is inserted by moving the mouse over an already existing tab (insertion before the tab) or behind the last tab
(appending):
![Dock area tab insert order](doc/DockArea_Tab_Insertion_Order.gif)
The [release 4.0](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System/releases/latest)
adds the following features:
@ -77,6 +141,12 @@ know it from Visual Studio.
### Overview
- [New and Noteworthy](#new-and-noteworthy)
- [Drag \& Drop to Auto-Hide](#drag--drop-to-auto-hide)
- [Auto-Hide Tab Insertion Order](#auto-hide-tab-insertion-order)
- [Auto-Hide Tab Sorting](#auto-hide-tab-sorting)
- [Auto-Hide Drag to Float / Dock](#auto-hide-drag-to-float--dock)
- [Auto-Hide Context Menu](#auto-hide-context-menu)
- [Dock Area Tab Insert Order](#dock-area-tab-insert-order)
- [Features](#features)
- [Overview](#overview)
- [Docking everywhere - no central widget](#docking-everywhere---no-central-widget)

View File

@ -448,8 +448,8 @@ void MainWindowPrivate::createContent()
// For this Special Dock Area we want to avoid dropping on the center of it (i.e. we don't want this widget to be ever tabbified):
{
SpecialDockArea->setAllowedAreas(ads::OuterDockAreas);
//SpecialDockArea->setAllowedAreas({ads::LeftDockWidgetArea, ads::RightDockWidgetArea}); // just for testing
//SpecialDockArea->setAllowedAreas(ads::OuterDockAreas);
SpecialDockArea->setAllowedAreas({ads::LeftDockWidgetArea, ads::RightDockWidgetArea, ads::TopDockWidgetArea}); // just for testing
}
DockWidget = createLongTextLabelDockWidget();
@ -517,7 +517,9 @@ void MainWindowPrivate::createContent()
// Test dock area docking
auto RighDockArea = DockManager->addDockWidget(ads::RightDockWidgetArea, createLongTextLabelDockWidget(), TopDockArea);
DockManager->addDockWidget(ads::TopDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
DockWidget = createLongTextLabelDockWidget();
DockWidget->setFeature(ads::CDockWidget::DockWidgetPinnable, false);
DockManager->addDockWidget(ads::TopDockWidgetArea, DockWidget, RighDockArea);
auto BottomDockArea = DockManager->addDockWidget(ads::BottomDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
DockManager->addDockWidget(ads::CenterDockWidgetArea, createLongTextLabelDockWidget(), RighDockArea);
auto LabelDockWidget = createLongTextLabelDockWidget();

View File

@ -117,6 +117,7 @@ struct AutoHideDockContainerPrivate
CResizeHandle* ResizeHandle = nullptr;
QSize Size; // creates invalid size
QPointer<CAutoHideTab> SideTab;
QSize SizeCache;
/**
* Private data constructor
@ -215,6 +216,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, SideBarL
bool OpaqueResize = CDockManager::testConfigFlag(CDockManager::OpaqueSplitterResize);
d->ResizeHandle->setOpaqueResize(OpaqueResize);
d->Size = d->DockArea->size();
d->SizeCache = DockWidget->size();
addDockWidget(DockWidget);
parent->registerAutoHideWidget(this);
@ -237,7 +239,6 @@ void CAutoHideDockContainer::updateSize()
}
auto rect = dockContainerParent->contentRect();
switch (sideBarLocation())
{
case SideBarLocation::SideBarTop:
@ -271,6 +272,15 @@ void CAutoHideDockContainer::updateSize()
default:
break;
}
if (orientation() == Qt::Horizontal)
{
d->SizeCache.setHeight(this->height());
}
else
{
d->SizeCache.setWidth(this->width());
}
}
//============================================================================
@ -294,7 +304,7 @@ CAutoHideDockContainer::~CAutoHideDockContainer()
}
//============================================================================
CAutoHideSideBar* CAutoHideDockContainer::sideBar() const
CAutoHideSideBar* CAutoHideDockContainer::autoHideSideBar() const
{
if (d->SideTab)
{
@ -303,7 +313,7 @@ CAutoHideSideBar* CAutoHideDockContainer::sideBar() const
else
{
auto DockContainer = dockContainer();
return DockContainer ? DockContainer->sideTabBar(d->SideTabBarArea) : nullptr;
return DockContainer ? DockContainer->autoHideSideBar(d->SideTabBarArea) : nullptr;
}
}
@ -344,6 +354,10 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget)
}
d->DockArea->addDockWidget(DockWidget);
updateSize();
// The dock area is not visible and will not update the size when updateSize()
// is called for this auto hide container. Therefore we explicitely resize
// it here. As soon as it will become visible, it will get the right size
d->DockArea->resize(size());
}
@ -643,5 +657,56 @@ bool CAutoHideDockContainer::event(QEvent* event)
return Super::event(event);
}
//============================================================================
Qt::Orientation CAutoHideDockContainer::orientation() const
{
return ads::internal::isHorizontalSideBarLocation(d->SideTabBarArea)
? Qt::Horizontal : Qt::Vertical;
}
//============================================================================
void CAutoHideDockContainer::resetToInitialDockWidgetSize()
{
if (orientation() == Qt::Horizontal)
{
setSize(d->SizeCache.height());
}
else
{
setSize(d->SizeCache.width());
}
}
//============================================================================
void CAutoHideDockContainer::moveToNewSideBarLocation(SideBarLocation NewSideBarLocation,
int TabIndex)
{
if (NewSideBarLocation == sideBarLocation() && TabIndex == this->tabIndex())
{
return;
}
auto OldOrientation = orientation();
auto SideBar = dockContainer()->autoHideSideBar(NewSideBarLocation);
SideBar->addAutoHideWidget(this, TabIndex);
// If we move a horizontal auto hide container to a vertical position
// then we resize it to the orginal dock widget size, to avoid
// an extremely streched dock widget after insertion
if (SideBar->orientation() != OldOrientation)
{
resetToInitialDockWidgetSize();
}
}
//============================================================================
int CAutoHideDockContainer::tabIndex() const
{
return d->SideTab->tabIndex();
}
}

View File

@ -93,7 +93,7 @@ public:
/**
* Get's the side tab bar
*/
CAutoHideSideBar* sideBar() const;
CAutoHideSideBar* autoHideSideBar() const;
/**
* Returns the side tab
@ -105,6 +105,11 @@ public:
*/
CDockWidget* dockWidget() const;
/**
* Returns the index of this container in the sidebar
*/
int tabIndex() const;
/**
* Adds a dock widget and removes the previous dock widget
*/
@ -166,6 +171,30 @@ public:
* of this auto hide container.
*/
void setSize(int Size);
/**
* Resets the with or hight to the initial dock widget size dependinng on
* the orientation.
* If the orientation is Qt::Horizontal, then the height is reset to
* the initial size and if orientation is Qt::Vertical, then the width is
* reset to the initial size
*/
void resetToInitialDockWidgetSize();
/**
* Returns orientation of this container.
* Left and right containers have a Qt::Vertical orientation and top / bottom
* containers have a Qt::Horizontal orientation.
* The function returns the orientation of the corresponding auto hide
* side bar.
*/
Qt::Orientation orientation() const;
/**
* Removes the AutoHide container from the current side bar and adds
* it to the new side bar given in SideBarLocation
*/
void moveToNewSideBarLocation(SideBarLocation SideBarLocation, int TabIndex = -1);
};
} // namespace ads

View File

@ -196,6 +196,7 @@ void CAutoHideSideBar::insertTab(int Index, CAutoHideTab* SideTab)
{
SideTab->setSideBar(this);
SideTab->installEventFilter(this);
// Default insertion is append
if (Index < 0)
{
d->TabsLayout->insertWidget(d->TabsLayout->count() - 1, SideTab);
@ -233,12 +234,25 @@ void CAutoHideSideBar::removeAutoHideWidget(CAutoHideDockContainer* AutoHideWidg
}
//============================================================================
void CAutoHideSideBar::addAutoHideWidget(CAutoHideDockContainer* AutoHideWidget)
void CAutoHideSideBar::addAutoHideWidget(CAutoHideDockContainer* AutoHideWidget,
int TabIndex)
{
auto SideBar = AutoHideWidget->autoHideTab()->sideBar();
if (SideBar == this)
{
return;
// If we move to the same tab index or if we insert before the next
// tab index, then we will end at the same tab position and can leave
if (AutoHideWidget->tabIndex() == TabIndex || (AutoHideWidget->tabIndex() + 1) == TabIndex)
{
return;
}
// We remove this auto hide widget from the sidebar in the code below
// and therefore need to correct the TabIndex here
if (AutoHideWidget->tabIndex() < TabIndex)
{
--TabIndex;
}
}
if (SideBar)
@ -248,7 +262,7 @@ void CAutoHideSideBar::addAutoHideWidget(CAutoHideDockContainer* AutoHideWidget)
AutoHideWidget->setParent(d->ContainerWidget);
AutoHideWidget->setSideBarLocation(d->SideTabArea);
d->ContainerWidget->registerAutoHideWidget(AutoHideWidget);
insertTab(-1, AutoHideWidget->autoHideTab());
insertTab(TabIndex, AutoHideWidget->autoHideTab());
}
@ -302,14 +316,14 @@ Qt::Orientation CAutoHideSideBar::orientation() const
//============================================================================
CAutoHideTab* CAutoHideSideBar::tabAt(int index) const
CAutoHideTab* CAutoHideSideBar::tab(int index) const
{
return qobject_cast<CAutoHideTab*>(d->TabsLayout->itemAt(index)->widget());
}
//============================================================================
int CAutoHideSideBar::tabCount() const
int CAutoHideSideBar::count() const
{
return d->TabsLayout->count() - 1;
}
@ -318,17 +332,17 @@ int CAutoHideSideBar::tabCount() const
//============================================================================
int CAutoHideSideBar::visibleTabCount() const
{
int count = 0;
int VisibleTabCount = 0;
auto ParentWidget = parentWidget();
for (auto i = 0; i < tabCount(); i++)
for (auto i = 0; i < count(); i++)
{
if (tabAt(i)->isVisibleTo(ParentWidget))
if (tab(i)->isVisibleTo(ParentWidget))
{
count++;
VisibleTabCount++;
}
}
return count;
return VisibleTabCount;
}
@ -336,9 +350,9 @@ int CAutoHideSideBar::visibleTabCount() const
bool CAutoHideSideBar::hasVisibleTabs() const
{
auto ParentWidget = parentWidget();
for (auto i = 0; i < tabCount(); i++)
for (auto i = 0; i < count(); i++)
{
if (tabAt(i)->isVisibleTo(ParentWidget))
if (tab(i)->isVisibleTo(ParentWidget))
{
return true;
}
@ -348,6 +362,21 @@ bool CAutoHideSideBar::hasVisibleTabs() const
}
//============================================================================
int CAutoHideSideBar::indexOfTab(const CAutoHideTab& Tab) const
{
for (auto i = 0; i < count(); i++)
{
if (tab(i) == &Tab)
{
return i;
}
}
return -1;
}
//============================================================================
SideBarLocation CAutoHideSideBar::sideBarLocation() const
{
@ -358,18 +387,18 @@ SideBarLocation CAutoHideSideBar::sideBarLocation() const
//============================================================================
void CAutoHideSideBar::saveState(QXmlStreamWriter& s) const
{
if (!tabCount())
if (!count())
{
return;
}
s.writeStartElement("SideBar");
s.writeAttribute("Area", QString::number(sideBarLocation()));
s.writeAttribute("Tabs", QString::number(tabCount()));
s.writeAttribute("Tabs", QString::number(count()));
for (auto i = 0; i < tabCount(); ++i)
for (auto i = 0; i < count(); ++i)
{
auto Tab = tabAt(i);
auto Tab = tab(i);
if (!Tab)
{
continue;
@ -417,5 +446,56 @@ CDockContainerWidget* CAutoHideSideBar::dockContainer() const
return d->ContainerWidget;
}
//===========================================================================
int CAutoHideSideBar::tabAt(const QPoint& Pos) const
{
if (!isVisible())
{
return TabInvalidIndex;
}
if (orientation() == Qt::Horizontal)
{
if (Pos.x() < tab(0)->geometry().x())
{
return -1;
}
}
else
{
if (Pos.y() < tab(0)->geometry().y())
{
return -1;
}
}
for (int i = 0; i < count(); ++i)
{
if (tab(i)->geometry().contains(Pos))
{
return i;
}
}
return count();
}
//===========================================================================
int CAutoHideSideBar::tabInsertIndexAt(const QPoint& Pos) const
{
int Index = tabAt(Pos);
if (Index == TabInvalidIndex)
{
return TabDefaultInsertIndex;
}
else
{
return (Index < 0) ? 0 : Index;
}
}
} // namespace ads

View File

@ -117,7 +117,7 @@ public:
* If the AutoHideWidget is in another sidebar, then it will be removed
* from this sidebar.
*/
void addAutoHideWidget(CAutoHideDockContainer* AutoHideWidget);
void addAutoHideWidget(CAutoHideDockContainer* AutoHideWidget, int Index = TabDefaultInsertIndex);
/**
* Returns orientation of side tab.
@ -125,14 +125,32 @@ public:
Qt::Orientation orientation() const;
/*
* get the side tab widget at position, returns nullptr if it's out of bounds
* Get the side tab widget at position, returns nullptr if it's out of bounds
*/
CAutoHideTab* tabAt(int index) const;
CAutoHideTab* tab(int index) const;
/**
* Returns the tab at the given position.
* Returns -1 if the position is left of the first tab and count() if the
* position is right of the last tab. Returns InvalidTabIndex (-2) to
* indicate an invalid value.
*/
int tabAt(const QPoint& Pos) const;
/**
* Returns the tab insertion index for the given mouse cursor position
*/
int tabInsertIndexAt(const QPoint& Pos) const;
/**
* Returns the index of the given tab
*/
int indexOfTab(const CAutoHideTab& Tab) const;
/*
* Gets the count of the tab widgets
*/
int tabCount() const;
int count() const;
/**
* Returns the number of visible tabs to its parent widget.

View File

@ -32,15 +32,20 @@
#include <QBoxLayout>
#include <QApplication>
#include <QElapsedTimer>
#include <QMenu>
#include "AutoHideDockContainer.h"
#include "AutoHideSideBar.h"
#include "DockAreaWidget.h"
#include "DockManager.h"
#include "DockWidget.h"
#include "FloatingDragPreview.h"
#include "DockOverlay.h"
namespace ads
{
static const char* const LocationProperty = "Location";
/**
* Private data class of CDockWidgetTab class (pimpl)
*/
@ -51,6 +56,12 @@ struct AutoHideTabPrivate
CAutoHideSideBar* SideBar = nullptr;
Qt::Orientation Orientation{Qt::Vertical};
QElapsedTimer TimeSinceHoverMousePress;
bool MousePressed = false;
eDragState DragState = DraggingInactive;
QPoint GlobalDragStartMousePosition;
QPoint DragStartMousePosition;
IFloatingWidget* FloatingWidget = nullptr;
Qt::Orientation DragStartOrientation;
/**
* Private data constructor
@ -82,6 +93,55 @@ struct AutoHideTabPrivate
DockContainer->handleAutoHideWidgetEvent(event, _this);
}
}
/**
* Helper function to create and initialize the menu entries for
* the "Auto Hide Group To..." menu
*/
QAction* createAutoHideToAction(const QString& Title, SideBarLocation Location,
QMenu* Menu)
{
auto Action = Menu->addAction(Title);
Action->setProperty("Location", Location);
QObject::connect(Action, &QAction::triggered, _this, &CAutoHideTab::onAutoHideToActionClicked);
Action->setEnabled(Location != _this->sideBarLocation());
return Action;
}
/**
* Test function for current drag state
*/
bool isDraggingState(eDragState dragState) const
{
return this->DragState == dragState;
}
/**
* Saves the drag start position in global and local coordinates
*/
void saveDragStartMousePosition(const QPoint& GlobalPos)
{
GlobalDragStartMousePosition = GlobalPos;
DragStartMousePosition = _this->mapFromGlobal(GlobalPos);
}
/**
* Starts floating of the dock widget that belongs to this title bar
* Returns true, if floating has been started and false if floating
* is not possible for any reason
*/
bool startFloating(eDragState DraggingState = DraggingFloatingWidget);
template <typename T>
IFloatingWidget* createFloatingWidget(T* Widget)
{
auto w = new CFloatingDragPreview(Widget);
_this->connect(w, &CFloatingDragPreview::draggingCanceled, [=]()
{
DragState = DraggingInactive;
});
return w;
}
}; // struct DockWidgetTabPrivate
@ -110,6 +170,53 @@ void AutoHideTabPrivate::updateOrientation()
}
//============================================================================
bool AutoHideTabPrivate::startFloating(eDragState DraggingState)
{
auto DockArea = DockWidget->dockAreaWidget();
ADS_PRINT("isFloating " << dockContainer->isFloating());
ADS_PRINT("startFloating");
DragState = DraggingState;
IFloatingWidget* FloatingWidget = nullptr;
FloatingWidget = createFloatingWidget(DockArea);
auto Size = DockArea->size();
auto StartPos = DragStartMousePosition;
auto AutoHideContainer = DockWidget->autoHideDockContainer();
DragStartOrientation = AutoHideContainer->orientation();
switch (SideBar->sideBarLocation())
{
case SideBarLeft:
StartPos.rx() = AutoHideContainer->rect().left() + 10;
break;
case SideBarRight:
StartPos.rx() = AutoHideContainer->rect().right() - 10;
break;
case SideBarTop:
StartPos.ry() = AutoHideContainer->rect().top() + 10;
break;
case SideBarBottom:
StartPos.ry() = AutoHideContainer->rect().bottom() - 10;
break;
case SideBarNone:
return false;
}
FloatingWidget->startFloating(StartPos, Size, DraggingFloatingWidget, _this);
auto DockManager = DockWidget->dockManager();
auto Overlay = DockManager->containerOverlay();
Overlay->setAllowedAreas(OuterDockAreas);
this->FloatingWidget = FloatingWidget;
qApp->postEvent(DockWidget, new QEvent((QEvent::Type)internal::DockedWidgetDragStartEvent));
return true;
}
//============================================================================
void CAutoHideTab::setSideBar(CAutoHideSideBar* SideTabBar)
{
@ -250,32 +357,205 @@ bool CAutoHideTab::event(QEvent* event)
d->forwardEventToDockContainer(event);
break;
case QEvent::MouseButtonPress:
// If AutoHideShowOnMouseOver is active, then the showing is triggered
// by a MousePressEvent sent to this tab. To prevent accidental hiding
// of the tab by a mouse click, we wait at least 500 ms before we accept
// the mouse click
if (!event->spontaneous())
{
d->TimeSinceHoverMousePress.restart();
d->forwardEventToDockContainer(event);
}
else if (d->TimeSinceHoverMousePress.hasExpired(500))
{
d->forwardEventToDockContainer(event);
}
break;
default:
break;
}
return Super::event(event);
}
//============================================================================
bool CAutoHideTab::iconOnly() const
{
return CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideSideBarsIconOnly) && !icon().isNull();
}
//============================================================================
void CAutoHideTab::contextMenuEvent(QContextMenuEvent* ev)
{
ev->accept();
d->saveDragStartMousePosition(ev->globalPos());
const bool isFloatable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable);
QAction* Action;
QMenu Menu(this);
Action = Menu.addAction(tr("Detach"), this, SLOT(setDockWidgetFloating()));
Action->setEnabled(isFloatable);
auto IsPinnable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable);
Action->setEnabled(IsPinnable);
auto menu = Menu.addMenu(tr("Pin To..."));
menu->setEnabled(IsPinnable);
d->createAutoHideToAction(tr("Top"), SideBarTop, menu);
d->createAutoHideToAction(tr("Left"), SideBarLeft, menu);
d->createAutoHideToAction(tr("Right"), SideBarRight, menu);
d->createAutoHideToAction(tr("Bottom"), SideBarBottom, menu);
Action = Menu.addAction(tr("Unpin (Dock)"), this, SLOT(unpinDockWidget()));
Menu.addSeparator();
Action = Menu.addAction(tr("Close"), this, SLOT(requestCloseDockWidget()));
Action->setEnabled(d->DockWidget->features().testFlag(CDockWidget::DockWidgetClosable));
Menu.exec(ev->globalPos());
}
//============================================================================
void CAutoHideTab::setDockWidgetFloating()
{
d->DockWidget->setFloating();
}
//============================================================================
void CAutoHideTab::unpinDockWidget()
{
d->DockWidget->setAutoHide(false);
}
//===========================================================================
void CAutoHideTab::onAutoHideToActionClicked()
{
int Location = sender()->property(LocationProperty).toInt();
d->DockWidget->setAutoHide(true, (SideBarLocation)Location);
}
//============================================================================
void CAutoHideTab::mousePressEvent(QMouseEvent* ev)
{
// If AutoHideShowOnMouseOver is active, then the showing is triggered
// by a MousePressEvent sent to this tab. To prevent accidental hiding
// of the tab by a mouse click, we wait at least 500 ms before we accept
// the mouse click
if (!ev->spontaneous())
{
d->TimeSinceHoverMousePress.restart();
d->forwardEventToDockContainer(ev);
}
else if (d->TimeSinceHoverMousePress.hasExpired(500))
{
d->forwardEventToDockContainer(ev);
}
if (ev->button() == Qt::LeftButton)
{
ev->accept();
d->MousePressed = true;
d->saveDragStartMousePosition(internal::globalPositionOf(ev));
d->DragState = DraggingMousePressed;
}
Super::mousePressEvent(ev);
}
//============================================================================
void CAutoHideTab::mouseReleaseEvent(QMouseEvent* ev)
{
if (ev->button() == Qt::LeftButton)
{
d->MousePressed = false;
auto CurrentDragState = d->DragState;
d->GlobalDragStartMousePosition = QPoint();
d->DragStartMousePosition = QPoint();
d->DragState = DraggingInactive;
switch (CurrentDragState)
{
case DraggingTab:
// End of tab moving, emit signal
/*if (d->DockArea)
{
ev->accept();
Q_EMIT moved(internal::globalPositionOf(ev));
}*/
break;
case DraggingFloatingWidget:
ev->accept();
d->FloatingWidget->finishDragging();
if (d->DockWidget->isAutoHide() && d->DragStartOrientation != orientation())
{
d->DockWidget->autoHideDockContainer()->resetToInitialDockWidgetSize();
}
break;
default:
break; // do nothing
}
}
Super::mouseReleaseEvent(ev);
}
//============================================================================
void CAutoHideTab::mouseMoveEvent(QMouseEvent* ev)
{
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
{
d->DragState = DraggingInactive;
Super::mouseMoveEvent(ev);
return;
}
// move floating window
if (d->isDraggingState(DraggingFloatingWidget))
{
d->FloatingWidget->moveFloating();
Super::mouseMoveEvent(ev);
return;
}
// move tab
if (d->isDraggingState(DraggingTab))
{
// Moving the tab is always allowed because it does not mean moving the
// dock widget around
//d->moveTab(ev);
}
auto MappedPos = mapToParent(ev->pos());
bool MouseOutsideBar = (MappedPos.x() < 0) || (MappedPos.x() > parentWidget()->rect().right());
// Maybe a fixed drag distance is better here ?
int DragDistanceY = qAbs(d->GlobalDragStartMousePosition.y() - internal::globalPositionOf(ev).y());
if (DragDistanceY >= CDockManager::startDragDistance() || MouseOutsideBar)
{
// Floating is only allowed for widgets that are floatable
// We can create the drag preview if the widget is movable.
auto Features = d->DockWidget->features();
if (Features.testFlag(CDockWidget::DockWidgetFloatable) || (Features.testFlag(CDockWidget::DockWidgetMovable)))
{
d->startFloating();
}
return;
}
Super::mouseMoveEvent(ev);
}
//============================================================================
void CAutoHideTab::requestCloseDockWidget()
{
d->DockWidget->requestCloseDockWidget();
}
//============================================================================
int CAutoHideTab::tabIndex() const
{
if (!d->SideBar)
{
return -1;
}
return d->SideBar->indexOfTab(*this);
}
}

View File

@ -65,11 +65,17 @@ private:
friend class CDockContainerWidget;
friend DockContainerWidgetPrivate;
private Q_SLOTS:
void onAutoHideToActionClicked();
protected:
void setSideBar(CAutoHideSideBar *SideTabBar);
void removeFromSideBar();
virtual bool event(QEvent* event) override;
virtual void contextMenuEvent(QContextMenuEvent* ev) override;
virtual void mousePressEvent(QMouseEvent* ev) override;
virtual void mouseReleaseEvent(QMouseEvent* ev) override;
virtual void mouseMoveEvent(QMouseEvent* ev) override;
public:
using Super = CPushButton;
@ -133,6 +139,27 @@ public:
* not in a side bar
*/
CAutoHideSideBar* sideBar() const;
/**
* Returns the index of this tab in the sideBar
*/
int tabIndex() const;
public Q_SLOTS:
/**
* Set the dock widget floating, if it is floatable
*/
void setDockWidgetFloating();
/**
* Unpin and dock the auto hide widget
*/
void unpinDockWidget();
/**
* Calls the requestCloseDockWidget() function for the assigned dock widget
*/
void requestCloseDockWidget();
}; // class AutoHideTab
}
// namespace ads

View File

@ -504,6 +504,46 @@ QSize CDockAreaTabBar::sizeHint() const
return d->TabsContainerWidget->sizeHint();
}
//===========================================================================
int CDockAreaTabBar::tabAt(const QPoint& Pos) const
{
if (!isVisible())
{
return TabInvalidIndex;
}
if (Pos.x() < tab(0)->geometry().x())
{
return -1;
}
for (int i = 0; i < count(); ++i)
{
if (tab(i)->geometry().contains(Pos))
{
return i;
}
}
return count();
}
//===========================================================================
int CDockAreaTabBar::tabInsertIndexAt(const QPoint& Pos) const
{
int Index = tabAt(Pos);
if (Index == TabInvalidIndex)
{
return TabDefaultInsertIndex;
}
else
{
return (Index < 0) ? 0 : Index;
}
}
} // namespace ads

View File

@ -113,6 +113,19 @@ public:
*/
CDockWidgetTab* tab(int Index) const;
/**
* Returns the tab at the given position.
* Returns -1 if the position is left of the first tab and count() if the
* position is right of the last tab. Returns -2 to indicate an invalid
* value.
*/
int tabAt(const QPoint& Pos) const;
/**
* Returns the tab insertion index for the given mouse cursor position
*/
int tabInsertIndexAt(const QPoint& Pos) const;
/**
* Filters the tab widget events
*/

View File

@ -68,10 +68,10 @@ static const char* const LocationProperty = "Location";
struct DockAreaTitleBarPrivate
{
CDockAreaTitleBar* _this;
QPointer<tTitleBarButton> TabsMenuButton;
QPointer<tTitleBarButton> AutoHideButton;
QPointer<tTitleBarButton> UndockButton;
QPointer<tTitleBarButton> CloseButton;
QPointer<CTitleBarButton> TabsMenuButton;
QPointer<CTitleBarButton> AutoHideButton;
QPointer<CTitleBarButton> UndockButton;
QPointer<CTitleBarButton> CloseButton;
QBoxLayout* Layout;
CDockAreaWidget* DockArea;
CDockAreaTabBar* TabBar;
@ -539,7 +539,7 @@ void CDockAreaTitleBar::onAutoHideToActionClicked()
//============================================================================
QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const
CTitleBarButton* CDockAreaTitleBar::button(TitleBarButton which) const
{
switch (which)
{
@ -677,6 +677,28 @@ void CDockAreaTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
}
//============================================================================
void CDockAreaTitleBar::setAreaFloating()
{
// If this is the last dock area in a dock container it does not make
// sense to move it to a new floating widget and leave this one
// empty.
auto DockContainer = d->DockArea->dockContainer();
if (DockContainer->isFloating() && DockContainer->dockAreaCount() == 1
&& !d->DockArea->isAutoHide())
{
return;
}
if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
{
return;
}
d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
}
//============================================================================
void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev)
{
@ -781,9 +803,9 @@ QString CDockAreaTitleBar::titleBarButtonToolTip(TitleBarButton Button) const
}
//============================================================================
CTitleBarButton::CTitleBarButton(bool visible, QWidget* parent)
CTitleBarButton::CTitleBarButton(bool showInTitleBar, QWidget* parent)
: tTitleBarButton(parent),
Visible(visible),
ShowInTitleBar(showInTitleBar),
HideWhenDisabled(CDockManager::testConfigFlag(CDockManager::DockAreaHideDisabledButtons))
{
setFocusPolicy(Qt::NoFocus);
@ -793,7 +815,7 @@ CTitleBarButton::CTitleBarButton(bool visible, QWidget* parent)
void CTitleBarButton::setVisible(bool visible)
{
// 'visible' can stay 'true' if and only if this button is configured to generaly visible:
visible = visible && this->Visible;
visible = visible && this->ShowInTitleBar;
// 'visible' can stay 'true' unless: this button is configured to be invisible when it is disabled and it is currently disabled:
if (visible && HideWhenDisabled)
@ -804,6 +826,18 @@ void CTitleBarButton::setVisible(bool visible)
Super::setVisible(visible);
}
//============================================================================
void CTitleBarButton::setShowInTitleBar(bool Show)
{
this->ShowInTitleBar = Show;
if (!Show)
{
setVisible(false);
}
}
//============================================================================
bool CTitleBarButton::event(QEvent *ev)
{

View File

@ -30,6 +30,7 @@
//============================================================================
// INCLUDES
//============================================================================
#include <QToolButton>
#include <QFrame>
#include "ads_globals.h"
@ -43,6 +44,44 @@ class CDockAreaWidget;
struct DockAreaTitleBarPrivate;
class CElidingLabel;
using tTitleBarButton = QToolButton;
/**
* Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour
* according to various config flags such as:
* CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible
* CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled
*/
class CTitleBarButton : public tTitleBarButton
{
Q_OBJECT
private:
bool ShowInTitleBar = true;
bool HideWhenDisabled = false;
public:
using Super = tTitleBarButton;
CTitleBarButton(bool ShowInTitleBar = true, QWidget* parent = nullptr);
/**
* Adjust this visibility change request with our internal settings:
*/
virtual void setVisible(bool visible) override;
/**
* Configures, if the title bar button should be shown in title bar
*/
void setShowInTitleBar(bool Show);
protected:
/**
* Handle EnabledChanged signal to set button invisible if the configured
*/
bool event(QEvent *ev) override;
};
/**
* Title bar of a dock area.
* The title bar contains a tabbar with all tabs for a dock widget group and
@ -121,7 +160,7 @@ public:
/**
* Returns the button corresponding to the given title bar button identifier
*/
QAbstractButton* button(TitleBarButton which) const;
CTitleBarButton* button(TitleBarButton which) const;
/**
* Returns the auto hide title label, used when the dock area is expanded and auto hidden
@ -163,6 +202,12 @@ public:
*/
QString titleBarButtonToolTip(TitleBarButton Button) const;
/**
* Moves the dock area into its own floating widget if the area
* DockWidgetFloatable flag is true
*/
void setAreaFloating();
Q_SIGNALS:
/**
* This signal is emitted if a tab in the tab bar is clicked by the user

View File

@ -31,43 +31,12 @@
// INCLUDES
//============================================================================
#include <QFrame>
#include <QToolButton>
#include "ads_globals.h"
namespace ads
{
using tTitleBarButton = QToolButton;
/**
* Title bar button of a dock area that customizes tTitleBarButton appearance/behaviour
* according to various config flags such as:
* CDockManager::DockAreaHas_xxx_Button - if set to 'false' keeps the button always invisible
* CDockManager::DockAreaHideDisabledButtons - if set to 'true' hides button when it is disabled
*/
class CTitleBarButton : public tTitleBarButton
{
Q_OBJECT
private:
bool Visible = true;
bool HideWhenDisabled = false;
public:
using Super = tTitleBarButton;
CTitleBarButton(bool visible = true, QWidget* parent = nullptr);
/**
* Adjust this visibility change request with our internal settings:
*/
virtual void setVisible(bool visible) override;
protected:
/**
* Handle EnabledChanged signal to set button invisible if the configured
*/
bool event(QEvent *ev) override;
};
/**

View File

@ -467,6 +467,7 @@ void CDockAreaWidget::setAutoHideDockContainer(CAutoHideDockContainer* AutoHideD
d->AutoHideDockContainer = AutoHideDockContainer;
updateAutoHideButtonCheckState();
updateTitleBarButtonsToolTips();
d->TitleBar->button(TitleBarButtonAutoHide)->setShowInTitleBar(true);
}
@ -626,15 +627,7 @@ void CDockAreaWidget::hideAreaWithNoVisibleContent()
void CDockAreaWidget::onTabCloseRequested(int Index)
{
ADS_PRINT("CDockAreaWidget::onTabCloseRequested " << Index);
auto* DockWidget = dockWidget(Index);
if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) || DockWidget->features().testFlag(CDockWidget::CustomCloseHandling))
{
DockWidget->closeDockWidgetInternal();
}
else
{
DockWidget->toggleView(false);
}
dockWidget(Index)->requestCloseDockWidget();
}
@ -1312,7 +1305,7 @@ SideBarLocation CDockAreaWidget::calculateSideTabBarArea() const
//============================================================================
void CDockAreaWidget::setAutoHide(bool Enable, SideBarLocation Location)
void CDockAreaWidget::setAutoHide(bool Enable, SideBarLocation Location, int TabIndex)
{
if (!isAutoHideFeatureEnabled())
{
@ -1323,11 +1316,18 @@ void CDockAreaWidget::setAutoHide(bool Enable, SideBarLocation Location)
{
if (isAutoHide())
{
autoHideDockContainer()->moveContentsToParent();
d->AutoHideDockContainer->moveContentsToParent();
}
return;
}
// If this is already an auto hide container, then move it to new location
if (isAutoHide())
{
d->AutoHideDockContainer->moveToNewSideBarLocation(Location, TabIndex);
return;
}
auto area = (SideBarNone == Location) ? calculateSideTabBarArea() : Location;
for (const auto DockWidget : openedDockWidgets())
{
@ -1341,7 +1341,7 @@ void CDockAreaWidget::setAutoHide(bool Enable, SideBarLocation Location)
continue;
}
dockContainer()->createAndSetupAutoHideContainer(area, DockWidget);
dockContainer()->createAndSetupAutoHideContainer(area, DockWidget, TabIndex++);
}
}
@ -1442,6 +1442,13 @@ bool CDockAreaWidget::isTopLevelArea() const
}
//============================================================================
void CDockAreaWidget::setFloating()
{
d->TitleBar->setAreaFloating();
}
#ifdef Q_OS_WIN
//============================================================================
bool CDockAreaWidget::event(QEvent *e)

View File

@ -221,7 +221,6 @@ public:
*/
bool isAutoHide() const;
/**
* Sets the current auto hide dock container
*/
@ -401,7 +400,7 @@ public Q_SLOTS:
* If the dock area is switched to auto hide mode, then all dock widgets
* that are pinable will be added to the sidebar
*/
void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone);
void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone, int TabIndex = -1);
/**
* Switches the dock area to auto hide mode or vice versa depending on its
@ -414,6 +413,12 @@ public Q_SLOTS:
*/
void closeOtherAreas();
/**
* Moves the dock area into its own floating widget if the area
* DockWidgetFloatable flag is true
*/
void setFloating();
Q_SIGNALS:
/**
* This signal is emitted when user clicks on a tab at an index.

View File

@ -145,7 +145,7 @@ public:
QList<CAutoHideDockContainer*> AutoHideWidgets;
QMap<SideBarLocation, CAutoHideSideBar*> SideTabBarWidgets;
QGridLayout* Layout = nullptr;
QSplitter* RootSplitter = nullptr;
CDockSplitter* RootSplitter = nullptr;
bool isFloating = false;
CDockAreaWidget* LastAddedAreaCache[5];
int VisibleDockAreaCount = -1;
@ -181,17 +181,29 @@ public:
*/
void dropIntoContainer(CFloatingDockContainer* FloatingWidget, DockWidgetArea area);
/**
* Drop floating widget into auto hide side bar
*/
void dropIntoAutoHideSideBar(CFloatingDockContainer* FloatingWidget, DockWidgetArea area);
/**
* Creates a new tab for a widget dropped into the center of a section
*/
void dropIntoCenterOfSection(CFloatingDockContainer* FloatingWidget,
CDockAreaWidget* TargetArea, int TabIndex = 0);
/**
* Drop floating widget into dock area
*/
void dropIntoSection(CFloatingDockContainer* FloatingWidget,
CDockAreaWidget* TargetArea, DockWidgetArea area);
CDockAreaWidget* TargetArea, DockWidgetArea area, int TabIndex = 0);
/**
* Moves the dock widget or dock area given in Widget parameter to a
* new dock widget area
*/
void moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area);
void moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area,
int TabIndex = 0);
/**
* Moves the dock widget or dock area given in Widget parameter to a
@ -202,13 +214,13 @@ public:
/**
* Creates a new tab for a widget dropped into the center of a section
*/
void dropIntoCenterOfSection(CFloatingDockContainer* FloatingWidget,
CDockAreaWidget* TargetArea);
void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea, int TabIndex = 0);
/**
* Creates a new tab for a widget dropped into the center of a section
* Moves the dock widget or dock area given in Widget parameter to
* a auto hide sidebar area
*/
void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea);
void moveToAutoHideSideBar(QWidget* Widget, DockWidgetArea area, int TabIndex = TabDefaultInsertIndex);
/**
@ -454,7 +466,7 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
CDockContainerWidget* FloatingDockContainer = FloatingWidget->dockContainer();
auto NewDockAreas = FloatingDockContainer->findChildren<CDockAreaWidget*>(
QString(), Qt::FindChildrenRecursively);
QSplitter* Splitter = RootSplitter;
auto Splitter = RootSplitter;
if (DockAreas.count() <= 1)
{
@ -462,7 +474,7 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
}
else if (Splitter->orientation() != InsertParam.orientation())
{
QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
auto NewSplitter = newSplitter(InsertParam.orientation());
QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
NewSplitter->addWidget(Splitter);
updateSplitterHandles(NewSplitter);
@ -505,14 +517,33 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
}
//============================================================================
void DockContainerWidgetPrivate::dropIntoAutoHideSideBar(CFloatingDockContainer* FloatingWidget, DockWidgetArea area)
{
auto SideBarLocation = internal::toSideBarLocation(area);
auto NewDockAreas = FloatingWidget->findChildren<CDockAreaWidget*>(
QString(), Qt::FindChildrenRecursively);
int TabIndex = DockManager->containerOverlay()->tabIndexUnderCursor();
for (auto DockArea : NewDockAreas)
{
auto DockWidgets = DockArea->dockWidgets();
for (auto DockWidget : DockWidgets)
{
_this->createAndSetupAutoHideContainer(SideBarLocation, DockWidget, TabIndex++);
}
}
}
//============================================================================
void DockContainerWidgetPrivate::dropIntoCenterOfSection(
CFloatingDockContainer* FloatingWidget, CDockAreaWidget* TargetArea)
CFloatingDockContainer* FloatingWidget, CDockAreaWidget* TargetArea, int TabIndex)
{
CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer();
auto NewDockWidgets = FloatingContainer->dockWidgets();
auto TopLevelDockArea = FloatingContainer->topLevelDockArea();
int NewCurrentIndex = -1;
TabIndex = qMax(0, TabIndex);
// If the floating widget contains only one single dock are, then the
// current dock widget of the dock area will also be the future current
@ -525,7 +556,7 @@ void DockContainerWidgetPrivate::dropIntoCenterOfSection(
for (int i = 0; i < NewDockWidgets.count(); ++i)
{
CDockWidget* DockWidget = NewDockWidgets[i];
TargetArea->insertDockWidget(i, DockWidget, false);
TargetArea->insertDockWidget(TabIndex + i, DockWidget, false);
// If the floating widget contains multiple visible dock areas, then we
// simply pick the first visible open dock widget and make it
// the current one.
@ -534,7 +565,7 @@ void DockContainerWidgetPrivate::dropIntoCenterOfSection(
NewCurrentIndex = i;
}
}
TargetArea->setCurrentIndex(NewCurrentIndex);
TargetArea->setCurrentIndex(NewCurrentIndex + TabIndex);
TargetArea->updateTitleBarVisibility();
return;
}
@ -542,13 +573,13 @@ void DockContainerWidgetPrivate::dropIntoCenterOfSection(
//============================================================================
void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* FloatingWidget,
CDockAreaWidget* TargetArea, DockWidgetArea area)
CDockAreaWidget* TargetArea, DockWidgetArea area, int TabIndex)
{
// Dropping into center means all dock widgets in the dropped floating
// widget will become tabs of the drop area
if (CenterDockWidgetArea == area)
{
dropIntoCenterOfSection(FloatingWidget, TargetArea);
dropIntoCenterOfSection(FloatingWidget, TargetArea, TabIndex);
return;
}
@ -638,11 +669,13 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin
//============================================================================
void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea)
void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea,
int TabIndex)
{
auto DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
auto DroppedArea = qobject_cast<CDockAreaWidget*>(Widget);
TabIndex = qMax(0, TabIndex);
if (DroppedDockWidget)
{
CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget();
@ -655,7 +688,7 @@ void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockA
{
OldDockArea->removeDockWidget(DroppedDockWidget);
}
TargetArea->insertDockWidget(0, DroppedDockWidget, true);
TargetArea->insertDockWidget(TabIndex, DroppedDockWidget, true);
}
else
{
@ -664,9 +697,9 @@ void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockA
for (int i = 0; i < NewDockWidgets.count(); ++i)
{
CDockWidget* DockWidget = NewDockWidgets[i];
TargetArea->insertDockWidget(i, DockWidget, false);
TargetArea->insertDockWidget(TabIndex + i, DockWidget, false);
}
TargetArea->setCurrentIndex(NewCurrentIndex);
TargetArea->setCurrentIndex(TabIndex + NewCurrentIndex);
DroppedArea->dockContainer()->removeDockArea(DroppedArea);
DroppedArea->deleteLater();
}
@ -677,13 +710,14 @@ void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockA
//============================================================================
void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area)
void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area,
int TabIndex)
{
// Dropping into center means all dock widgets in the dropped floating
// widget will become tabs of the drop area
if (CenterDockWidgetArea == area)
{
moveIntoCenterOfSection(Widget, TargetArea);
moveIntoCenterOfSection(Widget, TargetArea, TabIndex);
return;
}
@ -738,6 +772,48 @@ void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidg
}
//============================================================================
void DockContainerWidgetPrivate::moveToAutoHideSideBar(QWidget* Widget, DockWidgetArea area, int TabIndex)
{
CDockWidget* DroppedDockWidget = qobject_cast<CDockWidget*>(Widget);
CDockAreaWidget* DroppedDockArea = qobject_cast<CDockAreaWidget*>(Widget);
auto SideBarLocation = internal::toSideBarLocation(area);
if (DroppedDockWidget)
{
if (_this == DroppedDockWidget->dockContainer())
{
DroppedDockWidget->setAutoHide(true, SideBarLocation, TabIndex);
}
else
{
_this->createAndSetupAutoHideContainer(SideBarLocation, DroppedDockWidget, TabIndex);
}
}
else
{
if (_this == DroppedDockArea->dockContainer())
{
DroppedDockArea->setAutoHide(true, SideBarLocation, TabIndex);
}
else
{
for (const auto DockWidget : DroppedDockArea->openedDockWidgets())
{
if (!DockWidget->features().testFlag(
CDockWidget::DockWidgetPinnable))
{
continue;
}
_this->createAndSetupAutoHideContainer(SideBarLocation,
DockWidget, TabIndex++);
}
}
}
}
//============================================================================
void DockContainerWidgetPrivate::updateSplitterHandles( QSplitter* splitter )
{
@ -908,7 +984,7 @@ void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter& s)
{
for (const auto sideTabBar : SideTabBarWidgets.values())
{
if (!sideTabBar->tabCount())
if (!sideTabBar->count())
{
continue;
}
@ -1101,12 +1177,12 @@ bool DockContainerWidgetPrivate::restoreSideBar(CDockingStateReader& s,
continue;
}
auto SideBar = _this->sideTabBar(Area);
auto SideBar = _this->autoHideSideBar(Area);
CAutoHideDockContainer* AutoHideContainer;
if (DockWidget->isAutoHide())
{
AutoHideContainer = DockWidget->autoHideDockContainer();
if (AutoHideContainer->sideBar() != SideBar)
if (AutoHideContainer->autoHideSideBar() != SideBar)
{
SideBar->addAutoHideWidget(AutoHideContainer);
}
@ -1193,7 +1269,7 @@ void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockW
}
else
{
QSplitter* NewSplitter = newSplitter(InsertParam.orientation());
auto NewSplitter = newSplitter(InsertParam.orientation());
if (InsertParam.append())
{
QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter);
@ -1404,7 +1480,7 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW
//============================================================================
CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer(
SideBarLocation area, CDockWidget* DockWidget)
SideBarLocation area, CDockWidget* DockWidget, int TabIndex)
{
if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled))
{
@ -1417,7 +1493,7 @@ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer(
DockWidget->setDockManager(d->DockManager); // Auto hide Dock Container needs a valid dock manager
}
return sideTabBar(area)->insertDockWidget(-1, DockWidget);
return autoHideSideBar(area)->insertDockWidget(TabIndex, DockWidget);
}
@ -1528,7 +1604,7 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
}
QWidget* widget = Splitter->widget(0);
QSplitter* ChildSplitter = qobject_cast<QSplitter*>(widget);
auto ChildSplitter = qobject_cast<CDockSplitter*>(widget);
// If the one and only content widget of the splitter is not a splitter
// then we are finished
if (!ChildSplitter)
@ -1629,11 +1705,12 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
ADS_PRINT("CDockContainerWidget::dropFloatingWidget");
CDockWidget* SingleDroppedDockWidget = FloatingWidget->topLevelDockWidget();
CDockWidget* SingleDockWidget = topLevelDockWidget();
CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
auto dropArea = InvalidDockWidgetArea;
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
bool Dropped = false;
CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
// mouse is over dock area
if (DockArea)
{
auto dropOverlay = d->DockManager->dockAreaOverlay();
@ -1648,28 +1725,33 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
if (dropArea != InvalidDockWidgetArea)
{
ADS_PRINT("Dock Area Drop Content: " << dropArea);
d->dropIntoSection(FloatingWidget, DockArea, dropArea);
int TabIndex = d->DockManager->dockAreaOverlay()->tabIndexUnderCursor();
d->dropIntoSection(FloatingWidget, DockArea, dropArea, TabIndex);
Dropped = true;
}
}
// mouse is over container
if (InvalidDockWidgetArea == dropArea)
// mouse is over container or auto hide side bar
if (InvalidDockWidgetArea == dropArea && InvalidDockWidgetArea != ContainerDropArea)
{
dropArea = ContainerDropArea;
ADS_PRINT("Container Drop Content: " << dropArea);
if (dropArea != InvalidDockWidgetArea)
{
d->dropIntoContainer(FloatingWidget, dropArea);
Dropped = true;
}
if (internal::isSideBarArea(ContainerDropArea))
{
ADS_PRINT("Container Drop Content: " << ContainerDropArea);
d->dropIntoAutoHideSideBar(FloatingWidget, ContainerDropArea);
}
else
{
ADS_PRINT("Container Drop Content: " << ContainerDropArea);
d->dropIntoContainer(FloatingWidget, ContainerDropArea);
}
Dropped = true;
}
// Remove the auto hide widgets from the FloatingWidget and insert
// them into this widget
for (auto AutohideWidget : FloatingWidget->dockContainer()->autoHideWidgets())
{
auto SideBar = sideTabBar(AutohideWidget->sideBarLocation());
auto SideBar = autoHideSideBar(AutohideWidget->sideBarLocation());
SideBar->addAutoHideWidget(AutohideWidget);
}
@ -1697,12 +1779,17 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
//============================================================================
void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget)
void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget,
int TabIndex)
{
CDockWidget* SingleDockWidget = topLevelDockWidget();
if (TargetAreaWidget)
{
d->moveToNewSection(Widget, TargetAreaWidget, DropArea);
d->moveToNewSection(Widget, TargetAreaWidget, DropArea, TabIndex);
}
else if (internal::isSideBarArea(DropArea))
{
d->moveToAutoHideSideBar(Widget, DropArea, TabIndex);
}
else
{
@ -1846,8 +1933,8 @@ bool CDockContainerWidget::restoreState(CDockingStateReader& s, bool Testing)
}
d->Layout->replaceWidget(d->RootSplitter, NewRootSplitter);
QSplitter* OldRoot = d->RootSplitter;
d->RootSplitter = qobject_cast<QSplitter*>(NewRootSplitter);
auto OldRoot = d->RootSplitter;
d->RootSplitter = qobject_cast<CDockSplitter*>(NewRootSplitter);
OldRoot->deleteLater();
return true;
@ -2051,7 +2138,7 @@ void CDockContainerWidget::closeOtherAreas(CDockAreaWidget* KeepOpenArea)
}
//============================================================================
CAutoHideSideBar* CDockContainerWidget::sideTabBar(SideBarLocation area) const
CAutoHideSideBar* CDockContainerWidget::autoHideSideBar(SideBarLocation area) const
{
return d->SideTabBarWidgets[area];
}
@ -2065,7 +2152,21 @@ QRect CDockContainerWidget::contentRect() const
return QRect();
}
return d->RootSplitter->geometry();
if (d->RootSplitter->hasVisibleContent())
{
return d->RootSplitter->geometry();
}
else
{
auto ContentRect = this->rect();
ContentRect.adjust(
autoHideSideBar(SideBarLeft)->sizeHint().width(),
autoHideSideBar(SideBarTop)->sizeHint().height(),
-autoHideSideBar(SideBarRight)->sizeHint().width(),
-autoHideSideBar(SideBarBottom)->sizeHint().height());
return ContentRect;
}
}

View File

@ -101,7 +101,14 @@ protected:
* Initializing inserts the tabs into the side tab widget and hides it
* Returns nullptr if you try and insert into an area where the configuration is not enabled
*/
CAutoHideDockContainer* createAndSetupAutoHideContainer(SideBarLocation area, CDockWidget* DockWidget);
CAutoHideDockContainer* createAndSetupAutoHideContainer(SideBarLocation area, CDockWidget* DockWidget, int TabIndex = -1);
/**
* The funtion does the same like createAndSetupAutoHideContainer() but checks
* if the given DockWidget is pinnable. If it is not pinnable, the
* function returns a nullptr.
*/
CAutoHideDockContainer* createAutoHideContainerIfPinnable(SideBarLocation area, CDockWidget* DockWidget);
/**
* Helper function for creation of the root splitter
@ -125,7 +132,8 @@ protected:
* a nullptr, then the DropArea indicates the drop area in the given
* TargetAreaWidget
*/
void dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget);
void dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget,
int TabIndex = -1);
/**
* Adds the given dock area to this container widget
@ -322,7 +330,7 @@ public:
/**
* Returns the side tab widget for the given area
*/
CAutoHideSideBar* sideTabBar(SideBarLocation area) const;
CAutoHideSideBar* autoHideSideBar(SideBarLocation area) const;
/**

View File

@ -55,6 +55,8 @@ class CIconProvider;
class CDockComponentsFactory;
class CDockFocusController;
class CAutoHideSideBar;
class CAutoHideTab;
struct AutoHideTabPrivate;
/**
* The central dock manager that maintains the complete docking system.
@ -87,6 +89,8 @@ private:
friend class CDockAreaTitleBar;
friend class CAutoHideDockContainer;
friend CAutoHideSideBar;
friend CAutoHideTab;
friend AutoHideTabPrivate;
public Q_SLOTS:
/**
@ -248,7 +252,9 @@ public:
AutoHideCloseButtonCollapsesDock = 0x40, ///< Close button of an auto hide container collapses the dock instead of hiding it completely
DefaultAutoHideConfig = AutoHideFeatureEnabled
| DockAreaHasAutoHideButton ///< the default configuration for left and right side bars
| DockAreaHasAutoHideButton
| AutoHideCloseButtonCollapsesDock
};
Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag)

View File

@ -38,11 +38,18 @@
#include "DockAreaWidget.h"
#include "DockAreaTitleBar.h"
#include "DockContainerWidget.h"
#include "AutoHideSideBar.h"
#include "DockManager.h"
#include "DockAreaTabBar.h"
#include <iostream>
namespace ads
{
static const int AutoHideAreaWidth = 32;
static const int AutoHideAreaMouseZone = 8;
static const int InvalidTabIndex = -2;
/**
* Private data class of CDockOverlay
@ -57,11 +64,23 @@ struct DockOverlayPrivate
bool DropPreviewEnabled = true;
CDockOverlay::eMode Mode = CDockOverlay::ModeDockAreaOverlay;
QRect DropAreaRect;
int TabIndex = InvalidTabIndex;
/**
* Private data constructor
*/
DockOverlayPrivate(CDockOverlay* _public) : _this(_public) {}
/**
* Returns the overlay width / height depending on the visibility
* of the sidebar
*/
int sideBarOverlaySize(SideBarLocation sideBarLocation);
/**
* The area where the mouse is considered in the sidebar
*/
int sideBarMouseZone(SideBarLocation sideBarLocation);
};
/**
@ -155,8 +174,20 @@ struct DockOverlayCrossPrivate
QLabel* l = new QLabel();
l->setObjectName("DockWidgetAreaLabel");
const qreal metric = dropIndicatiorWidth(l);
const QSizeF size(metric, metric);
qreal metric = dropIndicatiorWidth(l);
QSizeF size(metric, metric);
if (internal::isSideBarArea(DockWidgetArea))
{
auto SideBarLocation = internal::toSideBarLocation(DockWidgetArea);
if (internal::isHorizontalSideBarLocation(SideBarLocation))
{
size.setHeight(size.height() / 2);
}
else
{
size.setWidth(size.width() / 2);
}
}
l->setPixmap(createHighDpiDropIndicatorPixmap(size, DockWidgetArea, Mode));
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
@ -182,6 +213,11 @@ struct DockOverlayCrossPrivate
{
QColor borderColor = iconColor(CDockOverlayCross::FrameColor);
QColor backgroundColor = iconColor(CDockOverlayCross::WindowBackgroundColor);
QColor overlayColor = iconColor(CDockOverlayCross::OverlayColor);
if (overlayColor.alpha() == 255)
{
overlayColor.setAlpha(64);
}
#if QT_VERSION >= 0x050600
double DevicePixelRatio = _this->window()->devicePixelRatioF();
@ -239,22 +275,22 @@ struct DockOverlayCrossPrivate
}
QSizeF baseSize = baseRect.size();
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
bool IsOuterContainerArea = (CDockOverlay::ModeContainerOverlay == Mode)
&& (DockWidgetArea != CenterDockWidgetArea)
&& !internal::isSideBarArea(DockWidgetArea);
if (IsOuterContainerArea)
{
baseRect = areaRect;
}
p.fillRect(baseRect, backgroundColor);
if (areaRect.isValid())
{
pen = p.pen();
pen.setColor(borderColor);
QColor Color = iconColor(CDockOverlayCross::OverlayColor);
if (Color.alpha() == 255)
{
Color.setAlpha(64);
}
p.setBrush(Color);
p.setBrush(overlayColor);
p.setPen(Qt::NoPen);
p.drawRect(areaRect);
@ -267,6 +303,7 @@ struct DockOverlayCrossPrivate
}
p.restore();
p.save();
// Draw outer border
pen = p.pen();
@ -282,8 +319,9 @@ struct DockOverlayCrossPrivate
p.drawRect(FrameRect);
p.restore();
// Draw arrow for outer container drop indicators
if (CDockOverlay::ModeContainerOverlay == Mode && DockWidgetArea != CenterDockWidgetArea)
if (IsOuterContainerArea)
{
QRectF ArrowRect;
ArrowRect.setSize(baseSize);
@ -326,6 +364,38 @@ struct DockOverlayCrossPrivate
};
//============================================================================
int DockOverlayPrivate::sideBarOverlaySize(SideBarLocation sideBarLocation)
{
auto Container = qobject_cast<CDockContainerWidget*>(TargetWidget.data());
auto SideBar = Container->autoHideSideBar(sideBarLocation);
if (!SideBar || !SideBar->isVisibleTo(Container))
{
return AutoHideAreaWidth;
}
else
{
return (SideBar->orientation() == Qt::Horizontal) ? SideBar->height() : SideBar->width();
}
}
//============================================================================
int DockOverlayPrivate::sideBarMouseZone(SideBarLocation sideBarLocation)
{
auto Container = qobject_cast<CDockContainerWidget*>(TargetWidget.data());
auto SideBar = Container->autoHideSideBar(sideBarLocation);
if (!SideBar || !SideBar->isVisibleTo(Container))
{
return AutoHideAreaMouseZone;
}
else
{
return (SideBar->orientation() == Qt::Horizontal) ? SideBar->height() : SideBar->width();
}
}
//============================================================================
CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) :
QFrame(parent),
@ -359,12 +429,26 @@ CDockOverlay::~CDockOverlay()
void CDockOverlay::setAllowedAreas(DockWidgetAreas areas)
{
if (areas == d->AllowedAreas)
{
return;
}
d->AllowedAreas = areas;
d->Cross->reset();
}
//============================================================================
void CDockOverlay::setAllowedArea(DockWidgetArea area, bool Enable)
{
auto AreasOld = d->AllowedAreas;
d->AllowedAreas.setFlag(area, Enable);
if (AreasOld != d->AllowedAreas)
{
d->Cross->reset();
}
}
//============================================================================
DockWidgetAreas CDockOverlay::allowedAreas() const
{
@ -375,22 +459,68 @@ DockWidgetAreas CDockOverlay::allowedAreas() const
//============================================================================
DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
{
d->TabIndex = InvalidTabIndex;
if (!d->TargetWidget)
{
return InvalidDockWidgetArea;
}
DockWidgetArea Result = d->Cross->cursorLocation();
if (Result != InvalidDockWidgetArea)
{
return Result;
}
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(d->TargetWidget.data());
if (!DockArea)
auto CursorPos = QCursor::pos();
auto DockArea = qobject_cast<CDockAreaWidget*>(d->TargetWidget.data());
if (!DockArea && CDockManager::autoHideConfigFlags().testFlag(CDockManager::AutoHideFeatureEnabled))
{
auto Rect = rect();
const QPoint pos = mapFromGlobal(QCursor::pos());
if ((pos.x() < d->sideBarMouseZone(SideBarLeft))
&& d->AllowedAreas.testFlag(LeftAutoHideArea))
{
Result = LeftAutoHideArea;
}
else if (pos.x() > (Rect.width() - d->sideBarMouseZone(SideBarRight))
&& d->AllowedAreas.testFlag(RightAutoHideArea))
{
Result = RightAutoHideArea;
}
else if (pos.y() < d->sideBarMouseZone(SideBarTop)
&& d->AllowedAreas.testFlag(TopAutoHideArea))
{
Result = TopAutoHideArea;
}
else if (pos.y() > (Rect.height() - d->sideBarMouseZone(SideBarBottom))
&& d->AllowedAreas.testFlag(BottomAutoHideArea))
{
Result = BottomAutoHideArea;
}
auto SideBarLocation = ads::internal::toSideBarLocation(Result);
if (SideBarLocation != SideBarNone)
{
auto Container = qobject_cast<CDockContainerWidget*>(d->TargetWidget.data());
auto SideBar = Container->autoHideSideBar(SideBarLocation);
if (SideBar->isVisible())
{
d->TabIndex = SideBar->tabInsertIndexAt(SideBar->mapFromGlobal(CursorPos));
}
}
return Result;
}
else if (!DockArea)
{
return Result;
}
if (DockArea->allowedAreas().testFlag(CenterDockWidgetArea)
&& !DockArea->titleBar()->isHidden()
&& DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(QCursor::pos())))
&& DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(CursorPos)))
{
auto TabBar = DockArea->titleBar()->tabBar();
d->TabIndex = TabBar->tabInsertIndexAt(TabBar->mapFromGlobal(CursorPos));
return CenterDockWidgetArea;
}
@ -398,6 +528,13 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
}
//============================================================================
int CDockOverlay::tabIndexUnderCursor() const
{
return d->TabIndex;
}
//============================================================================
DockWidgetArea CDockOverlay::visibleDropAreaUnderCursor() const
{
@ -471,6 +608,7 @@ bool CDockOverlay::dropPreviewEnabled() const
void CDockOverlay::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
// Draw rect based on location
if (!d->DropPreviewEnabled)
{
@ -490,8 +628,13 @@ void CDockOverlay::paintEvent(QPaintEvent* event)
case BottomDockWidgetArea: r.setY(r.height() * (1 - 1 / Factor)); break;
case LeftDockWidgetArea: r.setWidth(r.width() / Factor); break;
case CenterDockWidgetArea: r = rect();break;
case LeftAutoHideArea: r.setWidth(d->sideBarOverlaySize(SideBarLeft)); break;
case RightAutoHideArea: r.setX(r.width() - d->sideBarOverlaySize(SideBarRight)); break;
case TopAutoHideArea: r.setHeight(d->sideBarOverlaySize(SideBarTop)); break;
case BottomAutoHideArea: r.setY(r.height() - d->sideBarOverlaySize(SideBarBottom)); break;
default: return;
}
QPainter painter(this);
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
QPen Pen = painter.pen();
@ -627,6 +770,7 @@ void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode)
areaWidgets.insert(BottomDockWidgetArea, d->createDropIndicatorWidget(BottomDockWidgetArea, Mode));
areaWidgets.insert(LeftDockWidgetArea, d->createDropIndicatorWidget(LeftDockWidgetArea, Mode));
areaWidgets.insert(CenterDockWidgetArea, d->createDropIndicatorWidget(CenterDockWidgetArea, Mode));
#if QT_VERSION >= 0x050600
d->LastDevicePixelRatio = devicePixelRatioF();
#else

View File

@ -72,6 +72,11 @@ public:
*/
void setAllowedAreas(DockWidgetAreas areas);
/**
* Enable / disable a certain area
*/
void setAllowedArea(DockWidgetArea area, bool Enable);
/**
* Returns flags with all allowed drop areas
*/
@ -82,6 +87,17 @@ public:
*/
DockWidgetArea dropAreaUnderCursor() const;
/**
* If the drop area is the CenterDockWidgetArea or a sidebar area,
* then this function returns the index of the tab under cursor.
* Call this function after call to dropAreaUnderCursor() because this
* function updates the tab index.
* A value of -1 indicates a position before the first tab and a value of
* tabCount() indicates a position behind the last tab.
* A value of -2 indicates an valid value
*/
int tabIndexUnderCursor() const;
/**
* This function returns the same like dropAreaUnderCursor() if this
* overlay is not hidden and if drop preview is enabled and returns

View File

@ -555,6 +555,13 @@ bool CDockWidget::isAutoHide() const
}
//============================================================================
SideBarLocation CDockWidget::autoHideLocation() const
{
return isAutoHide() ? autoHideDockContainer()->sideBarLocation() : SideBarNone;
}
//============================================================================
bool CDockWidget::isFloating() const
{
@ -1021,7 +1028,15 @@ void CDockWidget::setFloating()
{
return;
}
d->TabWidget->detachDockWidget();
if (this->isAutoHide())
{
dockAreaWidget()->setFloating();
}
else
{
d->TabWidget->detachDockWidget();
}
}
@ -1044,6 +1059,22 @@ void CDockWidget::closeDockWidget()
}
//============================================================================
void CDockWidget::requestCloseDockWidget()
{
if (features().testFlag(CDockWidget::DockWidgetDeleteOnClose)
|| features().testFlag(CDockWidget::CustomCloseHandling))
{
closeDockWidgetInternal(false);
}
else
{
toggleView(false);
}
}
//============================================================================
bool CDockWidget::closeDockWidgetInternal(bool ForceClose)
{
@ -1190,7 +1221,7 @@ void CDockWidget::raise()
//============================================================================
void CDockWidget::setAutoHide(bool Enable, SideBarLocation Location)
void CDockWidget::setAutoHide(bool Enable, SideBarLocation Location, int TabIndex)
{
if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled))
{
@ -1198,20 +1229,25 @@ void CDockWidget::setAutoHide(bool Enable, SideBarLocation Location)
}
// Do nothing if nothing changes
if (Enable == isAutoHide())
if (Enable == isAutoHide() && Location == autoHideLocation())
{
return;
}
auto DockArea = dockAreaWidget();
if (!Enable)
{
DockArea->setAutoHide(false);
}
else if (isAutoHide())
{
autoHideDockContainer()->moveToNewSideBarLocation(Location);
}
else
{
auto area = (SideBarNone == Location) ? DockArea->calculateSideTabBarArea() : Location;
dockContainer()->createAndSetupAutoHideContainer(area, this);
dockContainer()->createAndSetupAutoHideContainer(area, this, TabIndex);
}
}

View File

@ -377,6 +377,12 @@ public:
*/
CAutoHideDockContainer* autoHideDockContainer() const;
/**
* Returns the auto hide side bar location or SideBarNone if, this is not
* an autohide dock widget
*/
SideBarLocation autoHideLocation() 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
@ -578,10 +584,19 @@ public Q_SLOTS:
void deleteDockWidget();
/**
* Closes the dock widget
* Closes the dock widget.
* The function forces closing of the dock widget even for CustomCloseHandling.
*/
void closeDockWidget();
/**
* Request closing of the dock widget.
* For DockWidget with default close handling, the function does the same
* like clodeDockWidget() but if the flas CustomCloseHandling is set,
* the function only emits the closeRequested() signal.
*/
void requestCloseDockWidget();
/**
* Shows the widget in full-screen mode.
* Normally this function only affects windows. To make the interface
@ -606,7 +621,7 @@ public Q_SLOTS:
* Sets the dock widget into auto hide mode if this feature is enabled
* via CDockManager::setAutoHideFlags(CDockManager::AutoHideFeatureEnabled)
*/
void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone);
void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone, int TabIndex = -1);
/**
* Switches the dock widget to auto hide mode or vice versa depending on its

View File

@ -499,10 +499,8 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
return;
}
if (DockManager->dockAreaOverlay()->dropAreaUnderCursor()
!= InvalidDockWidgetArea
|| DockManager->containerOverlay()->dropAreaUnderCursor()
!= InvalidDockWidgetArea)
if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
|| DockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea)
{
CDockOverlay *Overlay = DockManager->containerOverlay();
if (!Overlay->dropOverlayRect().isValid())
@ -510,21 +508,26 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
Overlay = DockManager->dockAreaOverlay();
}
// Resize the floating widget to the size of the highlighted drop area
// rectangle
QRect Rect = Overlay->dropOverlayRect();
int FrameWidth = (_this->frameSize().width() - _this->rect().width())
/ 2;
int TitleBarHeight = _this->frameSize().height()
- _this->rect().height() - FrameWidth;
if (Rect.isValid())
// Do not resize if we drop into an autohide sidebar area to preserve
// the dock area size for the initial size of the auto hide area
if (!ads::internal::isSideBarArea(Overlay->dropAreaUnderCursor()))
{
QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft());
TopLeft.ry() += TitleBarHeight;
_this->setGeometry(
QRect(TopLeft,
QSize(Rect.width(), Rect.height() - TitleBarHeight)));
QApplication::processEvents();
// Resize the floating widget to the size of the highlighted drop area
// rectangle
QRect Rect = Overlay->dropOverlayRect();
int FrameWidth = (_this->frameSize().width() - _this->rect().width())
/ 2;
int TitleBarHeight = _this->frameSize().height()
- _this->rect().height() - FrameWidth;
if (Rect.isValid())
{
QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft());
TopLeft.ry() += TitleBarHeight;
_this->setGeometry(
QRect(TopLeft,
QSize(Rect.width(), Rect.height() - TitleBarHeight)));
QApplication::processEvents();
}
}
DropContainer->dropFloatingWidget(_this, QCursor::pos());
}
@ -533,6 +536,7 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
DockManager->dockAreaOverlay()->hideOverlay();
}
//============================================================================
void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &GlobalPos)
{
@ -586,11 +590,25 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &GlobalPos)
}
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
ContainerOverlay->setAllowedAreas(
VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
DockWidgetAreas AllowedContainerAreas = (VisibleDockAreas > 1) ? OuterDockAreas : AllDockAreas;
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
// If the dock container contains only one single DockArea, then we need
// to respect the allowed areas - only the center area is relevant here because
// all other allowed areas are from the container
if (VisibleDockAreas == 1 && DockArea)
{
AllowedContainerAreas.setFlag(CenterDockWidgetArea, DockArea->allowedAreas().testFlag(CenterDockWidgetArea));
}
if (DockContainer->features().testFlag(CDockWidget::DockWidgetPinnable))
{
AllowedContainerAreas |= AutoHideDockAreas;
}
ContainerOverlay->setAllowedAreas(AllowedContainerAreas);
DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
{
DockAreaOverlay->enableDropPreview(true);

View File

@ -22,6 +22,8 @@
#include "DockManager.h"
#include "DockContainerWidget.h"
#include "DockOverlay.h"
#include "AutoHideDockContainer.h"
#include "ads_globals.h"
namespace ads
{
@ -33,6 +35,7 @@ struct FloatingDragPreviewPrivate
{
CFloatingDragPreview *_this;
QWidget* Content;
CDockWidget::DockWidgetFeatures ContentFeatures;
CDockAreaWidget* ContentSourceArea = nullptr;
QPoint DragStartMousePosition;
CDockManager* DockManager;
@ -77,20 +80,36 @@ struct FloatingDragPreviewPrivate
* Returns true, if the content is floatable
*/
bool isContentFloatable() const
{
return this->ContentFeatures.testFlag(CDockWidget::DockWidgetFloatable);
}
/**
* Returns true, if the content is pinnable
*/
bool isContentPinnable() const
{
return this->ContentFeatures.testFlag(CDockWidget::DockWidgetPinnable);
}
/**
* Returns the content features
*/
CDockWidget::DockWidgetFeatures contentFeatures() const
{
CDockWidget* DockWidget = qobject_cast<CDockWidget*>(Content);
if (DockWidget && DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable))
if (DockWidget)
{
return true;
return DockWidget->features();
}
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(Content);
if (DockArea && DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
if (DockArea)
{
return true;
return DockArea->features();
}
return false;
return CDockWidget::DockWidgetFeatures();
}
};
// struct LedArrayPanelPrivate
@ -126,8 +145,6 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
DropContainer = TopContainer;
auto ContainerOverlay = DockManager->containerOverlay();
auto DockAreaOverlay = DockManager->dockAreaOverlay();
auto DockDropArea = DockAreaOverlay->dropAreaUnderCursor();
auto ContainerDropArea = ContainerOverlay->dropAreaUnderCursor();
if (!TopContainer)
{
@ -140,6 +157,9 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
return;
}
auto DockDropArea = DockAreaOverlay->dropAreaUnderCursor();
auto ContainerDropArea = ContainerOverlay->dropAreaUnderCursor();
int VisibleDockAreas = TopContainer->visibleDockAreaCount();
// Include the overlay widget we're dragging as a visible widget
@ -149,13 +169,27 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
VisibleDockAreas++;
}
ContainerOverlay->setAllowedAreas( VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
DockWidgetAreas AllowedContainerAreas = (VisibleDockAreas > 1) ? OuterDockAreas : AllDockAreas;
//ContainerOverlay->enableDropPreview(ContainerDropArea != InvalidDockWidgetArea);
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
// If the dock container contains only one single DockArea, then we need
// to respect the allowed areas - only the center area is relevant here because
// all other allowed areas are from the container
if (VisibleDockAreas == 1 && DockArea)
{
AllowedContainerAreas.setFlag(CenterDockWidgetArea, DockArea->allowedAreas().testFlag(CenterDockWidgetArea));
}
if (isContentPinnable())
{
AllowedContainerAreas |= AutoHideDockAreas;
}
ContainerOverlay->setAllowedAreas(AllowedContainerAreas);
ContainerOverlay->enableDropPreview(ContainerDropArea != InvalidDockWidgetArea);
if (DockArea && DockArea->isVisible() && VisibleDockAreas >= 0 && DockArea != ContentSourceArea)
{
DockAreaOverlay->enableDropPreview(true);
DockAreaOverlay->setAllowedAreas( (VisibleDockAreas == 1) ? NoDockWidgetArea : DockArea->allowedAreas());
DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
// A CenterDockWidgetArea for the dockAreaOverlay() indicates that
@ -178,15 +212,13 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos)
DockAreaOverlay->hideOverlay();
// If there is only one single visible dock area in a container, then
// it does not make sense to show a dock overlay because the dock area
// would be removed and inserted at the same position
// would be removed and inserted at the same position. Only auto hide
// area is allowed
if (VisibleDockAreas == 1)
{
ContainerOverlay->hideOverlay();
}
else
{
ContainerOverlay->showOverlay(TopContainer);
ContainerOverlay->setAllowedAreas(AutoHideDockAreas);
}
ContainerOverlay->showOverlay(TopContainer);
if (DockArea == ContentSourceArea && InvalidDockWidgetArea == ContainerDropArea)
@ -249,6 +281,7 @@ CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) :
d(new FloatingDragPreviewPrivate(this))
{
d->Content = Content;
d->ContentFeatures = d->contentFeatures();
setAttribute(Qt::WA_DeleteOnClose);
if (CDockManager::testConfigFlag(CDockManager::DragPreviewHasWindowFrame))
{
@ -268,8 +301,6 @@ CFloatingDragPreview::CFloatingDragPreview(QWidget* Content, QWidget* parent) :
setWindowFlags(Flags);
#endif
setWindowOpacity(0.6);
// Create a static image of the widget that should get undocked
// This is like some kind preview image like it is uses in drag and drop
// operations
@ -356,7 +387,7 @@ void CFloatingDragPreview::finishDragging()
// state if they are dragged into a floating window
if (ValidDropArea || d->isContentFloatable())
{
cleanupAutoHideContainerWidget();
cleanupAutoHideContainerWidget(ContainerDropArea);
}
if (!d->DropContainer)
@ -365,20 +396,21 @@ void CFloatingDragPreview::finishDragging()
}
else if (DockDropArea != InvalidDockWidgetArea)
{
d->DropContainer->dropWidget(d->Content, DockDropArea, d->DropContainer->dockAreaAt(QCursor::pos()));
d->DropContainer->dropWidget(d->Content, DockDropArea, d->DropContainer->dockAreaAt(QCursor::pos()),
d->DockManager->dockAreaOverlay()->tabIndexUnderCursor());
}
else if (ContainerDropArea != InvalidDockWidgetArea)
{
CDockAreaWidget* DockArea = nullptr;
// If there is only one single dock area, and we drop into the center
// then we tabify the dropped widget into the only visible dock area
if (d->DropContainer->visibleDockAreaCount() <= 1 && CenterDockWidgetArea == ContainerDropArea)
{
d->DropContainer->dropWidget(d->Content, ContainerDropArea, d->DropContainer->dockAreaAt(QCursor::pos()));
}
else
{
d->DropContainer->dropWidget(d->Content, ContainerDropArea, nullptr);
DockArea = d->DropContainer->dockAreaAt(QCursor::pos());
}
d->DropContainer->dropWidget(d->Content, ContainerDropArea, DockArea,
d->DockManager->containerOverlay()->tabIndexUnderCursor());
}
else
{
@ -392,18 +424,29 @@ void CFloatingDragPreview::finishDragging()
//============================================================================
void CFloatingDragPreview::cleanupAutoHideContainerWidget()
void CFloatingDragPreview::cleanupAutoHideContainerWidget(DockWidgetArea ContainerDropArea)
{
auto DroppedDockWidget = qobject_cast<CDockWidget*>(d->Content);
auto DroppedArea = qobject_cast<CDockAreaWidget*>(d->Content);
if (DroppedDockWidget && DroppedDockWidget->autoHideDockContainer())
auto AutoHideContainer = DroppedDockWidget
? DroppedDockWidget->autoHideDockContainer()
: DroppedArea->autoHideDockContainer();
if (!AutoHideContainer)
{
DroppedDockWidget->autoHideDockContainer()->cleanupAndDelete();
return;
}
if (DroppedArea && DroppedArea->autoHideDockContainer())
// If the dropped widget is already an auto hide widget and if it is moved
// to a new side bar location in the same container, then we do not need
// to cleanup
if (ads::internal::isSideBarArea(ContainerDropArea)
&& (d->DropContainer == AutoHideContainer->dockContainer()))
{
DroppedArea->autoHideDockContainer()->cleanupAndDelete();
return;
}
AutoHideContainer->cleanupAndDelete();
}
@ -417,6 +460,7 @@ void CFloatingDragPreview::paintEvent(QPaintEvent* event)
}
QPainter painter(this);
painter.setOpacity(0.6);
if (CDockManager::testConfigFlag(CDockManager::DragPreviewShowsContentPixmap))
{
painter.drawPixmap(QPoint(0, 0), d->ContentPreviewPixmap);

View File

@ -95,7 +95,7 @@ public: // implements IFloatingWidget -----------------------------------------
/**
* Cleanup auto hide container if the dragged widget has one
*/
void cleanupAutoHideContainerWidget();
void cleanupAutoHideContainerWidget(DockWidgetArea ContainerDropArea);
Q_SIGNALS:
/**

View File

@ -18,5 +18,7 @@
<file>images/vs-pin-button.svg</file>
<file>images/vs-pin-button-pinned.svg</file>
<file>images/vs-pin-button-pinned-focused.svg</file>
<file>images/vs-pin-button_45.svg</file>
<file>images/pin-button-big.svg</file>
</qresource>
</RCC>

View File

@ -333,6 +333,47 @@ CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area)
}
//============================================================================
SideBarLocation toSideBarLocation(DockWidgetArea Area)
{
switch (Area)
{
case LeftAutoHideArea: return SideBarLeft;
case RightAutoHideArea: return SideBarRight;
case TopAutoHideArea: return SideBarTop;
case BottomAutoHideArea: return SideBarBottom;
default:
return SideBarNone;
}
return SideBarNone;
}
//============================================================================
bool isHorizontalSideBarLocation(SideBarLocation Location)
{
switch (Location)
{
case SideBarTop:
case SideBarBottom: return true;
case SideBarLeft:
case SideBarRight: return false;
default:
return false;
}
return false;
}
//============================================================================
bool isSideBarArea(DockWidgetArea Area)
{
return toSideBarLocation(Area) != SideBarNone;
}
//============================================================================
QPixmap createTransparentPixmap(const QPixmap& Source, qreal Opacity)
{

View File

@ -82,14 +82,26 @@ enum DockWidgetArea
TopDockWidgetArea = 0x04,
BottomDockWidgetArea = 0x08,
CenterDockWidgetArea = 0x10,
LeftAutoHideArea = 0x20,
RightAutoHideArea = 0x40,
TopAutoHideArea = 0x80,
BottomAutoHideArea = 0x100,
InvalidDockWidgetArea = NoDockWidgetArea,
OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea | BottomDockWidgetArea,
AutoHideDockAreas = LeftAutoHideArea | RightAutoHideArea | TopAutoHideArea | BottomAutoHideArea,
AllDockAreas = OuterDockAreas | CenterDockWidgetArea
};
Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea)
enum eTabIndex
{
TabDefaultInsertIndex = -1,
TabInvalidIndex = -2
};
enum TitleBarButton
{
TitleBarButtonTabsMenu,
@ -194,6 +206,7 @@ void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To);
*/
void hideEmptyParentSplitters(CDockSplitter* FirstParentSplitter);
/**
* Convenience class for QPair to provide better naming than first and
* second
@ -212,6 +225,25 @@ public:
*/
CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area);
/**
* Returns the SieBarLocation for the AutoHide dock widget areas
*/
SideBarLocation toSideBarLocation(DockWidgetArea Area);
/**
* Returns true for the top or bottom side bar ansd false for the
* left and right side bar
*/
bool isHorizontalSideBarLocation(SideBarLocation Location);
/**
* Returns true, if the given dock area is a SideBar area
*/
bool isSideBarArea(DockWidgetArea Area);
/**
* Searches for the parent widget of the given type.
* Returns the parent widget of the given widget or 0 if the widget is not

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16" height="16" enable-background="new 0 0 122.879 122.867" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(.12293 0 0 .12294 .39712 .49812)" fill="#ffffff" stroke="#000000" stroke-width="8.1347"><path d="m83.88 0.451 38.547 38.549c0.603 0.601 0.603 1.585 0 2.188l-13.128 13.125c-0.602 0.604-1.586 0.604-2.187 0l-3.732-3.73-17.303 17.3c3.882 14.621 0.095 30.857-11.37 42.32-0.266 0.268-0.535 0.529-0.808 0.787-1.004 0.955-0.843 0.949-1.813-0.021l-24.489-24.489-47.597 36.387 36.399-47.584-24.525-24.523c-0.978-0.98-0.896-0.826 0.066-1.837 0.24-0.251 0.485-0.503 0.734-0.753 11.463-11.463 27.702-15.253 42.322-11.37l17.301-17.3-3.733-3.732c-0.601-0.601-0.601-1.585 0-2.188l13.127-13.129c0.604-0.601 1.588-0.601 2.189 0z" clip-rule="evenodd" fill="#ffffff" fill-rule="evenodd" stroke="#000000" stroke-width="8.1347"/></g></svg>

After

Width:  |  Height:  |  Size: 940 B

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16" height="16" enable-background="new 0 0 122.879 122.867" version="1.1" viewBox="0 0 16 16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m10.286-1.055e-6 -6.8571 6.8571-1.1429-1.1429-1.1429 1.1429 3.4286 3.4286-4.5714 4.5714 1.1429 1.1429 4.5714-4.5714 3.4286 3.4286 1.1429-1.1429-1.1429-1.1429 6.8571-6.8571-4.5714-4.5714zm0 2.2857 2.2857 2.2857-5.7143 5.7143-2.2857-2.2857z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 473 B